Rendering Engine 0.2.0
Modular Graphics Rendering Engine | v0.2.0
Loading...
Searching...
No Matches
image_codec_jpeg.hpp File Reference

JPEG read/write backend using libjpeg. More...

#include <iostream>
#include <stdio.h>
#include "jpeglib.h"
#include <setjmp.h>
#include "image_data.hpp"

Go to the source code of this file.

Classes

struct  codec_error_mgr

Typedefs

typedef struct codec_error_mgrcodec_error_mgr_ptr

Functions

static void SaveTextureFileJpeg (rendering_engine::ImageData const &imageData, char const *filename)
 Saves image data to a JPEG file.
 codec_error_exit (j_common_ptr cinfo)
static bool DoReadJpegFile (struct jpeg_decompress_struct *cinfo, char const *filename, unsigned int &width, unsigned int &height, std::vector< unsigned int > &rgbImageDataVector)
static bool ReadJpegFile (char const *filename, unsigned int &width, unsigned int &height, std::vector< unsigned int > &rgbImageDataVector)
 Reads a JPEG file into an RGB image buffer.
static bool ReadJpegFromMemory (const unsigned char *memory, size_t memorySize, unsigned int &width, unsigned int &height, std::vector< unsigned int > &rgbImageDataVector)
 Decode a JPEG image directly from a memory buffer.

Detailed Description

JPEG read/write backend using libjpeg.

Provides low-level I/O routines bridging ImageData and the libjpeg API. Supports 8-bit RGB images for loading and saving.

The implementation follows the official libjpeg API workflow:

Custom error handling is implemented via codec_error_mgr to safely recover from libjpeg�s internal longjmp behavior.

Note
This file is an internal backend of the Rendering Engine and is not part of the public API.
See also
rendering_engine::ImageData

Definition in file image_codec_jpeg.hpp.

Typedef Documentation

◆ codec_error_mgr_ptr

Definition at line 98 of file image_codec_jpeg.hpp.

Function Documentation

◆ codec_error_exit()

codec_error_exit ( j_common_ptr cinfo)

Definition at line 105 of file image_codec_jpeg.hpp.

106{
107 /* cinfo->err really points to a codec_error_mgr struct, so coerce pointer */
108 codec_error_mgr_ptr codecErr = (codec_error_mgr_ptr)cinfo->err;
109
110 /* Always display the message. */
111 /* We could postpone this until after returning, if we chose. */
112 (*cinfo->err->output_message) (cinfo);
113
114 /* Return control to the setjmp point */
115 longjmp(codecErr->setjmp_buffer, 1);
116}
struct codec_error_mgr * codec_error_mgr_ptr

◆ DoReadJpegFile()

bool DoReadJpegFile ( struct jpeg_decompress_struct * cinfo,
char const * filename,
unsigned int & width,
unsigned int & height,
std::vector< unsigned int > & rgbImageDataVector )
static

Definition at line 154 of file image_codec_jpeg.hpp.

