CDibSection* InformApp::GetImage(const char* path) { // Check if it's a PNG file CStdioFile imageFile; if (!imageFile.Open(path,CFile::modeRead|CFile::typeBinary)) return 0; png_byte fileHeader[8]; imageFile.Read(fileHeader,8); bool isPNG = (png_sig_cmp(fileHeader,0,8) == 0); if (isPNG) { // Prepare to read the PNG file png_structp png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING,(png_voidp)NULL,NULL,NULL); if (png_ptr == NULL) return 0; png_infop info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_read_struct(&png_ptr,(png_infopp)NULL,(png_infopp)NULL); return 0; } png_infop end_info = png_create_info_struct(png_ptr); if (end_info == NULL) { png_destroy_read_struct(&png_ptr,&info_ptr,(png_infopp)NULL); return 0; } // Set up the point to return to in case of error png_bytep* rowPointers = NULL; if (setjmp(png_jmpbuf(png_ptr))) { if (rowPointers) delete[] rowPointers; png_destroy_read_struct(&png_ptr,&info_ptr,&end_info); return 0; } png_init_io(png_ptr,imageFile.m_pStream); png_set_sig_bytes(png_ptr,8); png_read_info(png_ptr,info_ptr); // Get details of the image png_uint_32 width = png_get_image_width(png_ptr,info_ptr); png_uint_32 height = png_get_image_height(png_ptr,info_ptr); int bit_depth = png_get_bit_depth(png_ptr,info_ptr); int color_type = png_get_color_type(png_ptr,info_ptr); // Set up transforms to the required format if (color_type == PNG_COLOR_TYPE_PALETTE && bit_depth <= 8) png_set_palette_to_rgb(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) png_set_expand_gray_1_2_4_to_8(png_ptr); if (png_get_valid(png_ptr,info_ptr,PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); double gamma; if (png_get_gAMA(png_ptr,info_ptr,&gamma)) png_set_gamma(png_ptr,2.2,gamma); if (bit_depth == 16) png_set_strip_16(png_ptr); if (bit_depth < 8) png_set_packing(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); png_set_bgr(png_ptr); png_set_filler(png_ptr,0xFF,PNG_FILLER_AFTER); // Create a bitmap HDC dc = ::GetDC(NULL); CDibSection* dib = new CDibSection(); BOOL created = dib->CreateBitmap(dc,width,height); ::ReleaseDC(NULL,dc); if (!created) { png_destroy_read_struct(&png_ptr,&info_ptr,&end_info); return NULL; } // Read in the image rowPointers = new png_bytep[height]; for (int i = 0; i < (int)height; i++) rowPointers[i] = ((png_bytep)dib->GetBits())+(width*i*4); png_read_image(png_ptr,rowPointers); png_read_end(png_ptr,end_info); delete[] rowPointers; png_destroy_read_struct(&png_ptr,&info_ptr,&end_info); return dib; } else { imageFile.SeekToBegin(); struct jpeg_decompress_struct info; struct JPEGErrorInfo error; // Initialize the error handling info.err = jpeg_std_error(&(error.base)); error.base.error_exit = errorJPEGExit; error.base.output_message = outputJPEGMessage; if (setjmp(error.errorJump)) { jpeg_destroy_decompress(&info); return NULL; } // Set up the decompression jpeg_create_decompress(&info); jpeg_stdio_src(&info,imageFile.m_pStream); // Read the image attributes jpeg_read_header(&info,TRUE); jpeg_calc_output_dimensions(&info); int width = info.output_width; int height = info.output_height; // Force RGB output info.out_color_space = JCS_RGB; // Create a bitmap HDC dc = ::GetDC(NULL); CDibSection* dib = new CDibSection(); BOOL created = dib->CreateBitmap(dc,width,height); ::ReleaseDC(NULL,dc); if (!created) { jpeg_destroy_decompress(&info); return NULL; } // Get an output buffer JSAMPARRAY buffer = (*info.mem->alloc_sarray) ((j_common_ptr)&info,JPOOL_IMAGE,width*3,1); // Read in the image jpeg_start_decompress(&info); while ((int)info.output_scanline < height) { jpeg_read_scanlines(&info,buffer,1); BYTE* pixelRow = ((BYTE*)dib->GetBits())+(width*(info.output_scanline-1)*4); for (int i = 0; i < width; i++) { pixelRow[(i*4)+0] = (*buffer)[(i*3)+2]; pixelRow[(i*4)+1] = (*buffer)[(i*3)+1]; pixelRow[(i*4)+2] = (*buffer)[(i*3)+0]; pixelRow[(i*4)+3] = 0xFF; } } jpeg_finish_decompress(&info); jpeg_destroy_decompress(&info); return dib; } }
int main (int argc, char **argv) { struct jpegxr_file_struct finfo; struct jpeg_error_mgr jerr; #ifdef PROGRESS_REPORT struct cdjpeg_progress_mgr progress; #endif int file_index; djpeg_dest_ptr dest_mgr = NULL; FILE * input_file; FILE * output_file; JDIMENSION num_scanlines; /* On Mac, fetch a command line. */ #ifdef USE_CCOMMAND argc = ccommand(&argv); #endif progname = argv[0]; if (progname == NULL || progname[0] == 0) progname = "djpeg-xr"; /* in case C library doesn't provide it */ /* Initialize the JPEG-XR file decompression object with default error * handling. */ finfo.err = jpeg_std_error(&jerr); jpegxr_file_create_decompress(&finfo); /* Add some application-specific error messages (from cderror.h) */ jerr.addon_message_table = cdjpeg_message_table; jerr.first_addon_message = JMSG_FIRSTADDONCODE; jerr.last_addon_message = JMSG_LASTADDONCODE; /* Now safe to enable signal catcher. */ #ifdef NEED_SIGNAL_CATCHER enable_signal_catcher((j_common_ptr) &finfo); #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 ignored; we will rescan the switches after opening * the input file. * (Exception: tracing level set here controls verbosity for COM markers * found during jpeg_read_header...) */ file_index = parse_switches(&finfo, argc, argv, 0, FALSE); #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) &finfo, &progress); #endif /* Specify data source for decompression */ jpeg_stdio_src((j_common_ptr) &finfo, input_file); /* Read file header */ (void) jpegxr_file_read_metadata(&finfo); /* TODO - initialise the output module here */ /* Start decompressor */ (void) jpegxr_file_start_decompress(&finfo); /* Write output file header */ //(*dest_mgr->start_output) (&finfo, dest_mgr); /* TODO - process data, equivalent to jpeg_read_scanlines() */ //(*dest_mgr->finish_output) (&finfo, dest_mgr); /* Finish decompression and release memory. * Must be done in this order because output module has allocated memory * of lifespan JPOOL_IMAGE; it needs to finish before releasing memory. */ (void) jpegxr_file_finish_decompress(&finfo); jpegxr_file_destroy(&finfo); /* 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) &finfo); #endif /* All done. */ exit(jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS); return 0; /* suppress no-return-value warnings */ }
/*! * pixReadStreamJpeg() * * Input: stream * cmapflag (0 for no colormap in returned pix; * 1 to return an 8 bpp cmapped pix if spp = 3 or 4) * reduction (scaling factor: 1, 2, 4 or 8) * &nwarn (<optional return> number of warnings) * hint (a bitwise OR of L_JPEG_* values; 0 for default) * Return: pix, or null on error * * Usage: see pixReadJpeg() * Notes: * (1) The jpeg comment, if it exists, is not stored in the pix. */ PIX * pixReadStreamJpeg(FILE *fp, l_int32 cmapflag, l_int32 reduction, l_int32 *pnwarn, l_int32 hint) { l_int32 cyan, yellow, magenta, black, nwarn; l_int32 i, j, k, rval, gval, bval; l_int32 w, h, wpl, spp, ncolors, cindex, ycck, cmyk; l_uint32 *data; l_uint32 *line, *ppixel; JSAMPROW rowbuffer; PIX *pix; PIXCMAP *cmap; struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; jmp_buf jmpbuf; /* must be local to the function */ PROCNAME("pixReadStreamJpeg"); if (pnwarn) *pnwarn = 0; if (!fp) return (PIX *)ERROR_PTR("fp not defined", procName, NULL); if (cmapflag != 0 && cmapflag != 1) cmapflag = 0; /* default */ if (reduction != 1 && reduction != 2 && reduction != 4 && reduction != 8) return (PIX *)ERROR_PTR("reduction not in {1,2,4,8}", procName, NULL); if (BITS_IN_JSAMPLE != 8) /* set in jmorecfg.h */ return (PIX *)ERROR_PTR("BITS_IN_JSAMPLE != 8", procName, NULL); rewind(fp); pix = NULL; rowbuffer = NULL; /* Modify the jpeg error handling to catch fatal errors */ cinfo.err = jpeg_std_error(&jerr); jerr.error_exit = jpeg_error_catch_all_1; cinfo.client_data = (void *)&jmpbuf; if (setjmp(jmpbuf)) { pixDestroy(&pix); FREE(rowbuffer); return (PIX *)ERROR_PTR("internal jpeg error", procName, NULL); } /* Initialize jpeg structs for decompression */ jpeg_create_decompress(&cinfo); jpeg_stdio_src(&cinfo, fp); jpeg_read_header(&cinfo, TRUE); cinfo.scale_denom = reduction; cinfo.scale_num = 1; jpeg_calc_output_dimensions(&cinfo); if (hint & L_JPEG_READ_LUMINANCE) { cinfo.out_color_space = JCS_GRAYSCALE; spp = 1; L_INFO("reading luminance channel only\n", procName); } else { spp = cinfo.out_color_components; } /* Allocate the image and a row buffer */ w = cinfo.output_width; h = cinfo.output_height; ycck = (cinfo.jpeg_color_space == JCS_YCCK && spp == 4 && cmapflag == 0); cmyk = (cinfo.jpeg_color_space == JCS_CMYK && spp == 4 && cmapflag == 0); if (spp != 1 && spp != 3 && !ycck && !cmyk) { return (PIX *)ERROR_PTR("spp must be 1 or 3, or YCCK or CMYK", procName, NULL); } if ((spp == 3 && cmapflag == 0) || ycck || cmyk) { /* rgb or 4 bpp color */ rowbuffer = (JSAMPROW)CALLOC(sizeof(JSAMPLE), spp * w); pix = pixCreate(w, h, 32); } else { /* 8 bpp gray or colormapped */ rowbuffer = (JSAMPROW)CALLOC(sizeof(JSAMPLE), w); pix = pixCreate(w, h, 8); } if (!rowbuffer || !pix) { FREE(rowbuffer); pixDestroy(&pix); return (PIX *)ERROR_PTR("rowbuffer or pix not made", procName, NULL); } /* Initialize decompression. Set up a colormap for color * quantization if requested. */ if (spp == 1) { /* Grayscale or colormapped */ jpeg_start_decompress(&cinfo); } else { /* Color; spp == 3 or YCCK or CMYK */ if (cmapflag == 0) { /* 24 bit color in 32 bit pix or YCCK/CMYK */ cinfo.quantize_colors = FALSE; jpeg_start_decompress(&cinfo); } else { /* Color quantize to 8 bits */ cinfo.quantize_colors = TRUE; cinfo.desired_number_of_colors = 256; jpeg_start_decompress(&cinfo); /* Construct a pix cmap */ cmap = pixcmapCreate(8); ncolors = cinfo.actual_number_of_colors; for (cindex = 0; cindex < ncolors; cindex++) { rval = cinfo.colormap[0][cindex]; gval = cinfo.colormap[1][cindex]; bval = cinfo.colormap[2][cindex]; pixcmapAddColor(cmap, rval, gval, bval); } pixSetColormap(pix, cmap); } } wpl = pixGetWpl(pix); data = pixGetData(pix); /* Decompress. Unfortunately, we cannot use the return value * from jpeg_read_scanlines() to determine if there was a problem * with the data; it always appears to return 1. We can only * tell from the warnings during decoding, such as "premature * end of data segment". The default behavior is to return an * image even if there are warnings. However, by setting the * hint to have the same bit flag as L_JPEG_FAIL_ON_BAD_DATA, * no image will be returned if there are any warnings. */ for (i = 0; i < h; i++) { if (jpeg_read_scanlines(&cinfo, &rowbuffer, (JDIMENSION)1) == 0) { L_ERROR("read error at scanline %d\n", procName, i); pixDestroy(&pix); jpeg_destroy_decompress(&cinfo); FREE(rowbuffer); return (PIX *)ERROR_PTR("bad data", procName, NULL); } /* -- 24 bit color -- */ if ((spp == 3 && cmapflag == 0) || ycck || cmyk) { ppixel = data + i * wpl; if (spp == 3) { for (j = k = 0; j < w; j++) { SET_DATA_BYTE(ppixel, COLOR_RED, rowbuffer[k++]); SET_DATA_BYTE(ppixel, COLOR_GREEN, rowbuffer[k++]); SET_DATA_BYTE(ppixel, COLOR_BLUE, rowbuffer[k++]); ppixel++; } } else { /* This is a conversion from CMYK -> RGB that ignores color profiles, and is invoked when the image header claims to be in CMYK or YCCK colorspace. If in YCCK, libjpeg may be doing YCCK -> CMYK under the hood. To understand why the colors need to be inverted on read-in for the Adobe marker, see the "Special color spaces" section of "Using the IJG JPEG Library" by Thomas G. Lane: http://www.jpegcameras.com/libjpeg/libjpeg-3.html#ss3.1 The non-Adobe conversion is equivalent to: rval = black - black * cyan / 255 ... The Adobe conversion is equivalent to: rval = black - black * (255 - cyan) / 255 ... Note that cyan is the complement to red, and we are subtracting the complement color (weighted by black) from black. For Adobe conversions, where they've already inverted the CMY but not the K, we have to invert again. The results must be clipped to [0 ... 255]. */ for (j = k = 0; j < w; j++) { cyan = rowbuffer[k++]; magenta = rowbuffer[k++]; yellow = rowbuffer[k++]; black = rowbuffer[k++]; if (cinfo.saw_Adobe_marker) { rval = (black * cyan) / 255; gval = (black * magenta) / 255; bval = (black * yellow) / 255; } else { rval = black * (255 - cyan) / 255; gval = black * (255 - magenta) / 255; bval = black * (255 - yellow) / 255; } rval = L_MIN(L_MAX(rval, 0), 255); gval = L_MIN(L_MAX(gval, 0), 255); bval = L_MIN(L_MAX(bval, 0), 255); composeRGBPixel(rval, gval, bval, ppixel); ppixel++; } } } else { /* 8 bpp grayscale or colormapped pix */ line = data + i * wpl; for (j = 0; j < w; j++) SET_DATA_BYTE(line, j, rowbuffer[j]); } } nwarn = cinfo.err->num_warnings; if (pnwarn) *pnwarn = nwarn; /* If the pixel density is neither 1 nor 2, it may not be defined. * In that case, don't set the resolution. */ if (cinfo.density_unit == 1) { /* pixels per inch */ pixSetXRes(pix, cinfo.X_density); pixSetYRes(pix, cinfo.Y_density); } else if (cinfo.density_unit == 2) { /* pixels per centimeter */ pixSetXRes(pix, (l_int32)((l_float32)cinfo.X_density * 2.54 + 0.5)); pixSetYRes(pix, (l_int32)((l_float32)cinfo.Y_density * 2.54 + 0.5)); } if (cinfo.output_components != spp) fprintf(stderr, "output spp = %d, spp = %d\n", cinfo.output_components, spp); jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); FREE(rowbuffer); if (nwarn > 0) { if (hint & L_JPEG_FAIL_ON_BAD_DATA) { L_ERROR("fail with %d warning(s) of bad data\n", procName, nwarn); pixDestroy(&pix); } else { L_WARNING("%d warning(s) of bad data\n", procName, nwarn); } } return pix; }
int main(void) { char *filename = "./test.jpg"; /* Open JPEG image file. Don't forget to use b for binary. */ FILE *file = fopen(filename, "rb"); if (!file) { printf("Error opening jpeg file %s\n", filename); return -1; } /* * This struct contains the JPEG compression parameters and pointers to * working space (which is allocated as needed by the JPEG library). */ struct jpeg_decompress_struct cinfo; /* * This struct represents a JPEG error handler. */ struct jpeg_error_mgr jerr; /* Setup the error handler */ cinfo.err = jpeg_std_error(&jerr); /* Initialize JPEG decompression object */ jpeg_create_decompress(&cinfo); /* Specify input file */ jpeg_stdio_src(&cinfo, file); /* Read JPEG file header */ (void)jpeg_read_header(&cinfo, TRUE); /* Get colorspace */ int colorspace = getColorspace(cinfo); /* Print colorspace name based on other int */ switch (colorspace) { case 3: printf("Image colorspace is RGB\n"); break; case 1: printf("Image colorspace is grayscale\n"); break; default: printf("No colorspace recognized"); break; } /* Release memory */ jpeg_destroy_decompress(&cinfo); /* Close input file */ fclose(file); system("pause"); return 0; }
// JPG decompression now subroutinised so I can call it from the savegame stuff... // // (note, the param "byte* pJPGData" should be a malloc of 4K more than the JPG data because the decompressor will read // up to 4K beyond what's actually presented during decompression). // // This will Z_Malloc the output data buffer that gets fed back into "pic", so Z_Free it yourself later. // void Decompress_JPG( const char *filename, byte *pJPGData, unsigned char **pic, int *width, int *height ) { /* 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. * 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 */ int row_stride; /* physical row width in output buffer */ unsigned char *out; byte *bbuf; /* 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); /* Now we can initialize the JPEG decompression object. */ jpeg_create_decompress(&cinfo); /* Step 2: specify data source (eg, a file) */ jpeg_stdio_src(&cinfo, pJPGData); /* Step 3: read file parameters with jpeg_read_header() */ (void) 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 */ /* In this example, we don't need to change any of the defaults set by * jpeg_read_header(), so we do nothing here. */ /* Step 5: Start decompressor */ (void) 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 */ row_stride = cinfo.output_width * cinfo.output_components; if (cinfo.output_components!=4 && cinfo.output_components!=1 ) { VID_Printf(PRINT_WARNING, "JPG %s is unsupported color depth (%d)\n", filename, cinfo.output_components); } out = (byte *)Z_Malloc(cinfo.output_width*cinfo.output_height*4, TAG_TEMP_JPG, qfalse ); *pic = out; *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. */ bbuf = ((out+(row_stride*cinfo.output_scanline))); buffer = &bbuf; (void) jpeg_read_scanlines(&cinfo, buffer, 1); } // if we've just loaded a greyscale, then adjust it from 8-bit to 32bit by stretch-copying it over itself... // (this also does the alpha stuff as well) // if (cinfo.output_components == 1) { byte *pbDest = (*pic + (cinfo.output_width * cinfo.output_height * 4))-1; byte *pbSrc = (*pic + (cinfo.output_width * cinfo.output_height ))-1; int iPixels = cinfo.output_width * cinfo.output_height; for (int i=0; i<iPixels; i++) { byte b = *pbSrc--; *pbDest-- = 255; *pbDest-- = b; *pbDest-- = b; *pbDest-- = b; } } else {// clear all the alphas to 255 int i, j; byte *buf; buf = *pic; j = cinfo.output_width * cinfo.output_height * 4; for ( i = 3 ; i < j ; i+=4 ) { buf[i] = 255; } } /* 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. */ /* 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...) */ /* 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 LoadFromJPEG(char *Name, char *filename, int text_id, hBool map_tex) { /* 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. * Note that this struct must live as long as the main JPEG parameter * struct, to avoid dangling-pointer problems. */ struct my_error_mgr jerr; /* More stuff */ JSAMPARRAY buffer; /* Output row buffer */ int 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. */ FILE * infile = fopen(filename, "r"); // rb if(infile == NULL) { //fprintf(stderr, "can't open %s\n", filename); return 0; } /* 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 = my_error_exit; /* 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); fclose(infile); 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); /* Step 3: read file parameters with jpeg_read_header() */ (void) 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 */ /* In this example, we don't need to change any of the defaults set by * jpeg_read_header(), so we do nothing here. */ /* Step 5: Start decompressor */ (void) 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 */ 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. */ int jpeg_w = (int)cinfo.output_width; int jpeg_h = (int)cinfo.output_height; unsigned char *jpeg_buffer = new unsigned char [jpeg_w * jpeg_h * row_stride]; memset(jpeg_buffer, 0, jpeg_w * jpeg_h * row_stride); 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. */ (void) jpeg_read_scanlines(&cinfo, buffer, 1); /* Assume put_scanline_someplace wants a pointer and sample count. */ // put_scanline_someplace(buffer[0], row_stride); memcpy(jpeg_buffer+(((int)cinfo.output_scanline-1)*jpeg_w*3), buffer[0], row_stride); } /* 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. */ /* 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...) */ fclose(infile); /* At this point you may want to check to see whether any corrupt-data * warnings occurred (test whether jerr.pub.num_warnings is nonzero). */ //int texture_id = GraphicAPI->UploadBitsToGPU(jpeg_w, jpeg_h, 24, jpeg_buffer, params); int k; if(jpeg_buffer == NULL) { return 0; } if(text_id == -1) { k = 1; //0 while(TextureList[k].used) { if(!strncmp(TextureList[k].name,Name,strlen(Name))) { m_ConsPrint("Already loaded ! (id:%d)\n",TextureList[k].id); return TextureList[k].id; } k++; if(k >= TEXTURELOADED) break; } } else { k = text_id; } if(k >= TEXTURELOADED) { m_ConsPrint("too much loaded texture. max : %d", TEXTURELOADED); s_free(jpeg_buffer); //delete [] jpeg_buffer; return -1; } TextureList[k].used = true; TextureList[k].type = TEX_JPG; TextureList[k].map_tex = map_tex; TextureList[k].id = k; strcpy(TextureList[k].name,Name); TextureList[k].picmip_locked = -1; gl_LoadSurfaceTexture(jpeg_buffer, GL_UNSIGNED_BYTE, GL_RGB, GL_RGB, jpeg_w, jpeg_h, k); //s_free(jpeg_buffer); return k; }
int64_t GetImageMetadata(const char *path, char *name) { ExifData *ed; ExifEntry *e = NULL; ExifLoader *l; struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; FILE *infile; int width=0, height=0, thumb=0; char make[32], model[64] = {'\0'}; char b[1024]; struct stat file; int64_t ret; image_s *imsrc; metadata_t m; uint32_t free_flags = 0xFFFFFFFF; memset(&m, '\0', sizeof(metadata_t)); //DEBUG DPRINTF(E_DEBUG, L_METADATA, "Parsing %s...\n", path); if ( stat(path, &file) != 0 ) return 0; strip_ext(name); //DEBUG DPRINTF(E_DEBUG, L_METADATA, " * size: %jd\n", file.st_size); /* MIME hard-coded to JPEG for now, until we add PNG support */ m.mime = strdup("image/jpeg"); l = exif_loader_new(); exif_loader_write_file(l, path); ed = exif_loader_get_data(l); exif_loader_unref(l); if( !ed ) goto no_exifdata; e = exif_content_get_entry (ed->ifd[EXIF_IFD_EXIF], EXIF_TAG_DATE_TIME_ORIGINAL); if( e || (e = exif_content_get_entry(ed->ifd[EXIF_IFD_EXIF], EXIF_TAG_DATE_TIME_DIGITIZED)) ) { m.date = strdup(exif_entry_get_value(e, b, sizeof(b))); if( strlen(m.date) > 10 ) { m.date[4] = '-'; m.date[7] = '-'; m.date[10] = 'T'; } else { free(m.date); m.date = NULL; } } else { /* One last effort to get the date from XMP */ image_get_jpeg_date_xmp(path, &m.date); } //DEBUG DPRINTF(E_DEBUG, L_METADATA, " * date: %s\n", m.date); e = exif_content_get_entry(ed->ifd[EXIF_IFD_0], EXIF_TAG_MAKE); if( e ) { strncpyt(make, exif_entry_get_value(e, b, sizeof(b)), sizeof(make)); e = exif_content_get_entry(ed->ifd[EXIF_IFD_0], EXIF_TAG_MODEL); if( e ) { strncpyt(model, exif_entry_get_value(e, b, sizeof(b)), sizeof(model)); if( !strcasestr(model, make) ) snprintf(model, sizeof(model), "%s %s", make, exif_entry_get_value(e, b, sizeof(b))); m.creator = escape_tag(trim(model), 1); } } //DEBUG DPRINTF(E_DEBUG, L_METADATA, " * model: %s\n", model); e = exif_content_get_entry(ed->ifd[EXIF_IFD_0], EXIF_TAG_ORIENTATION); if( e ) { int rotate; switch( exif_get_short(e->data, exif_data_get_byte_order(ed)) ) { case 3: rotate = 180; break; case 6: rotate = 90; break; case 8: rotate = 270; break; default: rotate = 0; break; } if( rotate ) xasprintf(&m.rotation, "%d", rotate); } if( ed->size ) { /* We might need to verify that the thumbnail is 160x160 or smaller */ if( ed->size > 12000 ) { imsrc = image_new_from_jpeg(NULL, 0, (char *)ed->data, ed->size, 1, ROTATE_NONE); if( imsrc ) { if( (imsrc->width <= 160) && (imsrc->height <= 160) ) thumb = 1; image_free(imsrc); } } else thumb = 1; } //DEBUG DPRINTF(E_DEBUG, L_METADATA, " * thumbnail: %d\n", thumb); exif_data_unref(ed); no_exifdata: /* If SOF parsing fails, then fall through to reading the JPEG data with libjpeg to get the resolution */ if( image_get_jpeg_resolution(path, &width, &height) != 0 || !width || !height ) { infile = fopen(path, "r"); if( infile ) { cinfo.err = jpeg_std_error(&jerr); jerr.error_exit = libjpeg_error_handler; jpeg_create_decompress(&cinfo); if( setjmp(setjmp_buffer) ) goto error; jpeg_stdio_src(&cinfo, infile); jpeg_read_header(&cinfo, TRUE); jpeg_start_decompress(&cinfo); width = cinfo.output_width; height = cinfo.output_height; error: jpeg_destroy_decompress(&cinfo); fclose(infile); } } //DEBUG DPRINTF(E_DEBUG, L_METADATA, " * resolution: %dx%d\n", width, height); if( !width || !height ) { free_metadata(&m, free_flags); return 0; } if( width <= 640 && height <= 480 ) m.dlna_pn = strdup("JPEG_SM"); else if( width <= 1024 && height <= 768 ) m.dlna_pn = strdup("JPEG_MED"); else if( (width <= 4096 && height <= 4096) || !GETFLAG(DLNA_STRICT_MASK) ) m.dlna_pn = strdup("JPEG_LRG"); xasprintf(&m.resolution, "%dx%d", width, height); ret = sql_exec(db, "INSERT into DETAILS" " (PATH, TITLE, SIZE, TIMESTAMP, DATE, RESOLUTION," " ROTATION, THUMBNAIL, CREATOR, DLNA_PN, MIME) " "VALUES" " (%Q, '%q', %lld, %ld, %Q, %Q, %Q, %d, %Q, %Q, %Q);", path, name, (long long)file.st_size, file.st_mtime, m.date, m.resolution, m.rotation, thumb, m.creator, m.dlna_pn, m.mime); if( ret != SQLITE_OK ) { fprintf(stderr, "Error inserting details for '%s'!\n", path); ret = 0; } else { ret = sqlite3_last_insert_rowid(db); } free_metadata(&m, free_flags); return ret; }
int read_jpeg_file( char *filename ) { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPROW row_pointer[1]; FILE *infile = fopen( filename, "rb" ); unsigned long location = 0; long long j=0, i = 0; if ( !infile ) { printf("Error opening jpeg file %s\n!", filename ); return -1; } cinfo.err = jpeg_std_error( &jerr ); jpeg_create_decompress( &cinfo ); jpeg_stdio_src( &cinfo, infile ); jpeg_read_header( &cinfo, TRUE ); jpeg_start_decompress( &cinfo ); width=cinfo.image_width; height=cinfo.image_height; bytes_per_pixel=cinfo.num_components; printf("components = %d\n", cinfo.num_components); raw_image = (unsigned char*)malloc( cinfo.output_width*cinfo.output_height*cinfo.num_components ); raw_image2 = (unsigned char*)malloc( cinfo.output_width*cinfo.output_height*cinfo.num_components ); unsigned char **img = (unsigned char **)malloc(height * sizeof(unsigned char *)); for (i=0; i<height; i++) img[i] = (unsigned char *)malloc(width*bytes_per_pixel * sizeof(unsigned char )); unsigned char **oimg = (unsigned char **)malloc(height * sizeof(unsigned char *)); for (i=0; i<height; i++) oimg[i] = (unsigned char *)malloc(width*bytes_per_pixel * sizeof(unsigned char )); row_pointer[0] = (unsigned char *)malloc( cinfo.output_width*cinfo.num_components ); while( cinfo.output_scanline < cinfo.image_height ) { jpeg_read_scanlines( &cinfo, row_pointer, 1 ); for( i=0; i<cinfo.image_width*cinfo.num_components;i++) raw_image[location++] = row_pointer[0][i]; } location=0; for(i=0;i<height;i++) for(j=0;j<width*bytes_per_pixel;j++) { img[i][j]=raw_image[location++]; } for(i=0;i<height;i++) for(j=0;j<width*bytes_per_pixel;j++) { int sumfs=0,sumft=0; for(p=0;p<fno;p++) for(q=0;q<fno;q++) { if(i+p<=height-fno+1&&j+q<=width*bytes_per_pixel-fno+1) { sumfs+=img[i+p][j+q]*lt[0+p][0+q]; } } if(abs(sumfs/dlt)<=255&&abs(sumfs/dlt)>=0) oimg[i][j]=abs(sumfs/dlt); else { if(abs(sumfs/dlt)>255) oimg[i][j]=(char)255; else oimg[i][j]=(char)0; } } location=0; for(i=0;i<height;i++) for(j=0;j<width*bytes_per_pixel;j++) { raw_image2[location++]=oimg[i][j]; } jpeg_finish_decompress( &cinfo ); jpeg_destroy_decompress( &cinfo ); free( row_pointer[0] ); fclose( infile ); return 1; }
SbBool ReadJPEGImage(const SoInput& in, int &w, int &h, int &nc, unsigned char *&bytes) { /* 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. */ struct my_error_mgr jerr; /* More stuff */ FILE * infile; /* source file */ JSAMPARRAY buffer; /* Output row buffer */ int row_stride; /* physical row width in output buffer */ infile = in.getCurFile(); fseek(infile, 0, SEEK_SET); /* 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 = my_error_exit; /* 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 FALSE; } /* 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); /* Step 3: read file parameters with jpeg_read_header() */ jpeg_read_header(&cinfo, TRUE); /* Step 5: Start decompressor */ jpeg_start_decompress(&cinfo); // make buffer for data to be put into w = cinfo.output_width; h = cinfo.output_height; nc = cinfo.output_components; bytes = new unsigned char[w*h*nc]; row_stride = w*nc; /* 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); unsigned char *curline = bytes+(h-1)*w*nc; while (cinfo.output_scanline < cinfo.output_height) { jpeg_read_scanlines(&cinfo, buffer, 1); // put the data from the sample buffer into the output buffer for (int i = 0; i < row_stride; ++i) curline[i] = (unsigned char) (buffer[0][i]); curline -= w*nc; } /* Step 7: Finish decompression */ jpeg_finish_decompress(&cinfo); /* 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). */ return TRUE; }
bool ImageGrayScale::image2GrayScaleJPEG(const QString& src, const QString& dest, QString& err, bool updateFileTimeStamp) { JCOPY_OPTION copyoption = JCOPYOPT_ALL; jpeg_transform_info transformoption; transformoption.transform = JXFORM_NONE; transformoption.force_grayscale = true; transformoption.trim = false; struct jpeg_decompress_struct srcinfo; struct jpeg_compress_struct dstinfo; struct jpeg_error_mgr jsrcerr; struct jpeg_error_mgr jdsterr; jvirt_barray_ptr * src_coef_arrays; jvirt_barray_ptr * dst_coef_arrays; // 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); FILE *input_file; FILE *output_file; input_file = fopen(QFile::encodeName(src), "rb"); if (!input_file) { kError( 51000 ) << "Image2GrayScale: Error in opening input file" << endl; err = i18n("Error in opening input file"); return false; } output_file = fopen(QFile::encodeName(dest), "wb"); if (!output_file) { fclose(input_file); kError( 51000 ) << "Image2GrayScale: Error in opening output file" << endl; err = i18n("Error in opening output file"); return false; } // Open jpeglib stream jpeg_stdio_src(&srcinfo, input_file); // Setup decompression object to save desired markers in memory jcopy_markers_setup(&srcinfo, copyoption); // Decompression startup: read start of JPEG datastream to see what's there (void) jpeg_read_header(&srcinfo, true); // Request any required workspace jtransform_request_workspace(&srcinfo, &transformoption); // 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 output image parameters dst_coef_arrays = jtransform_adjust_parameters(&srcinfo, &dstinfo, src_coef_arrays, &transformoption); // Specify data destination for compression jpeg_stdio_dest(&dstinfo, output_file); // Do not write a JFIF header if previously the image did not contain it dstinfo.write_JFIF_header = false; // 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 (merging from src file with Qt tmp file) jcopy_markers_execute(&srcinfo, &dstinfo, copyoption); // Execute the actual jpeg transformations jtransform_execute_transformation(&srcinfo, &dstinfo, src_coef_arrays, &transformoption); // Finish compression and release memory jpeg_finish_compress(&dstinfo); jpeg_destroy_compress(&dstinfo); (void) jpeg_finish_decompress(&srcinfo); jpeg_destroy_decompress(&srcinfo); fclose(input_file); fclose(output_file); // And set finaly update the metadata to target file. KExiv2Iface::KExiv2 exiv2Iface; #if KEXIV2_VERSION >= 0x000600 exiv2Iface.setUpdateFileTimeStamp(updateFileTimeStamp); #endif exiv2Iface.load(dest); QImage img(dest); QImage exifThumbnail = img.scaled(160, 120, Qt::KeepAspectRatio); exiv2Iface.setImageProgramId(QString("Kipi-plugins"), QString(kipiplugins_version)); exiv2Iface.setExifThumbnail(exifThumbnail); exiv2Iface.save(dest); return true; }
void ImageJPG::ReadJPG(FILE * stream, uint8_t *data, unsigned len, int& width, int& height, void*& pixels) { struct jpeg_decompress_struct cinfo; int res; int pitch; JSAMPARRAY buffer; uint8_t* dst; bool from_mem; pixels = NULL; from_mem = (data) ? true : false; jpeg_create_decompress(&cinfo); if (from_mem) { assert(data); jpeg_mem_src(&cinfo, data, len); } else { assert(stream); jpeg_stdio_src(&cinfo, stream); } res = jpeg_read_header(&cinfo, TRUE); if (res != JPEG_HEADER_OK) { Output::Warning("Not a valid JPEG image."); goto clean_exit; } res = jpeg_start_decompress(&cinfo); if (!res) { Output::Warning("Corrupted JPEG image."); goto clean_exit; } width = cinfo.output_width; height = cinfo.output_height; pitch = width * cinfo.output_components; buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, pitch, 1); pixels = malloc(pitch * height); dst = (uint8_t*) pixels; while (cinfo.output_scanline < (unsigned) height) { res = jpeg_read_scanlines(&cinfo, buffer, 1); if (!res) { Output::Warning("Corrupted JPEG image."); goto clean_exit; } memcpy(dst, buffer, pitch); dst += pitch; } res = jpeg_finish_decompress(&cinfo); if (!res) { Output::Warning("Corrupted JPEG image."); goto clean_exit; } clean_exit: jpeg_destroy_decompress(&cinfo); return; }
/* The load_jpeg function is based on Imlib2 loader. */ ngx_int_t ngx_http_small_light_load_jpeg( void **dest_data, int *width, int *height, const ngx_http_request_t *r, const char *filename, int hint_w, int hint_h) { int w, h; struct jpeg_decompress_struct cinfo; struct ImLib_JPEG_error_mgr jerr; FILE *f; ngx_int_t fd; int denom; DATA8 *ptr, *line[16], *data; DATA32 *ptr2, *dest; int x, y, l, i, scans; *dest_data = NULL; *width = *height = 0; fd = ngx_open_file(filename, NGX_FILE_RDONLY, NGX_FILE_OPEN, NGX_FILE_DEFAULT_ACCESS); if (fd == NGX_INVALID_FILE) { return NGX_ERROR; } f = fdopen(fd, "rb"); cinfo.err = jpeg_std_error(&(jerr.pub)); jerr.pub.error_exit = _JPEGFatalErrorHandler; jerr.pub.emit_message = _JPEGErrorHandler2; jerr.pub.output_message = _JPEGErrorHandler; if (sigsetjmp(jerr.setjmp_buffer, 1)) { jpeg_destroy_decompress(&cinfo); ngx_close_file(fd); fclose(f); return NGX_ERROR; } jpeg_create_decompress(&cinfo); jpeg_stdio_src(&cinfo, f); jpeg_read_header(&cinfo, TRUE); cinfo.do_fancy_upsampling = FALSE; cinfo.do_block_smoothing = FALSE; jpeg_start_decompress(&cinfo); w = cinfo.output_width; h = cinfo.output_height; denom = w / hint_w; if (denom > h / hint_h) { denom = h / hint_h; } denom = denom >= 1 ? denom : 1; denom = denom <= 8 ? denom : 8; jpeg_destroy_decompress(&cinfo); fseek(f, 0, SEEK_SET); jpeg_create_decompress(&cinfo); jpeg_stdio_src(&cinfo, f); jpeg_read_header(&cinfo, TRUE); cinfo.do_fancy_upsampling = FALSE; cinfo.do_block_smoothing = FALSE; cinfo.scale_denom = denom; jpeg_start_decompress(&cinfo); w = cinfo.output_width; h = cinfo.output_height; if ((cinfo.rec_outbuf_height > 16) || (cinfo.output_components <= 0) || !IMAGE_DIMENSIONS_OK(w, h)) { jpeg_destroy_decompress(&cinfo); ngx_close_file(fd); fclose(f); return NGX_ERROR; } data = ngx_palloc(r->pool, w * 16 * cinfo.output_components); if (!data) { jpeg_destroy_decompress(&cinfo); ngx_close_file(fd); fclose(f); return NGX_ERROR; } /* must set the im->data member before callign progress function */ ptr2 = dest = ngx_palloc(r->pool, w * h * sizeof(DATA32)); if (!dest) { jpeg_destroy_decompress(&cinfo); ngx_close_file(fd); fclose(f); return NGX_ERROR; } if (cinfo.output_components > 1) { for (i = 0; i < cinfo.rec_outbuf_height; i++) { line[i] = data + (i * w * cinfo.output_components); } for (l = 0; l < h; l += cinfo.rec_outbuf_height) { jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height); scans = cinfo.rec_outbuf_height; if ((h - l) < scans) { scans = h - l; } ptr = data; for (y = 0; y < scans; y++) { for (x = 0; x < w; x++) { *ptr2 = (0xff000000) | ((ptr[0]) << 16) | ((ptr[1]) << 8) | (ptr[2]); ptr += cinfo.output_components; ptr2++; } } } } else if (cinfo.output_components == 1) { for (i = 0; i < cinfo.rec_outbuf_height; i++) { line[i] = data + (i * w); } for (l = 0; l < h; l += cinfo.rec_outbuf_height) { jpeg_read_scanlines(&cinfo, line, cinfo.rec_outbuf_height); scans = cinfo.rec_outbuf_height; if ((h - l) < scans) { scans = h - l; } ptr = data; for (y = 0; y < scans; y++) { for (x = 0; x < w; x++) { *ptr2 = (0xff000000) | ((ptr[0]) << 16) | ((ptr[0]) << 8) | (ptr[0]); ptr++; ptr2++; } } } } jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); ngx_close_file(fd); fclose(f); *dest_data = dest; *width = w; *height = h; return NGX_OK; }
int read_jpeg(const char *filename, uint8_t **memptr, size_t *memsize, int *naxis, int *w, int *h ) { int row; unsigned char *r_data = NULL, *g_data, *b_data; /* these are standard libjpeg structures for reading(decompression) */ struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; /* libjpeg data structure for storing one row, that is, scanline of an image */ JSAMPROW row_pointer[1] = {NULL}; FILE *infile = fopen( filename, "rb" ); int i = 0; if ( !infile ) { DEBUGFDEVICE(device, INDI::Logger::DBG_DEBUG, "Error opening jpeg file %s!", filename ); return -1; } /* here we set up the standard libjpeg error handler */ cinfo.err = jpeg_std_error( &jerr ); /* setup decompression process and source, then read JPEG header */ jpeg_create_decompress( &cinfo ); /* this makes the library read from infile */ jpeg_stdio_src( &cinfo, infile ); /* reading the image header which contains image information */ jpeg_read_header( &cinfo, TRUE ); /* Start decompression jpeg here */ jpeg_start_decompress( &cinfo ); *memsize = cinfo.output_width * cinfo.output_height * cinfo.num_components; *memptr = (uint8_t *) realloc(*memptr, *memsize); uint8_t *oldmem = *memptr; // if you do some ugly pointer math, remember to restore the original pointer or some random crashes will happen. This is why I do not like pointers!! *naxis = cinfo.num_components; *w = cinfo.output_width; *h = cinfo.output_height; /* now actually read the jpeg into the raw buffer */ row_pointer[0] = (unsigned char *)malloc( cinfo.output_width*cinfo.num_components ); if (cinfo.num_components) { r_data = (unsigned char *) *memptr; g_data = r_data + cinfo.output_width * cinfo.output_height; b_data = r_data + 2 * cinfo.output_width * cinfo.output_height; } /* read one scan line at a time */ for (row = 0; row < cinfo.image_height; row++) { unsigned char *ppm8 = row_pointer[0]; jpeg_read_scanlines( &cinfo, row_pointer, 1 ); if (cinfo.num_components == 3) { for (i = 0; i < cinfo.output_width; i++) { *r_data++ = *ppm8++; *g_data++ = *ppm8++; *b_data++ = *ppm8++; } } else { memcpy(*memptr, ppm8, cinfo.output_width); *memptr += cinfo.output_width; } } /* wrap up decompression, destroy objects, free pointers and close open files */ jpeg_finish_decompress( &cinfo ); jpeg_destroy_decompress( &cinfo ); if (row_pointer[0] ) free( row_pointer[0] ); if(infile) fclose( infile ); *memptr = oldmem; return 0; }
CSize InformApp::GetImageSize(const char* path) { CSize size(0,0); // Check if it's a PNG file CStdioFile imageFile; if (!imageFile.Open(path,CFile::modeRead|CFile::typeBinary)) return size; png_byte fileHeader[8]; imageFile.Read(fileHeader,8); bool isPNG = (png_sig_cmp(fileHeader,0,8) == 0); if (isPNG) { png_structp png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING,(png_voidp)NULL,NULL,NULL); if (png_ptr == NULL) return size; png_infop info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_read_struct(&png_ptr,(png_infopp)NULL,(png_infopp)NULL); return size; } png_infop end_info = png_create_info_struct(png_ptr); if (end_info == NULL) { png_destroy_read_struct(&png_ptr,&info_ptr,(png_infopp)NULL); return size; } if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr,&info_ptr,&end_info); return size; } png_init_io(png_ptr,imageFile.m_pStream); png_set_sig_bytes(png_ptr,8); png_read_info(png_ptr,info_ptr); size.cx = png_get_image_width(png_ptr,info_ptr); size.cy = png_get_image_height(png_ptr,info_ptr); png_destroy_read_struct(&png_ptr,&info_ptr,&end_info); return size; } else { imageFile.SeekToBegin(); struct jpeg_decompress_struct info; struct JPEGErrorInfo error; info.err = jpeg_std_error(&(error.base)); error.base.error_exit = errorJPEGExit; error.base.output_message = outputJPEGMessage; if (setjmp(error.errorJump)) { jpeg_destroy_decompress(&info); return size; } jpeg_create_decompress(&info); jpeg_stdio_src(&info,imageFile.m_pStream); jpeg_read_header(&info,TRUE); jpeg_calc_output_dimensions(&info); size.cx = info.output_width; size.cy = info.output_height; jpeg_destroy_decompress(&info); return size; } }
int main (int argc, char **argv) { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; #ifdef PROGRESS_REPORT struct cdjpeg_progress_mgr progress; #endif int file_index; djpeg_dest_ptr dest_mgr = NULL; FILE * input_file; FILE * output_file; unsigned char *inbuffer = NULL; unsigned long insize = 0; JDIMENSION num_scanlines; /* On Mac, fetch a command line. */ #ifdef USE_CCOMMAND argc = ccommand(&argv); #endif progname = argv[0]; if (progname == NULL || progname[0] == 0) progname = "djpeg"; /* in case C library doesn't provide it */ /* Initialize the JPEG decompression object with default error handling. */ cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); /* Add some application-specific error messages (from cderror.h) */ jerr.addon_message_table = cdjpeg_message_table; jerr.first_addon_message = JMSG_FIRSTADDONCODE; jerr.last_addon_message = JMSG_LASTADDONCODE; /* Insert custom marker processor for COM and APP12. * APP12 is used by some digital camera makers for textual info, * so we provide the ability to display it as text. * If you like, additional APPn marker types can be selected for display, * but don't try to override APP0 or APP14 this way (see libjpeg.txt). */ jpeg_set_marker_processor(&cinfo, JPEG_COM, print_text_marker); jpeg_set_marker_processor(&cinfo, JPEG_APP0+12, print_text_marker); /* Now safe to enable signal catcher. */ #ifdef NEED_SIGNAL_CATCHER enable_signal_catcher((j_common_ptr) &cinfo); #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 ignored; we will rescan the switches after opening * the input file. * (Exception: tracing level set here controls verbosity for COM markers * found during jpeg_read_header...) */ file_index = parse_switches(&cinfo, argc, argv, 0, FALSE); #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) &cinfo, &progress); #endif /* Specify data source for decompression */ #if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED) if (memsrc) { size_t nbytes; do { inbuffer = (unsigned char *)realloc(inbuffer, insize + INPUT_BUF_SIZE); if (inbuffer == NULL) { fprintf(stderr, "%s: memory allocation failure\n", progname); exit(EXIT_FAILURE); } nbytes = JFREAD(input_file, &inbuffer[insize], INPUT_BUF_SIZE); if (nbytes < INPUT_BUF_SIZE && ferror(input_file)) { if (file_index < argc) fprintf(stderr, "%s: can't read from %s\n", progname, argv[file_index]); else fprintf(stderr, "%s: can't read from stdin\n", progname); } insize += (unsigned long)nbytes; } while (nbytes == INPUT_BUF_SIZE); fprintf(stderr, "Compressed size: %lu bytes\n", insize); jpeg_mem_src(&cinfo, inbuffer, insize); } else #endif jpeg_stdio_src(&cinfo, input_file); /* Read file header, set default decompression parameters */ (void) jpeg_read_header(&cinfo, TRUE); /* Adjust default decompression parameters by re-parsing the options */ file_index = parse_switches(&cinfo, argc, argv, 0, TRUE); /* Initialize the output module now to let it override any crucial * option settings (for instance, GIF wants to force color quantization). */ switch (requested_fmt) { #ifdef BMP_SUPPORTED case FMT_BMP: dest_mgr = jinit_write_bmp(&cinfo, FALSE); break; case FMT_OS2: dest_mgr = jinit_write_bmp(&cinfo, TRUE); break; #endif #ifdef GIF_SUPPORTED case FMT_GIF: dest_mgr = jinit_write_gif(&cinfo); break; #endif #ifdef PPM_SUPPORTED case FMT_PPM: dest_mgr = jinit_write_ppm(&cinfo); break; #endif #ifdef RLE_SUPPORTED case FMT_RLE: dest_mgr = jinit_write_rle(&cinfo); break; #endif #ifdef TARGA_SUPPORTED case FMT_TARGA: dest_mgr = jinit_write_targa(&cinfo); break; #endif default: ERREXIT(&cinfo, JERR_UNSUPPORTED_FORMAT); break; } dest_mgr->output_file = output_file; /* Start decompressor */ (void) jpeg_start_decompress(&cinfo); /* Strip decode */ if (strip || skip) { JDIMENSION tmp; /* Check for valid endY. We cannot check this value until after * jpeg_start_decompress() is called. Note that we have already verified * that startY <= endY. */ if (endY > cinfo.output_height - 1) { fprintf(stderr, "%s: strip %d-%d exceeds image height %d\n", progname, startY, endY, cinfo.output_height); exit(EXIT_FAILURE); } /* Write output file header. This is a hack to ensure that the destination * manager creates an image of the proper size for the partial decode. */ tmp = cinfo.output_height; cinfo.output_height = endY - startY + 1; if (skip) cinfo.output_height = tmp - cinfo.output_height; (*dest_mgr->start_output) (&cinfo, dest_mgr); cinfo.output_height = tmp; /* Process data */ if (skip) { while (cinfo.output_scanline < startY) { num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer, dest_mgr->buffer_height); (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); } jpeg_skip_scanlines(&cinfo, endY - startY + 1); while (cinfo.output_scanline < cinfo.output_height) { num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer, dest_mgr->buffer_height); (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); } } else { jpeg_skip_scanlines(&cinfo, startY); while (cinfo.output_scanline <= endY) { num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer, dest_mgr->buffer_height); (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); } jpeg_skip_scanlines(&cinfo, cinfo.output_height - endY + 1); } /* Normal full image decode */ } else { /* Write output file header */ (*dest_mgr->start_output) (&cinfo, dest_mgr); /* Process data */ while (cinfo.output_scanline < cinfo.output_height) { num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer, dest_mgr->buffer_height); (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); } } #ifdef PROGRESS_REPORT /* Hack: count final pass as done in case finish_output does an extra pass. * The library won't have updated completed_passes. */ progress.pub.completed_passes = progress.pub.total_passes; #endif /* Finish decompression and release memory. * I must do it in this order because output module has allocated memory * of lifespan JPOOL_IMAGE; it needs to finish before releasing memory. */ (*dest_mgr->finish_output) (&cinfo, dest_mgr); (void) jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); /* 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) &cinfo); #endif if (memsrc && inbuffer != NULL) free(inbuffer); /* All done. */ exit(jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS); return 0; /* suppress no-return-value warnings */ }
bool JPEG::Decode (Resource *resource, ImageBuffer* imageBuffer, bool decodeData) { struct jpeg_decompress_struct cinfo; //struct jpeg_error_mgr jerr; //cinfo.err = jpeg_std_error (&jerr); struct ErrorData jpegError; cinfo.err = jpeg_std_error (&jpegError.base); jpegError.base.error_exit = OnError; jpegError.base.output_message = OnOutput; FILE_HANDLE *file = NULL; if (resource->path) { file = lime::fopen (resource->path, "rb"); if (!file) { return false; } } if (setjmp (jpegError.on_error)) { if (file) { lime::fclose (file); } jpeg_destroy_decompress (&cinfo); return false; } jpeg_create_decompress (&cinfo); if (file) { if (file->isFile ()) { jpeg_stdio_src (&cinfo, file->getFile ()); } else { Bytes data = Bytes (resource->path); MySrcManager manager (data.Data (), data.Length ()); cinfo.src = &manager.pub; } } else { MySrcManager manager (resource->data->Data (), resource->data->Length ()); cinfo.src = &manager.pub; } bool decoded = false; if (jpeg_read_header (&cinfo, TRUE) == JPEG_HEADER_OK) { cinfo.out_color_space = JCS_RGB; if (decodeData) { jpeg_start_decompress (&cinfo); int components = cinfo.output_components; imageBuffer->Resize (cinfo.output_width, cinfo.output_height, 32); unsigned char *bytes = imageBuffer->data->Data (); unsigned char *scanline = new unsigned char [imageBuffer->width * imageBuffer->height * components]; while (cinfo.output_scanline < cinfo.output_height) { jpeg_read_scanlines (&cinfo, &scanline, 1); // convert 24-bit scanline to 32-bit const unsigned char *line = scanline; const unsigned char *const end = line + imageBuffer->width * components; while (line != end) { *bytes++ = *line++; *bytes++ = *line++; *bytes++ = *line++; *bytes++ = 0xFF; } } delete[] scanline; jpeg_finish_decompress (&cinfo); } else { imageBuffer->width = cinfo.image_width; imageBuffer->height = cinfo.image_height; } decoded = true; } if (file) { lime::fclose (file); } jpeg_destroy_decompress (&cinfo); return decoded; }
gl_texture_t * ReadJPEGFromFile (const char *filename) { gl_texture_t *texinfo = NULL; FILE *fp = NULL; struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPROW j; int i; /* open image file */ fp = fopen (filename, "rb"); if (!fp) { fprintf (stderr, "error: couldn't open \"%s\"!\n", filename); return NULL; } /* create and configure decompressor */ jpeg_create_decompress (&cinfo); cinfo.err = jpeg_std_error (&jerr); jpeg_stdio_src (&cinfo, fp); /* * NOTE: this is the simplest "readJpegFile" function. There * is no advanced error handling. It would be a good idea to * setup an error manager with a setjmp/longjmp mechanism. * In this function, if an error occurs during reading the JPEG * file, the libjpeg abords the program. * See jpeg_mem.c (or RTFM) for an advanced error handling which * prevent this kind of behavior (http://tfc.duke.free.fr) */ /* read header and prepare for decompression */ jpeg_read_header (&cinfo, TRUE); jpeg_start_decompress (&cinfo); /* initialize image's member variables */ texinfo = (gl_texture_t *)malloc (sizeof (gl_texture_t)); texinfo->width = cinfo.image_width; texinfo->height = cinfo.image_height; texinfo->internalFormat = cinfo.num_components; if (cinfo.num_components == 1) texinfo->format = GL_LUMINANCE; else texinfo->format = GL_RGB; texinfo->texels = (GLubyte *)malloc (sizeof (GLubyte) * texinfo->width * texinfo->height * texinfo->internalFormat); /* extract each scanline of the image */ for (i = 0; i < texinfo->height; ++i) { j = (texinfo->texels + ((texinfo->height - (i + 1)) * texinfo->width * texinfo->internalFormat)); jpeg_read_scanlines (&cinfo, &j, 1); } /* finish decompression and release memory */ jpeg_finish_decompress (&cinfo); jpeg_destroy_decompress (&cinfo); fclose (fp); return texinfo; }
bool Image::LoadJpeg(const char *filename) { // Get access to error log system::ErrorLogStream * error_log = system::ErrorLogStream::GetInstance(); /* 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. * Note that this struct must live as long as the main JPEG parameter * struct, to avoid dangling-pointer problems. */ jpegErrorManager jerr; /* More stuff */ sht::system::FileStream stream; unsigned char * rowptr[1]; int 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. */ if (!stream.Open(filename, sht::system::StreamAccess::kReadBinary)) { error_log->PrintString("can't open %s\n", filename); return false; } /* 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 = jpegErrorExit; /* 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. */ jpeg_destroy_decompress(&cinfo); stream.Close(); return false; } /* Now we can initialize the JPEG decompression object. */ jpeg_create_decompress(&cinfo); /* Step 2: specify data source (eg, a file) */ jpeg_stdio_src(&cinfo, stream.GetFilePointer()); /* Step 3: read file parameters with jpeg_read_header() */ (void)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.txt for more info. */ /* Step 4: set parameters for decompression */ /* In this example, we don't need to change any of the defaults set by * jpeg_read_header(), so we do nothing here. */ /* Step 5: Start decompressor */ (void)jpeg_start_decompress(&cinfo); /* We can ignore the return value since suspension is not possible * with the stdio data source. */ width_ = cinfo.output_width; height_ = cinfo.output_height; channels_ = cinfo.num_components; data_type_ = DataType::kUint8; switch (channels_) { case 4: bpp_ = 4; format_ = Format::kRGBA8; break; case 3: bpp_ = 3; format_ = Format::kRGB8; break; case 2: bpp_ = 2; format_ = Format::kRG8; break; case 1: bpp_ = 1; format_ = Format::kR8; break; default: assert(!"Implement this case"); break; } pixels_ = new u8[width_ * height_ * bpp_]; /* 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 */ row_stride = cinfo.output_width * cinfo.output_components; /* 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) { if (inverted_row_order_) { int row_number = cinfo.output_height - 1 - cinfo.output_scanline; rowptr[0] = pixels_ + row_stride * row_number; } else // normal row order rowptr[0] = pixels_ + row_stride * cinfo.output_scanline; /* 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. */ (void)jpeg_read_scanlines(&cinfo, rowptr, 1); } /* 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. */ /* 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...) */ stream.Close(); /* At this point you may want to check to see whether any corrupt-data * warnings occurred (test whether jerr.pub.num_warnings is nonzero). */ return true; }
JpegParser::Impl::Impl(const char* filename) { #ifndef INVT_HAVE_LIBJPEG LFATAL("jpeg support is disabled since libjpeg was not found at configure time"); #else GVX_TRACE(__PRETTY_FUNCTION__); if (BITS_IN_JSAMPLE != 8) { throw rutz::error("jpeg library must be built for 8 bits-per-sample", SRC_POS); } jmp_buf state; // 1. Allocate and initialize the JPEG decompression object jpeg_decompress_struct cinfo; jpeg_error_mgr jerr; jpeg_aux aux; aux.infile = 0; aux.jmp_state = &state; cinfo.client_data = static_cast<void*>(&aux); cinfo.err = jpeg_std_error(&jerr); cinfo.err->error_exit = &jpeg_error_exit; SETJMP_TRY(jpeg_create_decompress(&cinfo)); // 2. Specify the source of the compressed data (i.e., the input file) aux.infile = fopen(filename, "rb"); if (aux.infile == 0) { throw rutz::error(rutz::sfmt("couldn't open '%s' for reading", filename), SRC_POS); } SETJMP_TRY(jpeg_stdio_src(&cinfo, aux.infile)); // 3. Call jpeg_read_header() to obtain image info SETJMP_TRY(jpeg_read_header(&cinfo, TRUE)); // 4. Set parameters for decompression // 5. Start decompression SETJMP_TRY(jpeg_start_decompress(&cinfo)); // cinfo.output_width // cinfo.output_height // cinfo.out_color_components // cinfo.output_components // 6. Read scanlines switch (cinfo.output_components) { case 1: { this->gray = Image<byte>(cinfo.output_width, cinfo.output_height, NO_INIT); while (cinfo.output_scanline < cinfo.output_height) { JSAMPLE* dest = this->gray.getArrayPtr() + cinfo.output_scanline * this->gray.getWidth(); SETJMP_TRY(jpeg_read_scanlines(&cinfo, &dest, /* max lines */ 1)); } } break; case 3: { this->rgb = Image<PixRGB<byte> >(cinfo.output_width, cinfo.output_height, NO_INIT); while (cinfo.output_scanline < cinfo.output_height) { JSAMPLE* dest = reinterpret_cast<JSAMPLE*> (this->rgb.getArrayPtr() + cinfo.output_scanline * this->rgb.getWidth()); SETJMP_TRY(jpeg_read_scanlines(&cinfo, &dest, /* max lines */ 1)); } } break; default: LFATAL("invalid number of jpeg components (%d)", cinfo.output_components); break; } // 7. finish decompression SETJMP_TRY(jpeg_finish_decompress(&cinfo)); // 8. cleanup cleanup(&cinfo); #endif }
gint32 load_thumbnail_image (GFile *file, gint *width, gint *height, GimpImageType *type, GError **error) { gint32 volatile image_ID = -1; struct jpeg_decompress_struct cinfo; struct my_error_mgr jerr; FILE *infile = NULL; gimp_progress_init_printf (_("Opening thumbnail for '%s'"), g_file_get_parse_name (file)); image_ID = gimp_image_metadata_load_thumbnail (file, error); if (image_ID < 1) return -1; cinfo.err = jpeg_std_error (&jerr.pub); jerr.pub.error_exit = my_error_exit; jerr.pub.output_message = my_output_message; if ((infile = g_fopen (g_file_get_path (file), "rb")) == NULL) { g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno), _("Could not open '%s' for reading: %s"), g_file_get_parse_name (file), g_strerror (errno)); if (image_ID != -1) gimp_image_delete (image_ID); return -1; } /* 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); if (image_ID != -1) gimp_image_delete (image_ID); return -1; } /* 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); /* Step 3: read file parameters with jpeg_read_header() */ jpeg_read_header (&cinfo, TRUE); jpeg_start_decompress (&cinfo); *width = cinfo.output_width; *height = cinfo.output_height; switch (cinfo.output_components) { case 1: *type = GIMP_GRAY_IMAGE; break; case 3: *type = GIMP_RGB_IMAGE; break; case 4: if (cinfo.out_color_space == JCS_CMYK) { *type = GIMP_RGB_IMAGE; break; } /*fallthrough*/ default: g_message ("Don't know how to load JPEG images " "with %d color channels, using colorspace %d (%d).", cinfo.output_components, cinfo.out_color_space, cinfo.jpeg_color_space); gimp_image_delete (image_ID); image_ID = -1; break; } /* Step 4: Release JPEG decompression object */ /* This is an important step since it will release a good deal * of memory. */ jpeg_destroy_decompress (&cinfo); fclose (infile); return image_ID; }
int res_create_surface_jpg(const char* name, gr_surface* pSurface) { GGLSurface* surface = NULL; int result = 0; struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; FILE* fp = fopen(name, "rb"); if (fp == NULL) { char resPath[256]; if (gr_get_rotation() % 180 == 0) snprintf(resPath, sizeof(resPath)-1, "/res/portrait/%s", name); else snprintf(resPath, sizeof(resPath)-1, "/res/landscape/%s", name); resPath[sizeof(resPath)-1] = '\0'; fp = fopen(resPath, "rb"); if (fp == NULL) { result = -1; goto exit; } } cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); /* Specify data source for decompression */ jpeg_stdio_src(&cinfo, fp); /* Read file header, set default decompression parameters */ if (jpeg_read_header(&cinfo, TRUE) != JPEG_HEADER_OK) goto exit; /* Start decompressor */ (void) jpeg_start_decompress(&cinfo); size_t width = cinfo.image_width; size_t height = cinfo.image_height; size_t stride = 4 * width; size_t pixelSize = stride * height; surface = malloc(sizeof(GGLSurface) + pixelSize); if (surface == NULL) { result = -8; goto exit; } unsigned char* pData = (unsigned char*) (surface + 1); surface->version = sizeof(GGLSurface); surface->width = width; surface->height = height; surface->stride = width; /* Yes, pixels, not bytes */ surface->data = pData; surface->format = GGL_PIXEL_FORMAT_RGBX_8888; int y; for (y = 0; y < (int) height; ++y) { unsigned char* pRow = pData + y * stride; jpeg_read_scanlines(&cinfo, &pRow, 1); int x; for(x = width - 1; x >= 0; x--) { int sx = x * 3; int dx = x * 4; unsigned char r = pRow[sx]; unsigned char g = pRow[sx + 1]; unsigned char b = pRow[sx + 2]; unsigned char a = 0xff; pRow[dx ] = r; // r pRow[dx + 1] = g; // g pRow[dx + 2] = b; // b pRow[dx + 3] = a; } } *pSurface = (gr_surface) surface; exit: if (fp != NULL) { if (surface) { (void) jpeg_finish_decompress(&cinfo); if (result < 0) { free(surface); } } jpeg_destroy_decompress(&cinfo); fclose(fp); } return result; }
gint32 load_image (const gchar *filename, GimpRunMode runmode, gboolean preview, gboolean *resolution_loaded, GError **error) { gint32 volatile image_ID; gint32 layer_ID; struct jpeg_decompress_struct cinfo; struct my_error_mgr jerr; jpeg_saved_marker_ptr marker; FILE *infile; guchar *buf; guchar **rowbuf; GimpImageBaseType image_type; GimpImageType layer_type; GeglBuffer *buffer = NULL; const Babl *format; gint tile_height; gint scanlines; gint i, start, end; cmsHTRANSFORM cmyk_transform = NULL; /* We set up the normal JPEG error routines. */ cinfo.err = jpeg_std_error (&jerr.pub); jerr.pub.error_exit = my_error_exit; if (!preview) { jerr.pub.output_message = my_output_message; gimp_progress_init_printf (_("Opening '%s'"), gimp_filename_to_utf8 (filename)); } if ((infile = g_fopen (filename, "rb")) == NULL) { g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno), _("Could not open '%s' for reading: %s"), gimp_filename_to_utf8 (filename), g_strerror (errno)); return -1; } image_ID = -1; /* 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); if (infile) fclose (infile); if (image_ID != -1 && !preview) gimp_image_delete (image_ID); if (preview) destroy_preview (); if (buffer) g_object_unref (buffer); return -1; } /* 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); if (! preview) { /* - step 2.1: tell the lib to save the comments */ jpeg_save_markers (&cinfo, JPEG_COM, 0xffff); /* - step 2.2: tell the lib to save APP1 data (Exif or XMP) */ jpeg_save_markers (&cinfo, JPEG_APP0 + 1, 0xffff); /* - step 2.3: tell the lib to save APP2 data (ICC profiles) */ jpeg_save_markers (&cinfo, JPEG_APP0 + 2, 0xffff); } /* Step 3: read file parameters with jpeg_read_header() */ 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 */ /* In this example, we don't need to change any of the defaults set by * jpeg_read_header(), so we do nothing here, except set the DCT * method. */ cinfo.dct_method = JDCT_FLOAT; /* 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. */ /* temporary buffer */ tile_height = gimp_tile_height (); buf = g_new (guchar, tile_height * cinfo.output_width * cinfo.output_components); rowbuf = g_new (guchar *, tile_height); for (i = 0; i < tile_height; i++) rowbuf[i] = buf + cinfo.output_width * cinfo.output_components * i; switch (cinfo.output_components) { case 1: image_type = GIMP_GRAY; layer_type = GIMP_GRAY_IMAGE; break; case 3: image_type = GIMP_RGB; layer_type = GIMP_RGB_IMAGE; break; case 4: if (cinfo.out_color_space == JCS_CMYK) { image_type = GIMP_RGB; layer_type = GIMP_RGB_IMAGE; break; } /*fallthrough*/ default: g_message ("Don't know how to load JPEG images " "with %d color channels, using colorspace %d (%d).", cinfo.output_components, cinfo.out_color_space, cinfo.jpeg_color_space); return -1; break; } if (preview) { image_ID = preview_image_ID; } else { image_ID = gimp_image_new_with_precision (cinfo.output_width, cinfo.output_height, image_type, GIMP_PRECISION_U8_GAMMA); gimp_image_undo_disable (image_ID); gimp_image_set_filename (image_ID, filename); } if (preview) { preview_layer_ID = gimp_layer_new (preview_image_ID, _("JPEG preview"), cinfo.output_width, cinfo.output_height, layer_type, 100, GIMP_NORMAL_MODE); layer_ID = preview_layer_ID; } else { layer_ID = gimp_layer_new (image_ID, _("Background"), cinfo.output_width, cinfo.output_height, layer_type, 100, GIMP_NORMAL_MODE); } if (! preview) { GString *comment_buffer = NULL; guint8 *profile = NULL; guint profile_size = 0; /* Step 5.0: save the original JPEG settings in a parasite */ jpeg_detect_original_settings (&cinfo, image_ID); /* Step 5.1: check for comments, or Exif metadata in APP1 markers */ for (marker = cinfo.marker_list; marker; marker = marker->next) { const gchar *data = (const gchar *) marker->data; gsize len = marker->data_length; if (marker->marker == JPEG_COM) { #ifdef GIMP_UNSTABLE g_print ("jpeg-load: found image comment (%d bytes)\n", marker->data_length); #endif if (! comment_buffer) { comment_buffer = g_string_new_len (data, len); } else { /* concatenate multiple comments, separate them with LF */ g_string_append_c (comment_buffer, '\n'); g_string_append_len (comment_buffer, data, len); } } else if ((marker->marker == JPEG_APP0 + 1) && (len > sizeof (JPEG_APP_HEADER_EXIF) + 8) && ! strcmp (JPEG_APP_HEADER_EXIF, data)) { #ifdef GIMP_UNSTABLE g_print ("jpeg-load: found Exif block (%d bytes)\n", (gint) (len - sizeof (JPEG_APP_HEADER_EXIF))); #endif } } if (jpeg_load_resolution (image_ID, &cinfo)) { if (resolution_loaded) *resolution_loaded = TRUE; } /* if we found any comments, then make a parasite for them */ if (comment_buffer && comment_buffer->len) { GimpParasite *parasite; jpeg_load_sanitize_comment (comment_buffer->str); parasite = gimp_parasite_new ("gimp-comment", GIMP_PARASITE_PERSISTENT, strlen (comment_buffer->str) + 1, comment_buffer->str); gimp_image_attach_parasite (image_ID, parasite); gimp_parasite_free (parasite); g_string_free (comment_buffer, TRUE); } /* Step 5.3: check for an embedded ICC profile in APP2 markers */ jpeg_icc_read_profile (&cinfo, &profile, &profile_size); if (cinfo.out_color_space == JCS_CMYK) { cmyk_transform = jpeg_load_cmyk_transform (profile, profile_size); } else if (profile) /* don't attach the profile if we are transforming */ { GimpParasite *parasite; parasite = gimp_parasite_new ("icc-profile", GIMP_PARASITE_PERSISTENT | GIMP_PARASITE_UNDOABLE, profile_size, profile); gimp_image_attach_parasite (image_ID, parasite); gimp_parasite_free (parasite); } g_free (profile); /* Do not attach the "jpeg-save-options" parasite to the image * because this conflicts with the global defaults (bug #75398). */ } /* 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. */ buffer = gimp_drawable_get_buffer (layer_ID); format = babl_format (image_type == GIMP_RGB ? "R'G'B' u8" : "Y' u8"); while (cinfo.output_scanline < cinfo.output_height) { start = cinfo.output_scanline; end = cinfo.output_scanline + tile_height; end = MIN (end, cinfo.output_height); scanlines = end - start; for (i = 0; i < scanlines; i++) jpeg_read_scanlines (&cinfo, (JSAMPARRAY) &rowbuf[i], 1); if (cinfo.out_color_space == JCS_CMYK) jpeg_load_cmyk_to_rgb (buf, cinfo.output_width * scanlines, cmyk_transform); gegl_buffer_set (buffer, GEGL_RECTANGLE (0, start, cinfo.output_width, scanlines), 0, format, buf, GEGL_AUTO_ROWSTRIDE); if (! preview && (cinfo.output_scanline % 32) == 0) gimp_progress_update ((gdouble) cinfo.output_scanline / (gdouble) cinfo.output_height); } /* Step 7: Finish decompression */ jpeg_finish_decompress (&cinfo); /* We can ignore the return value since suspension is not possible * with the stdio data source. */ if (cmyk_transform) cmsDeleteTransform (cmyk_transform); /* Step 8: Release JPEG decompression object */ /* This is an important step since it will release a good deal of memory. */ jpeg_destroy_decompress (&cinfo); g_object_unref (buffer); /* free up the temporary buffers */ g_free (rowbuf); g_free (buf); /* 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...) */ fclose (infile); /* At this point you may want to check to see whether any corrupt-data * warnings occurred (test whether jerr.num_warnings is nonzero). */ /* Detach from the drawable and add it to the image. */ if (! preview) { gimp_progress_update (1.0); } gimp_image_insert_layer (image_ID, layer_ID, -1, 0); return image_ID; }
Image *JPEGImageConverter::deformatImage( InputStream *inStream ) { // use a temp file with a random name to make this more // thread-safe char *fileName = new char[99]; sprintf( fileName, "temp%d.dat", rand() ); FILE *tempFile = fopen( fileName, "wb" ); if( tempFile == NULL ) { printf( "can't open jpeg conversion temp file %s\n", fileName ); return NULL; } // buffer for dumping stream to temp file unsigned char *tempBuffer = new unsigned char[1]; unsigned char previousByte = 0; // dump the JPEG stream from the input stream into tempFile // so that we can pass this file to libjpeg /* // optimization: use a buffer to prevent too many fwrite calls int bufferLength = 5000; unsigned char *fileBuffer = new unsigned char[ bufferLength ]; int currentBufferPosition = 0; while( !( tempBuffer[0] == 0xD9 && previousByte == 0xFF ) ) { previousByte = tempBuffer[0]; inStream->read( tempBuffer, 1 ); fileBuffer[currentBufferPosition] = tempBuffer[0]; if( currentBufferPosition == bufferLength - 1 ) { // at the end of the file buffer fwrite( fileBuffer, 1, bufferLength, tempFile ); currentBufferPosition = 0; } else { // keep filling the fileBuffer currentBufferPosition++; } } // now write remaining fileBuffer data to file fwrite( fileBuffer, 1, currentBufferPosition + 1, tempFile ); delete [] fileBuffer; */ // write until EOI sequence seen (0xFFD9) while( !( tempBuffer[0] == 0xD9 && previousByte == 0xFF ) ) { previousByte = tempBuffer[0]; inStream->read( tempBuffer, 1 ); fwrite( tempBuffer, 1, 1, tempFile ); } // end of jpeg stream reached. fclose( tempFile ); delete [] tempBuffer; // the remainder of this method was mostly copied from // IJG's example.c /* 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. * Note that this struct must live as long as the main JPEG parameter * struct, to avoid dangling-pointer problems. */ struct my_error_mgr jerr; /* More stuff */ FILE * infile; /* source file */ JSAMPARRAY buffer; /* Output row buffer */ int 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. */ if( ( infile = fopen( fileName, "rb" ) ) == NULL ) { printf( "can't open jpeg conversion temp file %s\n", fileName ); return NULL; } /* 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 = my_error_exit; /* 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 ); fclose( infile ); printf( "error in decompressing jpeg from stream.\n" ); return NULL; } /* 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 ); /* Step 3: read file parameters with jpeg_read_header() */ (void) 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 */ /* In this example, we don't need to change any of the defaults set by * jpeg_read_header(), so we do nothing here. */ /* Step 5: Start decompressor */ (void) 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 */ int imageWidth = cinfo.output_width; int imageHeight = cinfo.output_height; // the return image with 3 channels Image *returnImage = new Image( imageWidth, imageHeight, 3 ); // channels of returnImage, // which we will need to put pixel values into of double *redChannel = returnImage->getChannel(0); double *greenChannel = returnImage->getChannel(1); double *blueChannel = returnImage->getChannel(2); int currentIndex = 0; 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. */ int rowNumber = 0; double inv255 = 1.0 / 255.0; 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. */ (void) jpeg_read_scanlines( &cinfo, buffer, 1 ); // write the scanline into returnImage int yOffset = rowNumber * cinfo.output_width; // for each pixel in the row // copy it into the return image channels for( int p=0; p<cinfo.output_width; p++ ) { // index into inImage int pixelIndex = p + yOffset; // index into this row int startRowIndex = p * 3; // red redChannel[ pixelIndex ] = buffer[0][ startRowIndex ] * inv255; // green greenChannel[ pixelIndex ] = buffer[0][ startRowIndex + 1 ] * inv255; // blue blueChannel[ pixelIndex ] = buffer[0][ startRowIndex + 2 ] * inv255; } rowNumber++; } /* 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. */ /* 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...) */ fclose( infile ); /* At this point you may want to check to see whether any corrupt-data * warnings occurred (test whether jerr.pub.num_warnings is nonzero). */ // delete this temporary file remove( fileName ); delete [] fileName; /* And we're done! */ return returnImage; }
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; /* We assume all-in-memory processing and can therefore use only a * single file pointer for sequential input and output operation. */ FILE * fp; unsigned char *inbuffer = NULL; unsigned long insize = 0; unsigned char *outbuffer = NULL; unsigned long outsize = 0; /* 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); /* 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 ((fp = fopen(argv[file_index], READ_BINARY)) == NULL) { fprintf(stderr, "%s: can't open %s for reading\n", progname, argv[file_index]); exit(EXIT_FAILURE); } } else { /* default input file is stdin */ fp = read_stdin(); } #ifdef PROGRESS_REPORT start_progress_monitor((j_common_ptr) &dstinfo, &progress); #endif /* Specify data source for decompression */ if (jpeg_c_int_param_supported(&dstinfo, JINT_COMPRESS_PROFILE) && jpeg_c_get_int_param(&dstinfo, JINT_COMPRESS_PROFILE) == JCP_MAX_COMPRESSION) memsrc = TRUE; /* needed to revert to original */ #if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED) if (memsrc) { size_t nbytes; do { inbuffer = (unsigned char *)realloc(inbuffer, insize + INPUT_BUF_SIZE); if (inbuffer == NULL) { fprintf(stderr, "%s: memory allocation failure\n", progname); exit(EXIT_FAILURE); } nbytes = JFREAD(fp, &inbuffer[insize], INPUT_BUF_SIZE); if (nbytes < INPUT_BUF_SIZE && ferror(fp)) { if (file_index < argc) fprintf(stderr, "%s: can't read from %s\n", progname, argv[file_index]); else fprintf(stderr, "%s: can't read from stdin\n", progname); } insize += (unsigned long)nbytes; } while (nbytes == INPUT_BUF_SIZE); jpeg_mem_src(&srcinfo, inbuffer, insize); } else #endif jpeg_stdio_src(&srcinfo, fp); /* 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 /* Fail right away if -perfect is given and transformation is not perfect. */ if (!jtransform_request_workspace(&srcinfo, &transformoption)) { fprintf(stderr, "%s: transformation is not perfect\n", progname); exit(EXIT_FAILURE); } #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 /* Close input file, if we opened it. * Note: we assume that jpeg_read_coefficients consumed all input * until JPEG_REACHED_EOI, and that jpeg_finish_decompress will * only consume more while (! cinfo->inputctl->eoi_reached). * We cannot call jpeg_finish_decompress here since we still need the * virtual arrays allocated from the source object for processing. */ if (fp != stdin) fclose(fp); /* Open the output file. */ if (outfilename != NULL) { if ((fp = fopen(outfilename, WRITE_BINARY)) == NULL) { fprintf(stderr, "%s: can't open %s for writing\n", progname, outfilename); exit(EXIT_FAILURE); } } else { /* default output file is stdout */ fp = write_stdout(); } /* Adjust default compression parameters by re-parsing the options */ file_index = parse_switches(&dstinfo, argc, argv, 0, TRUE); /* Specify data destination for compression */ #if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED) if (jpeg_c_int_param_supported(&dstinfo, JINT_COMPRESS_PROFILE) && jpeg_c_get_int_param(&dstinfo, JINT_COMPRESS_PROFILE) == JCP_MAX_COMPRESSION) jpeg_mem_dest(&dstinfo, &outbuffer, &outsize); else #endif jpeg_stdio_dest(&dstinfo, fp); /* 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); if (jpeg_c_int_param_supported(&dstinfo, JINT_COMPRESS_PROFILE) && jpeg_c_get_int_param(&dstinfo, JINT_COMPRESS_PROFILE) == JCP_MAX_COMPRESSION) { size_t nbytes; unsigned char *buffer = outbuffer; unsigned long size = outsize; if (insize < size) { size = insize; buffer = inbuffer; } nbytes = JFWRITE(fp, buffer, size); if (nbytes < size && ferror(fp)) { if (file_index < argc) fprintf(stderr, "%s: can't write to %s\n", progname, argv[file_index]); else fprintf(stderr, "%s: can't write to stdout\n", progname); } } jpeg_destroy_compress(&dstinfo); (void) jpeg_finish_decompress(&srcinfo); jpeg_destroy_decompress(&srcinfo); /* Close output file, if we opened it */ if (fp != stdout) fclose(fp); #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 */ }
/** * @brief JPEG decompression routine. * @param file: JPEG file * @param out_params : output parameter structure. * @retval Status */ int32_t jpeg_decompress(FIL *file, OutParams_Typedef *out_params) { struct jpeg_decompress_struct cinfo; /* This struct contains the JPEG decompression parameters */ struct jpeg_error_mgr jerr; /* This struct represents a JPEG error handler */ JSAMPROW buffer[2] = {0}; /* Output row buffer */ buffer[0] = out_params->out_buff; /* Step 1: allocate and initialize JPEG decompression object */ cinfo.err = jpeg_std_error(&jerr); /* Initialize the JPEG decompression object */ jpeg_create_decompress(&cinfo); /* Step 2: specify data source */ jpeg_stdio_src (&cinfo, file); /* Step 3: read image parameters with jpeg_read_header() */ jpeg_read_header(&cinfo, TRUE); /* Step 4: get parameters for scaling */ out_params->get_scale (cinfo.image_width, cinfo.image_height, (uint32_t *)&cinfo.scale_num, (uint32_t *)&cinfo.scale_denom) ; if((cinfo.image_width > 1024) || (cinfo.image_height > 768) || (cinfo.image_width < 160 ) || (cinfo.image_height < 120) || (cinfo.progressive_mode == 1)) { jpeg_destroy_decompress(&cinfo); return -1; } /* Step 5: set parameters for decompression */ #ifdef USE_STM324xG_EVAL cinfo.dct_method = JDCT_FLOAT; #elif defined (USE_STM322xG_EVAL) cinfo.dct_method = JDCT_IFAST; #endif /* Step 6: start decompressor */ jpeg_start_decompress(&cinfo); /* Step 7: Init output process */ out_params->set_scale (cinfo.output_width, cinfo.output_height); /* Step 8: process decompressing */ while (cinfo.output_scanline < cinfo.output_height) { (void) jpeg_read_scanlines(&cinfo, buffer, 1); if (out_params->out_process != NULL) { out_params->out_process(buffer[0], cinfo.output_width); } } /* Step 7: Finish decompression */ jpeg_finish_decompress(&cinfo); /* Step 8: Release JPEG decompression object */ jpeg_destroy_decompress(&cinfo); return 0; }
// createImageFromJpeg decompresses a JPEG image to the standard image format // source: https://github.com/ileben/ShivaVG/blob/master/examples/test_image.c VGImage createImageFromJpeg(const char *filename) { FILE *infile; struct jpeg_decompress_struct jdc; struct jpeg_error_mgr jerr; JSAMPARRAY buffer; unsigned int bstride; unsigned int bbpp; VGImage img; VGubyte *data; unsigned int width; unsigned int height; unsigned int dstride; unsigned int dbpp; VGubyte *brow; VGubyte *drow; unsigned int x; unsigned int lilEndianTest = 1; VGImageFormat rgbaFormat; // Check for endianness if (((unsigned char *)&lilEndianTest)[0] == 1) rgbaFormat = VG_sABGR_8888; else rgbaFormat = VG_sRGBA_8888; // Try to open image file infile = fopen(filename, "rb"); if (infile == NULL) { printf("Failed opening '%s' for reading!\n", filename); return VG_INVALID_HANDLE; } // Setup default error handling jdc.err = jpeg_std_error(&jerr); jpeg_create_decompress(&jdc); // Set input file jpeg_stdio_src(&jdc, infile); // Read header and start jpeg_read_header(&jdc, TRUE); jpeg_start_decompress(&jdc); width = jdc.output_width; height = jdc.output_height; // Allocate buffer using jpeg allocator bbpp = jdc.output_components; bstride = width * bbpp; buffer = (*jdc.mem->alloc_sarray) ((j_common_ptr) & jdc, JPOOL_IMAGE, bstride, 1); // Allocate image data buffer dbpp = 4; dstride = width * dbpp; data = (VGubyte *) malloc(dstride * height); // Iterate until all scanlines processed while (jdc.output_scanline < height) { // Read scanline into buffer jpeg_read_scanlines(&jdc, buffer, 1); drow = data + (height - jdc.output_scanline) * dstride; brow = buffer[0]; // Expand to RGBA for (x = 0; x < width; ++x, drow += dbpp, brow += bbpp) { switch (bbpp) { case 4: drow[0] = brow[0]; drow[1] = brow[1]; drow[2] = brow[2]; drow[3] = brow[3]; break; case 3: drow[0] = brow[0]; drow[1] = brow[1]; drow[2] = brow[2]; drow[3] = 255; break; } } } // Create VG image img = vgCreateImage(rgbaFormat, width, height, VG_IMAGE_QUALITY_BETTER); vgImageSubData(img, data, dstride, rgbaFormat, 0, 0, width, height); // Cleanup jpeg_destroy_decompress(&jdc); fclose(infile); free(data); return img; }
GLubyte * readJPEGimage(char *imagefile, GLsizei *xsize, GLsizei *ysize, GLsizei *zsize) { /* 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. * Note that this struct must live as long as the main JPEG parameter * struct, to avoid dangling-pointer problems. */ struct my_error_mgr jerr; /* More stuff */ FILE * infile; /* source file */ JSAMPARRAY buffer; /* Output row buffer */ int row_stride; /* physical row width in output buffer */ long cont; JSAMPLE *imagebuf; /* 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. */ if ((infile = fopen(imagefile, "rb")) == NULL) { fprintf(stderr, "can't open %s\n", imagefile); return NULL; } /* 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 = my_error_exit; /* 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); fclose(infile); return NULL; } /* 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); /* Step 3: read file parameters with jpeg_read_header() */ (void) 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 */ /* In this example, we don't need to change any of the defaults set by * jpeg_read_header(), so we do nothing here. */ /* Step 5: Start decompressor */ (void) 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 */ 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. */ imagebuf = (JSAMPLE *)malloc(cinfo.image_width *cinfo.image_height *cinfo.output_components); if(imagebuf==NULL) { fprintf(stderr, "Coundn't allocate memory"); return NULL; } *xsize = cinfo.image_width; *ysize = cinfo.image_height; *zsize = cinfo.output_components; cont=cinfo.output_height-1; 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. */ (void) jpeg_read_scanlines(&cinfo, buffer, 1); /* Assume put_scanline_someplace wants a pointer and sample count. */ /* put_scanline_someplace(buffer[0], row_stride); */ memcpy(imagebuf + cinfo.image_width *cinfo.output_components *cont, buffer[0], row_stride); cont--; } /* 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. */ /* 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...) */ fclose(infile); /* 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 imagebuf; }
static int libjpeg_(Main_size)(lua_State *L) { /* 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. * Note that this struct must live as long as the main JPEG parameter * struct, to avoid dangling-pointer problems. */ struct my_error_mgr jerr; /* More stuff */ FILE * infile; /* source file */ const char *filename = luaL_checkstring(L, 1); /* 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. */ if ((infile = fopen(filename, "rb")) == NULL) { luaL_error(L, "cannot open file <%s> for reading", filename); } /* 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 = libjpeg_(Main_error); /* 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); fclose(infile); 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); /* Step 3: read file parameters with jpeg_read_header() */ 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 */ /* In this example, we don't need to change any of the defaults set by * jpeg_read_header(), so we do nothing here. */ /* Step 5: Start decompressor */ (void) jpeg_start_decompress(&cinfo); /* We can ignore the return value since suspension is not possible * with the stdio data source. */ lua_pushnumber(L, cinfo.output_components); lua_pushnumber(L, cinfo.output_height); lua_pushnumber(L, cinfo.output_width); /* 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...) */ fclose(infile); /* 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 3; }
int read_jpeg_file( char *filename ) { /* these are standard libjpeg structures for reading(decompression) */ struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; /* libjpeg data structure for storing one row, that is, scanline of an image */ JSAMPROW row_pointer[1]; FILE *infile = fopen( filename, "rb" ); unsigned long location = 0; int i = 0; if ( !infile ) { printf("Error opening jpeg file %s\n!", filename ); return -1; } /* here we set up the standard libjpeg error handler */ cinfo.err = jpeg_std_error( &jerr ); /* setup decompression process and source, then read JPEG header */ jpeg_create_decompress( &cinfo ); /* this makes the library read from infile */ jpeg_stdio_src( &cinfo, infile ); /* reading the image header which contains image information */ jpeg_read_header( &cinfo, TRUE ); /* Uncomment the following to output image information, if needed. */ /*-- printf( "JPEG File Information: \n" ); printf( "Image width and height: %d pixels and %d pixels.\n", cinfo.image_width, cinfo.image_height ); printf( "Color components per pixel: %d.\n", cinfo.num_components ); printf( "Color space: %d.\n", cinfo.jpeg_color_space ); --*/ /* Start decompression jpeg here */ jpeg_start_decompress( &cinfo ); /* allocate memory to hold the uncompressed image */ raw_image = (unsigned char*)malloc( cinfo.output_width*cinfo.output_height*cinfo.num_components ); raw_image_size = cinfo.output_width*cinfo.output_height*cinfo.num_components; width = cinfo.output_width; height = cinfo.output_height; bytes_per_pixel = cinfo.num_components; /* now actually read the jpeg into the raw buffer */ row_pointer[0] = (unsigned char *)malloc( cinfo.output_width*cinfo.num_components ); /* read one scan line at a time */ while( cinfo.output_scanline < cinfo.image_height ) { jpeg_read_scanlines( &cinfo, row_pointer, 1 ); for( i=0; i<cinfo.image_width*cinfo.num_components;i++) { raw_image[location++] = row_pointer[0][i]; //printf("%02x ", raw_image[location-1]); //if((i + 1) % 3 == 0) printf("\n"); } } /* wrap up decompression, destroy objects, free pointers and close open files */ jpeg_finish_decompress( &cinfo ); jpeg_destroy_decompress( &cinfo ); free( row_pointer[0] ); fclose( infile ); /* yup, we succeeded! */ return 1; }
int main (int argc, char **argv) { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; #ifdef LIBJPEG_PROGRESS_REPORT struct cdjpeg_progress_mgr progress; #endif int file_index; djpeg_dest_ptr dest_mgr = NULL; FILE * input_file; FILE * output_file; JDIMENSION num_scanlines; /* On Mac, fetch a command line. */ #ifdef USE_CCOMMAND argc = ccommand(&argv); #endif progname = argv[0]; if (progname == NULL || progname[0] == 0) progname = "djpeg"; /* in case C library doesn't provide it */ /* Initialize the JPEG decompression object with default error handling. */ cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); /* Add some application-specific error messages (from cderror.h) */ jerr.addon_message_table = cdjpeg_message_table; jerr.first_addon_message = JMSG_FIRSTADDONCODE; jerr.last_addon_message = JMSG_LASTADDONCODE; /* Insert custom marker processor for COM and APP12. * APP12 is used by some digital camera makers for textual info, * so we provide the ability to display it as text. * If you like, additional APPn marker types can be selected for display, * but don't try to override APP0 or APP14 this way (see libjpeg.doc). */ jpeg_set_marker_processor(&cinfo, JPEG_COM, print_text_marker); jpeg_set_marker_processor(&cinfo, JPEG_APP0+12, print_text_marker); /* Now safe to enable signal catcher. */ #ifdef LIBJPEG_NEED_SIGNAL_CATCHER enable_signal_catcher((j_common_ptr) &cinfo); #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 ignored; we will rescan the switches after opening * the input file. * (Exception: tracing level set here controls verbosity for COM markers * found during jpeg_read_header...) */ file_index = parse_switches(&cinfo, argc, argv, 0, FALSE); #ifdef LIBJPEG_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 /* LIBJPEG_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 LIBJPEG_PROGRESS_REPORT start_progress_monitor((j_common_ptr) &cinfo, &progress); #endif /* Specify data source for decompression */ jpeg_stdio_src(&cinfo, input_file); /* Read file header, set default decompression parameters */ (void) jpeg_read_header(&cinfo, TRUE); /* Adjust default decompression parameters by re-parsing the options */ file_index = parse_switches(&cinfo, argc, argv, 0, TRUE); /* Initialize the output module now to let it override any crucial * option settings (for instance, GIF wants to force color quantization). */ switch (requested_fmt) { #ifdef LIBJPEG_BMP_SUPPORTED case FMT_BMP: dest_mgr = jinit_write_bmp(&cinfo, FALSE); break; case FMT_OS2: dest_mgr = jinit_write_bmp(&cinfo, TRUE); break; #endif #ifdef LIBJPEG_GIF_SUPPORTED case FMT_GIF: dest_mgr = jinit_write_gif(&cinfo); break; #endif #ifdef LIBJPEG_PPM_SUPPORTED case FMT_PPM: dest_mgr = jinit_write_ppm(&cinfo); break; #endif #ifdef LIBJPEG_RLE_SUPPORTED case FMT_RLE: dest_mgr = jinit_write_rle(&cinfo); break; #endif #ifdef LIBJPEG_TARGA_SUPPORTED case FMT_TARGA: dest_mgr = jinit_write_targa(&cinfo); break; #endif default: ERREXIT(&cinfo, JERR_UNSUPPORTED_FORMAT); break; } dest_mgr->output_file = output_file; /* Start decompressor */ (void) jpeg_start_decompress(&cinfo); /* Write output file header */ (*dest_mgr->start_output) (&cinfo, dest_mgr); /* Process data */ while (cinfo.output_scanline < cinfo.output_height) { num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer, dest_mgr->buffer_height); (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); } #ifdef LIBJPEG_PROGRESS_REPORT /* Hack: count final pass as done in case finish_output does an extra pass. * The library won't have updated completed_passes. */ progress.pub.completed_passes = progress.pub.total_passes; #endif /* Finish decompression and release memory. * I must do it in this order because output module has allocated memory * of lifespan JPOOL_IMAGE; it needs to finish before releasing memory. */ (*dest_mgr->finish_output) (&cinfo, dest_mgr); (void) jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); /* Close files, if we opened them */ if (input_file != stdin) fclose(input_file); if (output_file != stdout) fclose(output_file); #ifdef LIBJPEG_PROGRESS_REPORT end_progress_monitor((j_common_ptr) &cinfo); #endif /* All done. */ exit(jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS); return 0; /* suppress no-return-value warnings */ }