Home > Enterprise >  How do I create and save an image from a byte stream in c ?
How do I create and save an image from a byte stream in c ?

Time:08-12

I am working in c trying to create an image and save it to a given directory. I don't care what type of image file it is (PNG, jpeg, bitmap, etc.), I just want it to be viewable in Windows 10. The data stream is in the following form: std::vector<unsigned char>.

I would like to do this natively in c , but I am not against using a library if it is straightforward to implement and lightweight.

I have this working in C# using the following code, but I don't know if there is a direct translation into c

// C# code to translate into c  ?
var image = new BitmapImage();
using (var ms = new MemoryStream(message.ImageData))
{
  image.BeginInit();
  image.CacheOption = BitmapCacheOption.OnLoad; 
  image.StreamSource = ms;
  image.EndInit();
  image.Freeze(); 
}

CodePudding user response:

C# implementations have image routines in the language's standard library. C does not. So there is no equivalent code in standard C : you need to use a third party library. On Windows you could use Win32.

Below I use stb_image_write.h, which can be found here; the stb libraries are barebones 1-file or 2-file libraries typically used in independent game development where having a dependency on libPNG et. al. would be overkill.

#include <vector>

#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"

std::vector<unsigned char> generate_some_image(int wd, int hgt)
{
    // this is just an example for tutorial purposes ... generate a red circle
    // in a white field.

    std::vector<unsigned char> data(wd * hgt * 4);

    int c_x = wd / 2;
    int c_y = hgt / 2;
    int radius = c_x;
    int i = 0;
    for (int y = 0; y < hgt; y  ) {
        for (int x = 0; x < wd; x  ) {
            if ((x - c_x) * (x - c_x)   (y - c_y) * (y - c_y) <= radius * radius) {
                data[i  ] = 255;
                data[i  ] = 0;
                data[i  ] = 0;
                data[i  ] = 255;
            } else {
                data[i  ] = 255;
                data[i  ] = 255;
                data[i  ] = 255;
                data[i  ] = 255;
            }
        }
    }

    return data;
}

int main()
{
    const int wd = 128;
    const int hgt = 128;
    std::vector<unsigned char> data = generate_some_image(wd, hgt);
    return stbi_write_png( "c:\\test\\foo.png", wd, hgt, 4, &(data[0]), 4*wd);
}

CodePudding user response:

There is no default standard C library for creating an image file with a specific format (PNG, Bitmap ... etc). However, there are tricks to create an image and make it viewable if this is all that you need. The ways are discussed below:

  1. Use a library as jwezorek! mentioned in his answer. There are tons of libraries that can help: OpenCV, STB ... etc
  2. Create a function that creates a file and streams the pixels data to that file in a specific format (Can be fun for some and a headache for others).
  3. Save the image data as raw data (pixels data only) in a file, and use a simpler programming language to read the file data and view the image. For instance, let's assume that you will use "python" as the simpler language to create a simple image viewer on windows 10, the code will look as follows:
import NumPy as np
import scipy.misc as smp
from PIL import Image

w = 1066
h = 600

with open('rgb.raw', 'r') as file:
    data = file.read().replace('\n', ' ')       # Replacing new lines with spaces
    rgbs = data.split(' ')                      # Get a 1D array of all the numbers (pixels) in file
    rgbs = [ int(x) for x in rgbs  if x != '']  # Change the data into integers

    nprgbs = np.array(rgbs, dtype=np.uint8)     # Define a numpy array
    arr = np.reshape(nprgbs, (h,w,3))           # Reorder the 1D array to 3D matrix (width, height, channels)

    img = Image.fromarray(arr)                  # Create an Image from the pixels. 
    img.show()                                  # View the image in a window (It uses the default viewer of the OS)

The above code will read a file containing the RGB channels of an image and view it on the default viewer.

As you can see, you can do it in a variety of ways, choose the simplest and the most suitable for you. In conclusion, the answer to your question is "No" unless you use a custom library, create your own functions, or use simpler programming languages to read the stream of data and use them to create the file.

  • Related