155{
156 /* We use our private extension JPEG error handler.
157 * Note that this struct must live as long as the main JPEG parameter
158 * struct, to avoid dangling-pointer problems.
159 */
160 struct codec_error_mgr jerr;
161
162 FILE* infile; /* source file */
163 JSAMPARRAY buffer; /* Output row buffer */
164 int row_stride; /* physical row width in output buffer */
165
166 if( (infile = fopen(filename, "rb")) == NULL )
167 {
168 std::cout << "File can not be open." << std::endl;
169 return false;
170 }
171
172 /* Step 1: allocate and initialize JPEG decompression object */
173
174 /* We set up the normal JPEG error routines, then override error_exit. */
175 cinfo->err = jpeg_std_error(&jerr.pub);
176 jerr.pub.error_exit = codec_error_exit;
177 /* Establish the setjmp return context for my_error_exit to use. */
178 if( setjmp(jerr.setjmp_buffer) ) {
179 /* If we get here, the JPEG code has signaled an error.
180 * We need to clean up the JPEG object, close the input file, and return.
181 */
182 jpeg_destroy_decompress(cinfo);
183 fclose(infile);
184 return false;
185 }
186 /* Now we can initialize the JPEG decompression object. */
187 jpeg_create_decompress(cinfo);
188
189 /* Step 2: specify data source (eg, a file) */
190
191 jpeg_stdio_src(cinfo, infile);
192
193 /* Step 3: read file parameters with jpeg_read_header() */
194
195 (void)jpeg_read_header(cinfo, TRUE);
196 /* We can ignore the return value from jpeg_read_header since
197 * (a) suspension is not possible with the stdio data source, and
198 * (b) we passed TRUE to reject a tables-only JPEG file as an error.
199 * See libjpeg.txt for more info.
200 */
201
202 /* Step 4: set parameters for decompression */
203
204 /* In this example, we don't need to change any of the defaults set by
205 * jpeg_read_header(), so we do nothing here.
206 */
207
208 /* Step 5: Start decompressor and fulfill the output data */
209 width = cinfo->image_width;
210 height = cinfo->image_height;
211
212 rgbImageDataVector.clear();
213
214 (void)jpeg_start_decompress(cinfo);
215 /* We can ignore the return value since suspension is not possible
216 * with the stdio data source.
217 */
218
219 /* We may need to do some setup of our own at this point before reading
220 * the data. After jpeg_start_decompress() we have the correct scaled
221 * output image dimensions available, as well as the output colormap
222 * if we asked for color quantization.
223 * In this example, we need to make an output work buffer of the right size.
224 */
225 /* JSAMPLEs per row in output buffer */
226 row_stride = cinfo->output_width * cinfo->output_components;
227 /* Make a one-row-high sample array that will go away when done with image */
228 buffer = (*cinfo->mem->alloc_sarray)
229 ((j_common_ptr)cinfo, JPOOL_IMAGE, row_stride, 1);
230
231 /* Step 6: while (scan lines remain to be read) */
232 /* jpeg_read_scanlines(...); */
233
234 /* Here we use the library's state variable cinfo->output_scanline as the
235 * loop counter, so that we don't have to keep track ourselves.
236 */
237 ;
238 while( cinfo->output_scanline < cinfo->output_height ) {
239 /* jpeg_read_scanlines expects an array of pointers to scanlines.
240 * Here the array is only one element long, but you could ask for
241 * more than one scanline at a time if that's more convenient.
242 */
243 (void)jpeg_read_scanlines(cinfo, buffer, 1);
244 /* Assume put_scanline_someplace wants a pointer and sample count. */
245 for( int i = 0; i < row_stride; ++i )
246 {
247 rgbImageDataVector.push_back(*(buffer[0] + i));
248 }
249 }
250
251 /* Step 7: Finish decompression */
252
253 (void)jpeg_finish_decompress(cinfo);
254 /* We can ignore the return value since suspension is not possible
255 * with the stdio data source.
256 */
257
258 /* Step 8: Release JPEG decompression object */
259
260 /* This is an important step since it will release a good deal of memory. */
261 jpeg_destroy_decompress(cinfo);
262
263 /* After finish_decompress, we can close the input file.
264 * Here we postpone it until after no more JPEG errors are possible,
265 * so as to simplify the setjmp error logic above. (Actually, I don't
266 * think that jpeg_destroy can do an error exit, but why assume anything...)
267 */
268 fclose(infile);
269
270 /* At this point you may want to check to see whether any corrupt-data
271 * warnings occurred (test whether jerr.pub.num_warnings is nonzero).
272 */
273
274 /* And we're done! */
275 return true;
276}
codec_error_exit(j_common_ptr cinfo)

◆ ReadJpegFile()

bool ReadJpegFile ( char const * filename,
unsigned int & width,
unsigned int & height,
std::vector< unsigned int > & rgbImageDataVector )
static

Reads a JPEG file into an RGB image buffer.

Parameters
filenamePath to input JPEG file.
width[out] Image width in pixels.
height[out] Image height in pixels.
rgbImageDataVector[out] Output vector of RGB pixel data (3 bytes per pixel).
Returns
true on success, false on failure.

Definition at line 135 of file image_codec_jpeg.hpp.

136{
137 /* This struct contains the JPEG decompression parameters and pointers to
138 * working space (which is allocated as needed by the JPEG library).
139 */
140 struct jpeg_decompress_struct cinfo;
141
142 return DoReadJpegFile(&cinfo, filename, width, height, rgbImageDataVector);
143}
static bool DoReadJpegFile(struct jpeg_decompress_struct *cinfo, char const *filename, unsigned int &width, unsigned int &height, std::vector< unsigned int > &rgbImageDataVector)

◆ ReadJpegFromMemory()

bool ReadJpegFromMemory ( const unsigned char * memory,
size_t memorySize,
unsigned int & width,
unsigned int & height,
std::vector< unsigned int > & rgbImageDataVector )
static

Decode a JPEG image directly from a memory buffer.

