bool CxImageJPG::Decode(CxFile * hFile) { bool is_exif = false; #if CXIMAGEJPG_SUPPORT_EXIF is_exif = DecodeExif(hFile); #endif CImageIterator iter(this); /* This struct contains the JPEG decompression parameters and pointers to * working space (which is allocated as needed by the JPEG library). */ struct jpeg_decompress_struct cinfo; /* We use our private extension JPEG error handler. <CSC> */ struct jpg_error_mgr jerr; jerr.buffer=info.szLastError; /* More stuff */ JSAMPARRAY buffer; /* Output row buffer */ int32_t row_stride; /* physical row width in output buffer */ /* In this example we want to open the input file before doing anything else, * so that the setjmp() error recovery below can assume the file is open. * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that * requires it in order to read binary files. */ /* Step 1: allocate and initialize JPEG decompression object */ /* We set up the normal JPEG error routines, then override error_exit. */ cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = ima_jpeg_error_exit; CxFileJpg src(hFile); /* Establish the setjmp return context for my_error_exit to use. */ if (setjmp(jerr.setjmp_buffer)) { /* If we get here, the JPEG code has signaled an error. * We need to clean up the JPEG object, close the input file, and return. */ jpeg_destroy_decompress(&cinfo); return 0; } /* Now we can initialize the JPEG decompression object. */ jpeg_create_decompress(&cinfo); /* Step 2: specify data source (eg, a file) */ //jpeg_stdio_src(&cinfo, infile); cinfo.src = &src; /* Step 3: read file parameters with jpeg_read_header() */ (void) jpeg_read_header(&cinfo, TRUE); /* Step 4 <chupeev> handle decoder options*/ uint32_t dwCodecOptions = GetCodecOption(CXIMAGE_FORMAT_JPG); //[nm_114] if ((dwCodecOptions & DECODE_GRAYSCALE) != 0) cinfo.out_color_space = JCS_GRAYSCALE; if ((dwCodecOptions & DECODE_QUANTIZE) != 0) { cinfo.quantize_colors = TRUE; cinfo.desired_number_of_colors = GetJpegQuality(); } if ((dwCodecOptions & DECODE_DITHER) != 0) cinfo.dither_mode = m_nDither; if ((dwCodecOptions & DECODE_ONEPASS) != 0) cinfo.two_pass_quantize = FALSE; if ((dwCodecOptions & DECODE_NOSMOOTH) != 0) cinfo.do_fancy_upsampling = FALSE; //<DP>: Load true color images as RGB (no quantize) /* Step 4: set parameters for decompression */ /* if (cinfo.jpeg_color_space!=JCS_GRAYSCALE) { * cinfo.quantize_colors = TRUE; * cinfo.desired_number_of_colors = 128; *} */ //</DP> cinfo.scale_num = 1; // Set the scale <ignacio> cinfo.scale_denom = GetJpegScale(); // Borrowed the idea from GIF implementation <ignacio> if (info.nEscape == -1) { // Return output dimensions only jpeg_calc_output_dimensions(&cinfo); head.biWidth = cinfo.output_width; head.biHeight = cinfo.output_height; info.dwType = CXIMAGE_FORMAT_JPG; jpeg_destroy_decompress(&cinfo); return true; } /* Step 5: Start decompressor */ jpeg_start_decompress(&cinfo); /* We may need to do some setup of our own at this point before reading * the data. After jpeg_start_decompress() we have the correct scaled * output image dimensions available, as well as the output colormap * if we asked for color quantization. */ //Create the image using output dimensions <ignacio> //Create(cinfo.image_width, cinfo.image_height, 8*cinfo.output_components, CXIMAGE_FORMAT_JPG); Create(cinfo.output_width, cinfo.output_height, 8*cinfo.output_components, CXIMAGE_FORMAT_JPG); if (!pDib) longjmp(jerr.setjmp_buffer, 1); //<DP> check if the image has been created if (is_exif){ #if CXIMAGEJPG_SUPPORT_EXIF if ((info.ExifInfo.Xresolution != 0.0) && (info.ExifInfo.ResolutionUnit != 0)) SetXDPI((int32_t)(info.ExifInfo.Xresolution/info.ExifInfo.ResolutionUnit)); if ((info.ExifInfo.Yresolution != 0.0) && (info.ExifInfo.ResolutionUnit != 0)) SetYDPI((int32_t)(info.ExifInfo.Yresolution/info.ExifInfo.ResolutionUnit)); #endif } else { switch (cinfo.density_unit) { case 0: // [andy] fix for aspect ratio... if((cinfo.Y_density > 0) && (cinfo.X_density > 0)){ SetYDPI((int32_t)(GetXDPI()*(float(cinfo.Y_density)/float(cinfo.X_density)))); } break; case 2: // [andy] fix: cinfo.X/Y_density is pixels per centimeter SetXDPI((int32_t)floor(cinfo.X_density * 2.54 + 0.5)); SetYDPI((int32_t)floor(cinfo.Y_density * 2.54 + 0.5)); break; default: SetXDPI(cinfo.X_density); SetYDPI(cinfo.Y_density); } } if (cinfo.out_color_space==JCS_GRAYSCALE){ SetGrayPalette(); head.biClrUsed =256; } else { if (cinfo.quantize_colors){ SetPalette(cinfo.actual_number_of_colors, cinfo.colormap[0], cinfo.colormap[1], cinfo.colormap[2]); head.biClrUsed=cinfo.actual_number_of_colors; } else { head.biClrUsed=0; } } /* JSAMPLEs per row in output buffer */ row_stride = cinfo.output_width * cinfo.output_components; /* Make a one-row-high sample array that will go away when done with image */ buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); /* Step 6: while (scan lines remain to be read) */ /* jpeg_read_scanlines(...); */ /* Here we use the library's state variable cinfo.output_scanline as the * loop counter, so that we don't have to keep track ourselves. */ iter.Upset(); while (cinfo.output_scanline < cinfo.output_height) { if (info.nEscape) longjmp(jerr.setjmp_buffer, 1); // <vho> - cancel decoding (void) jpeg_read_scanlines(&cinfo, buffer, 1); // info.nProgress = (int32_t)(100*cinfo.output_scanline/cinfo.output_height); //<DP> Step 6a: CMYK->RGB */ if ((cinfo.num_components==4)&&(cinfo.quantize_colors==FALSE)){ uint8_t k,*dst,*src; dst=iter.GetRow(); src=buffer[0]; for(int32_t x3=0,x4=0; x3<(int32_t)info.dwEffWidth && x4<row_stride; x3+=3, x4+=4){ k=src[x4+3]; dst[x3] =(uint8_t)((k * src[x4+2])/255); dst[x3+1]=(uint8_t)((k * src[x4+1])/255); dst[x3+2]=(uint8_t)((k * src[x4+0])/255); } } else { /* Assume put_scanline_someplace wants a pointer and sample count. */ iter.SetRow(buffer[0], row_stride); } iter.PrevRow(); } /* Step 7: Finish decompression */ (void) jpeg_finish_decompress(&cinfo); /* We can ignore the return value since suspension is not possible * with the stdio data source. */ //<DP> Step 7A: Swap red and blue components // not necessary if swapped red and blue definition in jmorecfg.h;ln322 <W. Morrison> if ((cinfo.num_components==3)&&(cinfo.quantize_colors==FALSE)){ uint8_t* r0=GetBits(); for(int32_t y=0;y<head.biHeight;y++){ if (info.nEscape) longjmp(jerr.setjmp_buffer, 1); // <vho> - cancel decoding RGBtoBGR(r0,3*head.biWidth); r0+=info.dwEffWidth; } } /* Step 8: Release JPEG decompression object */ /* This is an important step since it will release a good deal of memory. */ jpeg_destroy_decompress(&cinfo); /* At this point you may want to check to see whether any corrupt-data * warnings occurred (test whether jerr.pub.num_warnings is nonzero). */ /* And we're done! */ return true; }
int main (int argc, char **argv) { struct jpeg_decompress_struct srcinfo; struct jpeg_compress_struct dstinfo; struct jpeg_error_mgr jsrcerr, jdsterr; #ifdef PROGRESS_REPORT struct cdjpeg_progress_mgr progress; #endif jvirt_barray_ptr * src_coef_arrays; jvirt_barray_ptr * dst_coef_arrays; int file_index; FILE * input_file; FILE * output_file; /* On Mac, fetch a command line. */ #ifdef USE_CCOMMAND argc = ccommand(&argv); #endif progname = argv[0]; if (progname == NULL || progname[0] == 0) progname = "jpegtran"; /* in case C library doesn't provide it */ /* Initialize the JPEG decompression object with default error handling. */ srcinfo.err = jpeg_std_error(&jsrcerr); jpeg_create_decompress(&srcinfo); /* Initialize the JPEG compression object with default error handling. */ dstinfo.err = jpeg_std_error(&jdsterr); jpeg_create_compress(&dstinfo); /* Now safe to enable signal catcher. * Note: we assume only the decompression object will have virtual arrays. */ #ifdef NEED_SIGNAL_CATCHER enable_signal_catcher((j_common_ptr) &srcinfo); #endif /* Scan command line to find file names. * It is convenient to use just one switch-parsing routine, but the switch * values read here are mostly ignored; we will rescan the switches after * opening the input file. Also note that most of the switches affect the * destination JPEG object, so we parse into that and then copy over what * needs to affects the source too. */ file_index = parse_switches(&dstinfo, argc, argv, 0, FALSE); jsrcerr.trace_level = jdsterr.trace_level; srcinfo.mem->max_memory_to_use = dstinfo.mem->max_memory_to_use; #ifdef TWO_FILE_COMMANDLINE /* Must have either -outfile switch or explicit output file name */ if (outfilename == NULL) { if (file_index != argc-2) { fprintf(stderr, "%s: must name one input and one output file\n", progname); usage(); } outfilename = argv[file_index+1]; } else { if (file_index != argc-1) { fprintf(stderr, "%s: must name one input and one output file\n", progname); usage(); } } #else /* Unix style: expect zero or one file name */ if (file_index < argc-1) { fprintf(stderr, "%s: only one input file\n", progname); usage(); } #endif /* TWO_FILE_COMMANDLINE */ /* Open the input file. */ if (file_index < argc) { if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) { fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]); exit(EXIT_FAILURE); } } else { /* default input file is stdin */ input_file = read_stdin(); } /* Open the output file. */ if (outfilename != NULL) { if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) { fprintf(stderr, "%s: can't open %s\n", progname, outfilename); exit(EXIT_FAILURE); } } else { /* default output file is stdout */ output_file = write_stdout(); } #ifdef PROGRESS_REPORT start_progress_monitor((j_common_ptr) &dstinfo, &progress); #endif /* Specify data source for decompression */ jpeg_stdio_src(&srcinfo, input_file); /* Enable saving of extra markers that we want to copy */ jcopy_markers_setup(&srcinfo, copyoption); /* Read file header */ (void) jpeg_read_header(&srcinfo, TRUE); /* Any space needed by a transform option must be requested before * jpeg_read_coefficients so that memory allocation will be done right. */ #if TRANSFORMS_SUPPORTED jtransform_request_workspace(&srcinfo, &transformoption); #endif /* Read source file as DCT coefficients */ src_coef_arrays = jpeg_read_coefficients(&srcinfo); /* Initialize destination compression parameters from source values */ jpeg_copy_critical_parameters(&srcinfo, &dstinfo); /* Adjust destination parameters if required by transform options; * also find out which set of coefficient arrays will hold the output. */ #if TRANSFORMS_SUPPORTED dst_coef_arrays = jtransform_adjust_parameters(&srcinfo, &dstinfo, src_coef_arrays, &transformoption); #else dst_coef_arrays = src_coef_arrays; #endif /* Adjust default compression parameters by re-parsing the options */ file_index = parse_switches(&dstinfo, argc, argv, 0, TRUE); /* Specify data destination for compression */ jpeg_stdio_dest(&dstinfo, output_file); /* Start compressor (note no image data is actually written here) */ jpeg_write_coefficients(&dstinfo, dst_coef_arrays); /* Copy to the output file any extra markers that we want to preserve */ jcopy_markers_execute(&srcinfo, &dstinfo, copyoption); /* Execute image transformation, if any */ #if TRANSFORMS_SUPPORTED jtransform_execute_transformation(&srcinfo, &dstinfo, src_coef_arrays, &transformoption); #endif /* Finish compression and release memory */ jpeg_finish_compress(&dstinfo); jpeg_destroy_compress(&dstinfo); (void) jpeg_finish_decompress(&srcinfo); jpeg_destroy_decompress(&srcinfo); /* Close files, if we opened them */ if (input_file != stdin) fclose(input_file); if (output_file != stdout) fclose(output_file); #ifdef PROGRESS_REPORT end_progress_monitor((j_common_ptr) &dstinfo); #endif /* All done. */ exit(jsrcerr.num_warnings + jdsterr.num_warnings ?EXIT_WARNING:EXIT_SUCCESS); return 0; /* suppress no-return-value warnings */ }
/** * jpgutl_decode_jpeg * Purpose: Decompress the jpeg data_in into the img_out buffer. * * Parameters: * jpeg_data_in The jpeg data sent in * jpeg_data_len The length of the jpeg data * width The width of the image * height The height of the image * img_out Pointer to the image output * * Return Values * Success 0, Failure -1 */ int jpgutl_decode_jpeg (unsigned char *jpeg_data_in, int jpeg_data_len, unsigned int width, unsigned int height, unsigned char *volatile img_out) { JSAMPARRAY line; /* Array of decomp data lines */ unsigned char *wline; /* Will point to line[0] */ unsigned int i; unsigned char *img_y, *img_cb, *img_cr; unsigned char offset_y; struct jpeg_decompress_struct dinfo; struct jpgutl_error_mgr jerr; /* We set up the normal JPEG error routines, then override error_exit. */ dinfo.err = jpeg_std_error (&jerr.pub); jerr.pub.error_exit = jpgutl_error_exit; /* Also hook the emit_message routine to note corrupt-data warnings. */ jerr.original_emit_message = jerr.pub.emit_message; jerr.pub.emit_message = jpgutl_emit_message; jerr.warning_seen = 0; jpeg_create_decompress (&dinfo); /* Establish the setjmp return context for jpgutl_error_exit to use. */ if (setjmp (jerr.setjmp_buffer)) { /* If we get here, the JPEG code has signaled an error. */ jpeg_destroy_decompress (&dinfo); return -1; } jpgutl_buffer_src (&dinfo, jpeg_data_in, jpeg_data_len); jpeg_read_header (&dinfo, TRUE); //420 sampling is the default for YCbCr so no need to override. dinfo.out_color_space = JCS_YCbCr; dinfo.dct_method = JDCT_DEFAULT; guarantee_huff_tables(&dinfo); /* Required by older versions of the jpeg libs */ jpeg_start_decompress (&dinfo); if ((dinfo.output_width == 0) || (dinfo.output_height == 0)) { MOTION_LOG(WRN, TYPE_VIDEO, NO_ERRNO,_("Invalid JPEG image dimensions")); jpeg_destroy_decompress(&dinfo); return -1; } if ((dinfo.output_width != width) || (dinfo.output_height != height)) { MOTION_LOG(WRN, TYPE_VIDEO, NO_ERRNO ,_("JPEG image size %dx%d, JPEG was %dx%d") ,width, height, dinfo.output_width, dinfo.output_height); jpeg_destroy_decompress(&dinfo); return -1; } img_y = img_out; img_cb = img_y + dinfo.output_width * dinfo.output_height; img_cr = img_cb + (dinfo.output_width * dinfo.output_height) / 4; /* Allocate space for one line. */ line = (*dinfo.mem->alloc_sarray)((j_common_ptr) &dinfo, JPOOL_IMAGE, dinfo.output_width * dinfo.output_components, 1); wline = line[0]; offset_y = 0; while (dinfo.output_scanline < dinfo.output_height) { jpeg_read_scanlines(&dinfo, line, 1); for (i = 0; i < (dinfo.output_width * 3); i += 3) { img_y[i / 3] = wline[i]; if (i & 1) { img_cb[(i / 3) / 2] = wline[i + 1]; img_cr[(i / 3) / 2] = wline[i + 2]; } } img_y += dinfo.output_width; if (offset_y++ & 1) { img_cb += dinfo.output_width / 2; img_cr += dinfo.output_width / 2; } } jpeg_finish_decompress(&dinfo); jpeg_destroy_decompress(&dinfo); /* * If there are too many warnings, this means that * only a partial image could be returned which would * trigger many false positive motion detections */ if (jerr.warning_seen > 2) return -1; return 0; }
jpeg_comp_dct_t *libjpeg_get_dct_data(const char *filepath) { int ic, ret; xyi_t ib; uint8_t *filedata; size_t filedata_size; struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; jvirt_barray_ptr *coefs; jpeg_comp_dct_t *out=NULL; JBLOCKARRAY dct; jpeg_component_info *compinf; filedata = load_raw_file(filepath, &filedata_size); if (filedata==NULL) return NULL; // allocate and initialize JPEG decompression object cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); jpeg_mem_src(&cinfo, filedata, filedata_size); //jpeg_stdio_src(&cinfo, file); // specify file ret = jpeg_read_header(&cinfo, TRUE); // read file header if (ret != 1) fprintf_rl(stderr, "File '%s' cannot be read by jpeg_read_header()\n", filepath); else { coefs = jpeg_read_coefficients(&cinfo); // read all the coefs (DCT, quantisation table etc) if (coefs) { out = calloc(3, sizeof(jpeg_comp_dct_t)); // copy every DCT block and the quantisation table for every component for (ic=0; ic<3; ic++) { compinf = &cinfo.comp_info[ic]; out[ic].image_dim = xyi(cinfo.image_width, cinfo.image_height); out[ic].block_dim = xyi(compinf->width_in_blocks, compinf->height_in_blocks); dct = (cinfo.mem->access_virt_barray) ((j_common_ptr) (&cinfo), coefs[ic], 0, compinf->v_samp_factor, FALSE); memcpy(out[ic].quant, compinf->quant_table->quantval, DCTSIZE2 * sizeof(uint16_t)); // copy quantisation table // copy DCT blocks out[ic].dct_block = calloc(mul_x_by_y_xyi(out[ic].block_dim), sizeof(int16_t *)); for (ib.y=0; ib.y < out[ic].block_dim.y; ib.y++) for (ib.x=0; ib.x < out[ic].block_dim.x; ib.x++) { out[ic].dct_block[ib.y * out[ic].block_dim.x + ib.x] = calloc(DCTSIZE2, sizeof(int16_t)); memcpy(out[ic].dct_block[ib.y * out[ic].block_dim.x + ib.x], dct[ib.y][ib.x], DCTSIZE2 * sizeof(int16_t)); } } } } // free the libjpeg stuff jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); free(filedata); return out; }
int ReadTextureFromJPG( struct Texture * t, const char * filename ) { #ifndef USE_JPG fprintf( stderr, "Error. Cannot load: %s. JPG Support not included.\n" ); return -1; #else //from: https://github.com/LuaDist/libjpeg/blob/master/example.c struct jpeg_decompress_struct cinfo; struct my_error_mgr jerr; FILE * infile; JSAMPARRAY buffer; int row_stride; if ((infile = fopen(filename, "rb")) == NULL) { fprintf(stderr, "can't open %s\n", filename); return 0; } cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = my_error_exit; if (setjmp(jerr.setjmp_buffer)) { jpeg_destroy_decompress(&cinfo); fclose(infile); return 0; } jpeg_create_decompress(&cinfo); jpeg_stdio_src(&cinfo, infile); (void) jpeg_read_header(&cinfo, TRUE); (void) jpeg_start_decompress(&cinfo); row_stride = cinfo.output_width * cinfo.output_components; buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); if( cinfo.output_components != 3 && cinfo.output_components != 1 ) { jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); fclose(infile); return -2; } t->format = (cinfo.output_components==3)?TTRGB:TTGRAYSCALE; t->width = cinfo.output_width; t->height = cinfo.output_height; t->type = GL_TEXTURE_2D; t->rawdata = malloc( t->width * t->height * cinfo.output_components ); int line = 0; while (cinfo.output_scanline < cinfo.output_height) { int i; jpeg_read_scanlines(&cinfo, buffer, 1); memcpy( &t->rawdata[row_stride * line], buffer[0], row_stride ); line++; } fail: jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); fclose(infile); return 0; #endif }
bool JpegDecoder::readData( Mat& img ) { bool result = false; int step = (int)img.step; bool color = img.channels() > 1; if( m_state && m_width && m_height ) { jpeg_decompress_struct* cinfo = &((JpegState*)m_state)->cinfo; JpegErrorMgr* jerr = &((JpegState*)m_state)->jerr; JSAMPARRAY buffer = 0; if( setjmp( jerr->setjmp_buffer ) == 0 ) { /* check if this is a mjpeg image format */ if ( cinfo->ac_huff_tbl_ptrs[0] == NULL && cinfo->ac_huff_tbl_ptrs[1] == NULL && cinfo->dc_huff_tbl_ptrs[0] == NULL && cinfo->dc_huff_tbl_ptrs[1] == NULL ) { /* yes, this is a mjpeg image format, so load the correct huffman table */ my_jpeg_load_dht( cinfo, my_jpeg_odml_dht, cinfo->ac_huff_tbl_ptrs, cinfo->dc_huff_tbl_ptrs ); } if( color ) { if( cinfo->num_components != 4 ) { cinfo->out_color_space = JCS_RGB; cinfo->out_color_components = 3; } else { cinfo->out_color_space = JCS_CMYK; cinfo->out_color_components = 4; } } else { if( cinfo->num_components != 4 ) { cinfo->out_color_space = JCS_GRAYSCALE; cinfo->out_color_components = 1; } else { cinfo->out_color_space = JCS_CMYK; cinfo->out_color_components = 4; } } jpeg_start_decompress( cinfo ); buffer = (*cinfo->mem->alloc_sarray)((j_common_ptr)cinfo, JPOOL_IMAGE, m_width*4, 1 ); uchar* data = img.ptr(); for( ; m_height--; data += step ) { jpeg_read_scanlines( cinfo, buffer, 1 ); if( color ) { if( cinfo->out_color_components == 3 ) icvCvt_RGB2BGR_8u_C3R( buffer[0], 0, data, 0, cvSize(m_width,1) ); else icvCvt_CMYK2BGR_8u_C4C3R( buffer[0], 0, data, 0, cvSize(m_width,1) ); } else { if( cinfo->out_color_components == 1 ) memcpy( data, buffer[0], m_width ); else icvCvt_CMYK2Gray_8u_C4C1R( buffer[0], 0, data, 0, cvSize(m_width,1) ); } } result = true; jpeg_finish_decompress( cinfo ); } } close(); return result; }
void LoadJPG( const char *filename, unsigned char **pic, int *width, int *height, int *numLayers, int *numMips, int *bits, byte alphaByte ) { /* This struct contains the JPEG decompression parameters and pointers to * working space (which is allocated as needed by the JPEG library). */ struct jpeg_decompress_struct cinfo = { nullptr }; /* We use our private extension JPEG error handler. * Note that this struct must live as long as the main JPEG parameter * struct, to avoid dangling-pointer problems. */ /* This struct represents a JPEG error handler. It is declared separately * because applications often want to supply a specialized error handler * (see the second half of this file for an example). But here we just * take the easy way out and use the standard error handler, which will * print a message on stderr and call exit() if compression fails. * Note that this struct must live as long as the main JPEG parameter * struct, to avoid dangling-pointer problems. */ struct jpeg_error_mgr jerr; /* More stuff */ JSAMPARRAY buffer; /* Output row buffer */ unsigned int row_stride; /* physical row width in output buffer */ unsigned int pixelcount, memcount; unsigned int sindex, dindex; byte *out; int len; union { byte *b; void *v; } fbuffer; byte *buf; #if JPEG_LIB_VERSION < 80 FILE *jpegfd; #endif /* In this example we want to open the input file before doing anything else, * so that the setjmp() error recovery below can assume the file is open. * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that * requires it in order to read binary files. */ len = ri.FS_ReadFile( ( char * ) filename, &fbuffer.v ); if ( !fbuffer.b || len < 0 ) { return; } /* Step 1: allocate and initialize JPEG decompression object */ /* We have to set up the error handler first, in case the initialization * step fails. (Unlikely, but it could happen if you are out of memory.) * This routine fills in the contents of struct jerr, and returns jerr's * address which we place into the link field in cinfo. */ cinfo.err = jpeg_std_error( &jerr ); cinfo.err->error_exit = R_JPGErrorExit; cinfo.err->output_message = R_JPGOutputMessage; /* Now we can initialize the JPEG decompression object. */ jpeg_create_decompress( &cinfo ); /* Step 2: specify data source (eg, a file) */ #if JPEG_LIB_VERSION < 80 jpegfd = fmemopen( fbuffer.b, len, "r" ); jpeg_stdio_src( &cinfo, jpegfd ); #else jpeg_mem_src( &cinfo, fbuffer.b, len ); #endif /* Step 3: read file parameters with jpeg_read_header() */ Q_UNUSED(jpeg_read_header( &cinfo, TRUE )); /* We can ignore the return value from jpeg_read_header since * (a) suspension is not possible with the stdio data source, and * (b) we passed TRUE to reject a tables-only JPEG file as an error. * See libjpeg.doc for more info. */ /* Step 4: set parameters for decompression */ /* * Make sure it always converts images to RGB color space. This will * automatically convert 8-bit greyscale images to RGB as well. */ cinfo.out_color_space = JCS_RGB; /* Step 5: Start decompressor */ Q_UNUSED(jpeg_start_decompress( &cinfo )); /* We can ignore the return value since suspension is not possible * with the stdio data source. */ /* We may need to do some setup of our own at this point before reading * the data. After jpeg_start_decompress() we have the correct scaled * output image dimensions available, as well as the output colormap * if we asked for color quantization. * In this example, we need to make an output work buffer of the right size. */ /* JSAMPLEs per row in output buffer */ pixelcount = cinfo.output_width * cinfo.output_height; if ( !cinfo.output_width || !cinfo.output_height || ( ( pixelcount * 4 ) / cinfo.output_width ) / 4 != cinfo.output_height || pixelcount > 0x1FFFFFFF || cinfo.output_components != 3 ) { // Free the memory to make sure we don't leak memory ri.FS_FreeFile( fbuffer.v ); jpeg_destroy_decompress( &cinfo ); #if JPEG_LIB_VERSION < 80 fclose( jpegfd ); #endif ri.Error( ERR_DROP, "LoadJPG: %s has an invalid image format: %dx%d*4=%d, components: %d", filename, cinfo.output_width, cinfo.output_height, pixelcount * 4, cinfo.output_components ); } memcount = pixelcount * 4; row_stride = cinfo.output_width * cinfo.output_components; out = (byte*) ri.Z_Malloc( memcount ); *width = cinfo.output_width; *height = cinfo.output_height; /* Step 6: while (scan lines remain to be read) */ /* jpeg_read_scanlines(...); */ /* Here we use the library's state variable cinfo.output_scanline as the * loop counter, so that we don't have to keep track ourselves. */ while ( cinfo.output_scanline < cinfo.output_height ) { /* jpeg_read_scanlines expects an array of pointers to scanlines. * Here the array is only one element long, but you could ask for * more than one scanline at a time if that's more convenient. */ buf = ( ( out + ( row_stride * cinfo.output_scanline ) ) ); buffer = &buf; Q_UNUSED(jpeg_read_scanlines( &cinfo, buffer, 1 )); } buf = out; // Expand from RGB to RGBA sindex = pixelcount * cinfo.output_components; dindex = memcount; do { buf[ --dindex ] = 255; buf[ --dindex ] = buf[ --sindex ]; buf[ --dindex ] = buf[ --sindex ]; buf[ --dindex ] = buf[ --sindex ]; } while ( sindex ); *pic = out; /* Step 7: Finish decompression */ jpeg_finish_decompress( &cinfo ); /* We can ignore the return value since suspension is not possible * with the stdio data source. */ /* Step 8: Release JPEG decompression object */ /* This is an important step since it will release a good deal of memory. */ jpeg_destroy_decompress( &cinfo ); /* After finish_decompress, we can close the input file. * Here we postpone it until after no more JPEG errors are possible, * so as to simplify the setjmp error logic above. (Actually, I don't * think that jpeg_destroy can do an error exit, but why assume anything...) */ #if JPEG_LIB_VERSION < 80 fclose( jpegfd ); #endif ri.FS_FreeFile( fbuffer.v ); /* At this point you may want to check to see whether any corrupt-data * warnings occurred (test whether jerr.pub.num_warnings is nonzero). */ /* And we're done! */ }
int v4lconvert_decode_jpeg_libjpeg(struct v4lconvert_data *data, unsigned char *src, int src_size, unsigned char *dest, struct v4l2_format *fmt, unsigned int dest_pix_fmt) { unsigned int width = fmt->fmt.pix.width; unsigned int height = fmt->fmt.pix.height; int result = 0; /* libjpeg errors before decoding the first line should signal EAGAIN */ data->jerr_errno = EAGAIN; result = setjmp(data->jerr_jmp_state); if (result) { if (data->cinfo_initialized) jpeg_abort_decompress(&data->cinfo); errno = result; return -1; } init_libjpeg_cinfo(data); jpeg_mem_src(&data->cinfo, src, src_size); jpeg_read_header(&data->cinfo, TRUE); if (data->cinfo.image_width != width || data->cinfo.image_height != height) { V4LCONVERT_ERR("unexpected width / height in JPEG header" "expected: %ux%u, header: %ux%u\n", width, height, data->cinfo.image_width, data->cinfo.image_height); errno = EIO; return -1; } if (data->cinfo.num_components != 3) { V4LCONVERT_ERR("unexpected no components in JPEG: %d\n", data->cinfo.num_components); errno = EIO; return -1; } if (dest_pix_fmt == V4L2_PIX_FMT_RGB24 || dest_pix_fmt == V4L2_PIX_FMT_BGR24) { JSAMPROW row_pointer[1]; #ifdef JCS_EXTENSIONS if (dest_pix_fmt == V4L2_PIX_FMT_BGR24) data->cinfo.out_color_space = JCS_EXT_BGR; #endif row_pointer[0] = dest; jpeg_start_decompress(&data->cinfo); /* Make libjpeg errors report that we've got some data */ data->jerr_errno = EPIPE; while (data->cinfo.output_scanline < height) { jpeg_read_scanlines(&data->cinfo, row_pointer, 1); row_pointer[0] += 3 * width; } jpeg_finish_decompress(&data->cinfo); #ifndef JCS_EXTENSIONS if (dest_pix_fmt == V4L2_PIX_FMT_BGR24) v4lconvert_swap_rgb(dest, dest, width, height); #endif } else { int h_samp, v_samp; unsigned char *udest, *vdest; if (data->cinfo.max_h_samp_factor == 2 && data->cinfo.cur_comp_info[0]->h_samp_factor == 2 && data->cinfo.cur_comp_info[1]->h_samp_factor == 1 && data->cinfo.cur_comp_info[2]->h_samp_factor == 1) { h_samp = 2; #if 0 /* HDG: untested, disable for now */ } else if (data->cinfo.max_h_samp_factor == 1 && data->cinfo.cur_comp_info[0]->h_samp_factor == 1 && data->cinfo.cur_comp_info[1]->h_samp_factor == 1 && data->cinfo.cur_comp_info[2]->h_samp_factor == 1) { h_samp = 1; #endif } else { fprintf(stderr, "libv4lconvert: unsupported jpeg h-sampling " "factors %d:%d:%d, please report this to " "[email protected]\n", data->cinfo.cur_comp_info[0]->h_samp_factor, data->cinfo.cur_comp_info[1]->h_samp_factor, data->cinfo.cur_comp_info[2]->h_samp_factor); errno = EOPNOTSUPP; return -1; } if (data->cinfo.max_v_samp_factor == 2 && data->cinfo.cur_comp_info[0]->v_samp_factor == 2 && data->cinfo.cur_comp_info[1]->v_samp_factor == 1 && data->cinfo.cur_comp_info[2]->v_samp_factor == 1) { v_samp = 2; } else if (data->cinfo.max_v_samp_factor == 1 && data->cinfo.cur_comp_info[0]->v_samp_factor == 1 && data->cinfo.cur_comp_info[1]->v_samp_factor == 1 && data->cinfo.cur_comp_info[2]->v_samp_factor == 1) { v_samp = 1; } else { fprintf(stderr, "libv4lconvert: unsupported jpeg v-sampling " "factors %d:%d:%d, please report this to " "[email protected]\n", data->cinfo.cur_comp_info[0]->v_samp_factor, data->cinfo.cur_comp_info[1]->v_samp_factor, data->cinfo.cur_comp_info[2]->v_samp_factor); errno = EOPNOTSUPP; return -1; } /* We don't want any padding as that may overflow our dest */ if (width % (8 * h_samp) || height % (8 * v_samp)) { V4LCONVERT_ERR( "resolution is not a multiple of dctsize"); errno = EIO; return -1; } if (dest_pix_fmt == V4L2_PIX_FMT_YVU420) { vdest = dest + width * height; udest = vdest + (width * height) / 4; } else { udest = dest + width * height; vdest = udest + (width * height) / 4; } data->cinfo.raw_data_out = TRUE; data->cinfo.do_fancy_upsampling = FALSE; jpeg_start_decompress(&data->cinfo); /* Make libjpeg errors report that we've got some data */ data->jerr_errno = EPIPE; if (h_samp == 1) { result = decode_libjpeg_h_samp1(data, dest, udest, vdest, v_samp); } else { result = decode_libjpeg_h_samp2(data, dest, udest, vdest, v_samp); } if (result) jpeg_abort_decompress(&data->cinfo); else jpeg_finish_decompress(&data->cinfo); } return result; }