Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simple way to write uncompressed JPEG or PNG image?

Tags:

c

image

png

jpeg

tiff

I have a raw image in memory, organized as an array of 32-bit RGB values. I'd like to write that out as quickly as possible to an image file so that I can free up the memory. Is there a way to do the following to write either an uncompressed JPEG, PNG or TIFF image? Or perhaps I should say, what image formats are compatible with this approach to writing raw pixel data? Note that the top-left pixel is in the first 4 bytes of the pixel data.

void write_image(uint32_t *pixels, int width, int height) {
 FILE *file=fopen("file.jpg","wb");
 write_header (file, width, height);
 fwrite (pixels,1,width*height*4,file); // write raw pixel data
 write_end (file);
 fclose(file);
}
like image 771
xyz Avatar asked Apr 08 '19 23:04

xyz


3 Answers

There seem to be two different issues or motivations on your part.

First, there is the desire to write an image in some uncompressed format to (presumably) gain speed. PNG and JPEG are compressed formats, though you can instruct the encoder (at least in some PNG implementations) to use the "no compress" setting.

However: a) there are few scenarios in which that "optimization" would make a critical difference, the normal compressors are quite quick.

b) Even when encoding using some compression_level=0 setting, you are still encoding the image in a particular format (typically a header, to start with). What leads us to the second motivation.

Second, it seems that you want to avoid not exactly (only) the compression, but the encoding. That is, you want to write the pixels in your unencoded ("raw") format. IN that case, of course, you cannot write a PNG or JPEG image. You can use your own or some standard RAW format, or the quasi-raw BMP format. But you still need to take care of how the pixels are organized in memory (for example, one byte per channel? RGB? BGR? RGBA ?) and perhaps some other issues (for example, BMP requires that the bytes per line are multiple of 4).

like image 199
leonbloy Avatar answered Sep 23 '22 08:09

leonbloy


Uncompressed JPEG and PNG are non-trivial, and the results would likely have portability issues. Your simplest option might be TGA:

TGA was designed to store rasterized images that could be quickly loaded for display into frame buffers. It has a very simple 18-byte header, then raw pixel data. It's streamable, meaning image data can be written as generated, provided it's rasterized. There is no requirement for length/offset/CRC tables. The biggest limitation is samples must be in rasterized BGR order with an optional fourth channel (usually alpha but can be anything). The width/height fields in the header must be 16-bit little-endian. TGA format isn't as widely supported as GIF/JPEG/PNG, but you should find some viewers capable of rendering it.

For BGR data, the header would probably be (hexadecimal values): 0x00 0x00 0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 (width%256) (width/256) (height%256) (height/256) 0x18 0x20

For BGRA data, the header would probably be: 0x00 0x00 0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 (width%256) (width/256) (height%256) (height/256) 0x20 0x28

If your data is not in BGR/BGRA order and you can't or don't want to convert it, my second recommendation would be TIFF:

TIFF design is focused on storing rasterized scans of documents and uses a more complex TTLV-style header. It is not as streamable and requires offset tables, but you can get around this with brute-force precalculation and by defining the entire image as a single strip. Once you get the header done, then you can stream the raw pixel data in rasterized RGB or RGBA order as it's generated. TIFF can also support either big-endian or little-endian and up to 16-bits per sample. It is often the output format of choice for scanners, so viewer/editor support is fairly common.

The first four bytes are a magic number (byte order and TIFF file version), followed by a 4-byte offset of the image file directory (IFD). Usually this offset is just 8 bytes into the file to place the IFD immediately next. The IFD is a count value (N) followed by a table of N 12-byte entries in the form of tag, type, count, and value/offset. The rest of the details are too much to describe here but you can read the specification for more info.

like image 33
Tjaye Avatar answered Sep 24 '22 08:09

Tjaye


TGA format is a good option for this. It is just a simple header followed by your data. 24 or 32 bits.

https://en.wikipedia.org/wiki/Truevision_TGA

like image 31
Doug Rogers Avatar answered Sep 21 '22 08:09

Doug Rogers