This function behaves similarly to ReadJpegFile(), but instead of reading from disk, it reads raw JPEG bytes already loaded in memory.

Useful when assets are stored in:

  • packed archives (Pack.bin)
  • networked streams
  • compressed inline resources

The function expects the buffer to contain valid JPEG-formatted data.

Parameters
memoryPointer to the start of the JPEG byte stream.
memorySizeTotal size of the memory buffer in bytes.
width[out] Decoded image width in pixels.
height[out] Decoded image height in pixels.
rgbImageDataVector[out] Output RGB pixel buffer (3 bytes per pixel).
Returns
  • true → Successful decode.
  • false → Memory buffer was not a valid JPEG stream or decode failed.
Warning
The function does not attempt format detection beyond JPEG signature. Callers must ensure the memory buffer contains JPEG data.

Definition at line 314 of file image_codec_jpeg.hpp.

320{
321 struct jpeg_decompress_struct cinfo;
322 struct codec_error_mgr jerr;
323
324 cinfo.err = jpeg_std_error(&jerr.pub);
325 jerr.pub.error_exit = codec_error_exit;
326
327 if (setjmp(jerr.setjmp_buffer)) {
328 jpeg_destroy_decompress(&cinfo);
329 return false;
330 }
331
332 jpeg_create_decompress(&cinfo);
333
334 jpeg_mem_src(&cinfo, memory, memorySize);
335
336 jpeg_read_header(&cinfo, TRUE);
337 jpeg_start_decompress(&cinfo);
338
339 width = cinfo.output_width;
340 height = cinfo.output_height;
341 unsigned int components = cinfo.output_components; // should = 3
342
343 size_t row_stride = width * components;
344 rgbImageDataVector.resize(width * height * components);
345
346 while (cinfo.output_scanline < cinfo.output_height)
347 {
348 unsigned char* row = (unsigned char*)(
349 rgbImageDataVector.data() +
350 cinfo.output_scanline * row_stride
351 );
352 jpeg_read_scanlines(&cinfo, &row, 1);
353 }
354
355 jpeg_finish_decompress(&cinfo);
356 jpeg_destroy_decompress(&cinfo);
357
358 return true;
359}

◆ SaveTextureFileJpeg()

void SaveTextureFileJpeg ( rendering_engine::ImageData const & imageData,
char const * filename )
static

Saves image data to a JPEG file.

Parameters
imageDataSource image in RGB format.
filenamePath to the output file.

Definition at line 38 of file image_codec_jpeg.hpp.

39{
40 auto const imageDataVector = imageData.GetImageDataRGB();
41 JSAMPLE* imageBuffer = new JSAMPLE[imageDataVector.size()];
42 std::copy(imageDataVector.begin(), imageDataVector.end(), imageBuffer);
43 int quality = 100;
44
45 struct jpeg_compress_struct cinfo;
46 struct jpeg_error_mgr jerr;
47
48 FILE* outfile; /* target file */
49 JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
50 int row_stride; /* physical row width in image buffer */
51
52 cinfo.err = jpeg_std_error(&jerr);
53 jpeg_create_compress(&cinfo);
54
55 if( (outfile = fopen(filename, "wb")) == NULL ) {
56 fprintf(stderr, "can't open %s\n", filename);
57 exit(1);
58 }
59 jpeg_stdio_dest(&cinfo, outfile);
60
61 cinfo.image_width = imageData.GetWidth(); /* image width and height, in pixels */
62 cinfo.image_height = imageData.GetHeight();
63 cinfo.input_components = 3; /* # of color components per pixel */
64 cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
65
66 jpeg_set_defaults(&cinfo);
67
68 jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
69
70 jpeg_start_compress(&cinfo, TRUE);
71
72 row_stride = imageData.GetWidth() * 3; /* JSAMPLEs per row in image_buffer */
73
74 while( cinfo.next_scanline < cinfo.image_height )
75 {
76 /* jpeg_write_scanlines expects an array of pointers to scanlines.
77 * Here the array is only one element long, but you could pass
78 * more than one scanline at a time if that's more convenient.
79 */
80 row_pointer[0] = &imageBuffer[cinfo.next_scanline * row_stride];
81 (void)jpeg_write_scanlines(&cinfo, row_pointer, 1);
82 }
83
84 jpeg_finish_compress(&cinfo);
85 /* After finish_compress, we can close the output file. */
86 fclose(outfile);
87
88 jpeg_destroy_compress(&cinfo);
89 delete[] imageBuffer;
90}