static int bitmap_decode(struct jpeg_decompress_struct *cinfo, Vbitmap *vbitmap, YmagineFormatOptions *options) { int nlines = -1; cinfo->client_data = (void*) vbitmap; if (prepareDecompressor(cinfo, options) != YMAGINE_OK) { return nlines; } /* Intercept APP1 markers for PhotoSphere parsing */ jpeg_set_marker_processor(cinfo, JPEG_APP0 + 1, APP1_handler); if (startDecompressor(cinfo, VbitmapColormode(vbitmap)) != YMAGINE_OK) { return nlines; } YmagineFormatOptions_invokeCallback(options, YMAGINE_IMAGEFORMAT_JPEG, cinfo->image_width, cinfo->image_height); #if YMAGINE_DEBUG_JPEG ALOGD("bitmap_decode: in=%dx%d bm=%dx%d max=%dx%d", cinfo->image_width, cinfo->image_height, VbitmapWidth(vbitmap), VbitmapHeight(vbitmap), options->maxwidth, options->maxheight); #endif nlines = decompress_jpeg(cinfo, NULL, JCOPYOPT_NONE, vbitmap, options); return nlines; }
/* * fgetJpegComment() * * Input: fp (file stream opened for read) * &comment (<return> comment) * Return: 0 if OK; 1 on error * * Notes: * (1) Side-effect: this rewinds the stream. */ l_int32 fgetJpegComment(FILE *fp, l_uint8 **pcomment) { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; struct callback_data cb_data; /* contains local jmp_buf */ PROCNAME("fgetJpegComment"); if (!pcomment) return ERROR_INT("&comment not defined", procName, 1); *pcomment = NULL; if (!fp) return ERROR_INT("stream not opened", procName, 1); rewind(fp); /* Modify the jpeg error handling to catch fatal errors */ cinfo.err = jpeg_std_error(&jerr); jerr.error_exit = jpeg_error_catch_all_2; cb_data.comment = NULL; cinfo.client_data = (void *)&cb_data; if (setjmp(cb_data.jmpbuf)) { LEPT_FREE(cb_data.comment); return ERROR_INT("internal jpeg error", procName, 1); } /* Initialize the jpeg structs for reading the header */ jpeg_create_decompress(&cinfo); jpeg_set_marker_processor(&cinfo, JPEG_COM, jpeg_comment_callback); jpeg_stdio_src(&cinfo, fp); jpeg_read_header(&cinfo, TRUE); /* Save the result */ *pcomment = cb_data.comment; jpeg_destroy_decompress(&cinfo); rewind(fp); return 0; }
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; 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 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 */ 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); /* 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 /* All done. */ exit(jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS); return 0; /* suppress no-return-value warnings */ }
int jpg_open(char *filename) { char outbuf[1024]; int i; struct my_error_mgr jerr; jpeg_component_info *compptr; FILE *fin; comments_init(); jpg_markers = 0; if ((fin = fopen(filename, "r")) == NULL) { int error = errno; fprintf(stderr, "%s : error: %s\n", filename, strerror(error)); return (-1); } jinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = my_error_exit; if (stego_eoi_cb != NULL) jerr.pub.emit_message = my_error_emit; /* Establish the setjmp return context for my_error_exit to use. */ if (setjmp(jerr.setjmp_buffer)) { /* Always display the message. */ (*jinfo.err->format_message) ((j_common_ptr)&jinfo, outbuf); fprintf(stderr, "%s : error: %s\n", filename, outbuf); /* 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(&jinfo); fclose(fin); return (-1); } jpeg_create_decompress(&jinfo); jpeg_set_marker_processor(&jinfo, JPEG_COM, comment_handler); for (i = 1; i < 16; i++) jpeg_set_marker_processor(&jinfo, JPEG_APP0+i, marker_handler); jpeg_stdio_src(&jinfo, fin); jpeg_read_header(&jinfo, TRUE); /* jinfo.quantize_colors = TRUE; */ dctcoeff = (njvirt_barray_ptr *)jpeg_read_coefficients(&jinfo); fclose(fin); if (dctcoeff == NULL) { fprintf(stderr, "%s : error: can not get coefficients\n", filename); goto out; } if (jinfo.out_color_space != JCS_RGB) { fprintf(stderr, "%s : error: is not a RGB image\n", filename); goto out; } i = jinfo.num_components; if (i != 3) { fprintf(stderr, "%s : error: wrong number of color components: %d\n", filename, i); goto out; } for(i = 0; i < 3; i++) { compptr = jinfo.cur_comp_info[i]; /* fprintf(stderr, "input_iMCU_row: %d, v_samp_factor: %d\n", jinfo.input_iMCU_row * compptr->v_samp_factor, (JDIMENSION) compptr->v_samp_factor); fprintf(stderr, "hib: %d, wib: %d\n", jinfo.comp_info[i].height_in_blocks, jinfo.comp_info[i].width_in_blocks); */ wib[i] = jinfo.comp_info[i].width_in_blocks; hib[i] = jinfo.comp_info[i].height_in_blocks; dctcompbuf[i] = dctcoeff[i]->mem_buffer; } return (0); out: jpg_destroy(); return (-1); }
static ImBuf * ibJpegImageFromCinfo(struct jpeg_decompress_struct * cinfo, int flags) { JSAMPARRAY row_pointer; JSAMPLE * buffer = NULL; int row_stride; int x, y, depth, r, g, b, k; struct ImBuf * ibuf = NULL; uchar * rect; jpeg_saved_marker_ptr marker; char *str, *key, *value; /* install own app1 handler */ ibuf_ftype = 0; jpeg_set_marker_processor(cinfo, 0xe1, handle_app1); cinfo->dct_method = JDCT_FLOAT; jpeg_save_markers(cinfo, JPEG_COM, 0xffff); if (jpeg_read_header(cinfo, FALSE) == JPEG_HEADER_OK) { x = cinfo->image_width; y = cinfo->image_height; depth = cinfo->num_components; if (cinfo->jpeg_color_space == JCS_YCCK) cinfo->out_color_space = JCS_CMYK; jpeg_start_decompress(cinfo); if (ibuf_ftype == 0) { ibuf_ftype = JPG_STD; if (cinfo->max_v_samp_factor == 1) { if (cinfo->max_h_samp_factor == 1) ibuf_ftype = JPG_MAX; else ibuf_ftype = JPG_VID; } } if (flags & IB_test) { jpeg_abort_decompress(cinfo); ibuf = IMB_allocImBuf(x, y, 8 * depth, 0); } else if ((ibuf = IMB_allocImBuf(x, y, 8 * depth, IB_rect)) == NULL) { jpeg_abort_decompress(cinfo); } else { row_stride = cinfo->output_width * depth; row_pointer = (*cinfo->mem->alloc_sarray) ((j_common_ptr) cinfo, JPOOL_IMAGE, row_stride, 1); for (y = ibuf->y - 1; y >= 0; y--) { jpeg_read_scanlines(cinfo, row_pointer, 1); rect = (uchar *) (ibuf->rect + y * ibuf->x); buffer = row_pointer[0]; switch(depth) { case 1: for (x=ibuf->x; x >0; x--) { rect[3] = 255; rect[0] = rect[1] = rect[2] = *buffer++; rect += 4; } break; case 3: for (x=ibuf->x; x >0; x--) { rect[3] = 255; rect[0] = *buffer++; rect[1] = *buffer++; rect[2] = *buffer++; rect += 4; } break; case 4: for (x=ibuf->x; x >0; x--) { r = *buffer++; g = *buffer++; b = *buffer++; k = *buffer++; k = 255 - k; r -= k; if (r & 0xffffff00) { if (r < 0) r = 0; else r = 255; } g -= k; if (g & 0xffffff00) { if (g < 0) g = 0; else g = 255; } b -= k; if (b & 0xffffff00) { if (b < 0) b = 0; else b = 255; } rect[3] = 255 - k; rect[2] = b; rect[1] = g; rect[0] = r; rect += 4; } } } marker= cinfo->marker_list; while(marker) { if(marker->marker != JPEG_COM) goto next_stamp_marker; /* * Because JPEG format don't support the * pair "key/value" like PNG, we store the * stampinfo in a single "encode" string: * "Blender:key:value" * * That is why we need split it to the * common key/value here. */ if(strncmp((char *) marker->data, "Blender", 7)) { /* * Maybe the file have text that * we don't know "what it's", in that * case we keep the text (with a * key "None"). * This is only for don't "lose" * the information when we write * it back to disk. */ IMB_metadata_add_field(ibuf, "None", (char *) marker->data); ibuf->flags |= IB_metadata; goto next_stamp_marker; } str = BLI_strdup ((char *) marker->data); key = strchr (str, ':'); /* * A little paranoid, but the file maybe * is broken... and a "extra" check is better * that a segfaul ;) */ if (!key) { MEM_freeN(str); goto next_stamp_marker; } key++; value = strchr (key, ':'); if (!value) { MEM_freeN(str); goto next_stamp_marker; } *value = '\0'; /* need finish the key string */ value++; IMB_metadata_add_field(ibuf, key, value); ibuf->flags |= IB_metadata; MEM_freeN(str); next_stamp_marker: marker= marker->next; } jpeg_finish_decompress(cinfo); } jpeg_destroy((j_common_ptr) cinfo); if(ibuf) { ibuf->ftype = ibuf_ftype; ibuf->profile = IB_PROFILE_SRGB; } } return(ibuf); }
process_one_file (int argc, char **argv, int old_file_index) { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; char *infilename; char workfilename[PATH_MAX]; const char *default_extension = NULL; #ifdef PROGRESS_REPORT struct cdjpeg_progress_mgr progress; #endif int file_index; djpeg_dest_ptr dest_mgr = NULL; FILE * input_file = NULL; FILE * output_file = NULL; JDIMENSION num_scanlines; /* 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 NEED_SIGNAL_CATCHER enable_signal_catcher((j_common_ptr) &cinfo); #endif /* Scan command line to find next file name. * 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, old_file_index, FALSE); if (file_index >= argc) { fprintf(stderr, "%s: missing input file name\n", progname); usage(); } /* Open the input file. */ infilename = argv[file_index]; if ((input_file = fopen(infilename, READ_BINARY)) == NULL) { fprintf(stderr, "%s: can't open %s\n", progname, infilename); goto fail; } #ifdef 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, old_file_index, 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); default_extension = ".bmp"; break; case FMT_OS2: dest_mgr = jinit_write_bmp(&cinfo, TRUE); default_extension = ".bmp"; break; #endif #ifdef GIF_SUPPORTED case FMT_GIF: dest_mgr = jinit_write_gif(&cinfo); default_extension = ".gif"; break; #endif #ifdef PPM_SUPPORTED case FMT_PPM: dest_mgr = jinit_write_ppm(&cinfo); default_extension = ".ppm"; break; #endif #ifdef RLE_SUPPORTED case FMT_RLE: dest_mgr = jinit_write_rle(&cinfo); default_extension = ".rle"; break; #endif #ifdef TARGA_SUPPORTED case FMT_TARGA: dest_mgr = jinit_write_targa(&cinfo); default_extension = ".tga"; break; #endif default: ERREXIT(&cinfo, JERR_UNSUPPORTED_FORMAT); break; } /* If user didn't supply -outfile switch, select output file name. */ if (outfilename == NULL) { int i; outfilename = workfilename; /* Make outfilename be infilename with appropriate extension */ strcpy(outfilename, infilename); for (i = strlen(outfilename)-1; i >= 0; i--) { switch (outfilename[i]) { case ':': case '/': case '\\': i = 0; /* stop scanning */ break; case '.': outfilename[i] = '\0'; /* lop off existing extension */ i = 0; /* stop scanning */ break; default: break; /* keep scanning */ } } strcat(outfilename, default_extension); } fprintf(stderr, "Decompressing %s => %s\n", infilename, outfilename); #ifndef NO_OVERWRITE_CHECK if (! is_write_ok(outfilename)) goto fail; #endif /* Open the output file. */ if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) { fprintf(stderr, "%s: can't create %s\n", progname, outfilename); goto fail; } 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 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); /* Clean up and exit */ fail: jpeg_destroy_decompress(&cinfo); if (input_file != NULL) fclose(input_file); if (output_file != NULL) fclose(output_file); #ifdef PROGRESS_REPORT end_progress_monitor((j_common_ptr) &cinfo); #endif /* Disable signal catcher. */ #ifdef NEED_SIGNAL_CATCHER enable_signal_catcher((j_common_ptr) NULL); #endif return file_index; }
int djpeg (char *inbuf,int inbuflen,unsigned char **ppout) { struct jpeg_decompress_struct cinfo ; struct jpeg_error_mgr jerr ; djpeg_dest_ptr dest_mgr = NULL; JDIMENSION num_scanlines; if (ppout == NULL) return -1; *ppout = NULL; /* Initialize the JPEG decompression object with default error handling. */ cinfo.err = jpeg_std_error(&jerr); cinfo.err->error_exit = My_Error_Exit; 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); set_cinfo(&cinfo); Jpeg_Memory_Src(&cinfo, inbuf, inbuflen); /* Read file header, set default decompression parameters */ (void) jpeg_read_header(&cinfo, TRUE); /* Adjust default decompression parameters by re-parsing the options */ set_cinfo(&cinfo); /* Initialize the output module now to let it override any crucial * option settings (for instance, GIF wants to force color quantization). */ dest_mgr = jinit_write_bmp(&cinfo, FALSE); /* 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); } /* 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. */ put_gray_to_buff(&cinfo,dest_mgr,ppout); //toview (void) jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); return 0; }
/*! * pixReadStreamJpeg() * * Input: stream * colormap flag (0 means return RGB image if color; * 1 means create colormap and return 8 bpp * palette image if color) * reduction (scaling factor: 1, 2, 4 or 8) * &pnwarn (<optional return> number of warnings) * hint: (a bitwise OR of L_HINT_* values); use 0 for no hints * Return: pix, or null on error * * Usage: see pixReadJpeg() */ PIX * pixReadStreamJpeg(FILE *fp, l_int32 cmflag, l_int32 reduction, l_int32 *pnwarn, l_int32 hint) { l_uint8 cyan, yellow, magenta, black, white; l_int32 rval, gval, bval; l_int32 i, j, k; 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; l_uint8 *comment = NULL; PROCNAME("pixReadStreamJpeg"); if (!fp) return (PIX *)ERROR_PTR("fp not defined", procName, NULL); if (pnwarn) *pnwarn = 0; /* init */ if (cmflag != 0 && cmflag != 1) cmflag = 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; /* init */ if (setjmp(jpeg_jmpbuf)) { pixDestroy(&pix); FREE(rowbuffer); return (PIX *)ERROR_PTR("internal jpeg error", procName, NULL); } rowbuffer = NULL; cinfo.err = jpeg_std_error(&jerr); jerr.error_exit = jpeg_error_do_not_exit; /* catch error; do not exit! */ jpeg_create_decompress(&cinfo); cinfo.client_data = &comment; jpeg_set_marker_processor(&cinfo, JPEG_COM, jpeg_comment_callback); jpeg_stdio_src(&cinfo, fp); jpeg_read_header(&cinfo, TRUE); cinfo.scale_denom = reduction; cinfo.scale_num = 1; if (hint & L_HINT_GRAY) cinfo.out_color_space = JCS_GRAYSCALE; jpeg_calc_output_dimensions(&cinfo); /* Allocate the image and a row buffer */ spp = cinfo.out_color_components; w = cinfo.output_width; h = cinfo.output_height; ycck = (cinfo.jpeg_color_space == JCS_YCCK && spp == 4 && cmflag == 0); cmyk = (cinfo.jpeg_color_space == JCS_CMYK && spp == 4 && cmflag == 0); if (spp != 1 && spp != 3 && !ycck && !cmyk) { if (comment) FREE(comment); return (PIX *)ERROR_PTR("spp must be 1 or 3, or YCCK or CMYK", procName, NULL); } if ((spp == 3 && cmflag == 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) { if (comment) FREE(comment); if (rowbuffer) FREE(rowbuffer); pixDestroy(&pix); return (PIX *)ERROR_PTR("rowbuffer or pix not made", procName, NULL); } if (comment) { pixSetText(pix, (char *)comment); FREE(comment); } if (spp == 1) /* Grayscale or colormapped */ jpeg_start_decompress(&cinfo); else { /* Color; spp == 3 or YCCK or CMYK */ if (cmflag == 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 */ if ((spp == 3 && cmflag == 0) || ycck || cmyk) { /* -- 24 bit color -- */ for (i = 0; i < h; i++) { if (jpeg_read_scanlines(&cinfo, &rowbuffer, (JDIMENSION)1) != 1) return (PIX *)ERROR_PTR("bad read scanline", procName, NULL); 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 are inverted on read-in, see the "Special color spaces" section of "Using the IJG JPEG Library" by Thomas G. Lane. */ for (j = k = 0; j < w; j++) { cyan = 255 - rowbuffer[k++]; magenta = 255 - rowbuffer[k++]; yellow = 255 - rowbuffer[k++]; white = rowbuffer[k++]; black = 255 - white; rval = 255 - (cyan * white) / 255 - black; gval = 255 - (magenta * white) / 255 - black; bval = 255 - (yellow * white) / 255 - black; 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 */ for (i = 0; i < h; i++) { if (jpeg_read_scanlines(&cinfo, &rowbuffer, (JDIMENSION)1) != 1) return (PIX *)ERROR_PTR("bad read scanline", procName, NULL); line = data + i * wpl; for (j = 0; j < w; j++) SET_DATA_BYTE(line, j, rowbuffer[j]); } } if (pnwarn) *pnwarn = cinfo.err->num_warnings; switch (cinfo.density_unit) { case 1: /* pixels per inch */ pixSetXRes(pix, cinfo.X_density); pixSetYRes(pix, cinfo.Y_density); break; case 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)); break; default: /* the pixel density may not be defined; ignore */ break; } jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); FREE(rowbuffer); return pix; }
static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo, int flags) { JSAMPARRAY row_pointer; JSAMPLE *buffer = NULL; int row_stride; int x, y, depth, r, g, b, k; struct ImBuf *ibuf = NULL; uchar *rect; jpeg_saved_marker_ptr marker; char *str, *key, *value; /* install own app1 handler */ ibuf_quality = jpeg_default_quality; jpeg_set_marker_processor(cinfo, 0xe1, handle_app1); cinfo->dct_method = JDCT_FLOAT; jpeg_save_markers(cinfo, JPEG_COM, 0xffff); if (jpeg_read_header(cinfo, false) == JPEG_HEADER_OK) { x = cinfo->image_width; y = cinfo->image_height; depth = cinfo->num_components; if (cinfo->jpeg_color_space == JCS_YCCK) cinfo->out_color_space = JCS_CMYK; jpeg_start_decompress(cinfo); if (flags & IB_test) { jpeg_abort_decompress(cinfo); ibuf = IMB_allocImBuf(x, y, 8 * depth, 0); } else if ((ibuf = IMB_allocImBuf(x, y, 8 * depth, IB_rect)) == NULL) { jpeg_abort_decompress(cinfo); } else { row_stride = cinfo->output_width * depth; row_pointer = (*cinfo->mem->alloc_sarray)((j_common_ptr) cinfo, JPOOL_IMAGE, row_stride, 1); for (y = ibuf->y - 1; y >= 0; y--) { jpeg_read_scanlines(cinfo, row_pointer, 1); rect = (uchar *) (ibuf->rect + y * ibuf->x); buffer = row_pointer[0]; switch (depth) { case 1: for (x = ibuf->x; x > 0; x--) { rect[3] = 255; rect[0] = rect[1] = rect[2] = *buffer++; rect += 4; } break; case 3: for (x = ibuf->x; x > 0; x--) { rect[3] = 255; rect[0] = *buffer++; rect[1] = *buffer++; rect[2] = *buffer++; rect += 4; } break; case 4: for (x = ibuf->x; x > 0; x--) { r = *buffer++; g = *buffer++; b = *buffer++; k = *buffer++; r = (r * k) / 255; g = (g * k) / 255; b = (b * k) / 255; rect[3] = 255; rect[2] = b; rect[1] = g; rect[0] = r; rect += 4; } break; } } marker = cinfo->marker_list; while (marker) { if (marker->marker != JPEG_COM) goto next_stamp_marker; /* * JPEG marker strings are not null-terminated, * create a null-terminated copy before going further */ str = BLI_strdupn((char *)marker->data, marker->data_length); /* * Because JPEG format don't support the * pair "key/value" like PNG, we store the * stampinfo in a single "encode" string: * "Blender:key:value" * * That is why we need split it to the * common key/value here. */ if (!STREQLEN(str, "Blender", 7)) { /* * Maybe the file have text that * we don't know "what it's", in that * case we keep the text (with a * key "None"). * This is only for don't "lose" * the information when we write * it back to disk. */ IMB_metadata_ensure(&ibuf->metadata); IMB_metadata_set_field(ibuf->metadata, "None", str); ibuf->flags |= IB_metadata; MEM_freeN(str); goto next_stamp_marker; } key = strchr(str, ':'); /* * A little paranoid, but the file maybe * is broken... and a "extra" check is better * then segfault ;) */ if (!key) { MEM_freeN(str); goto next_stamp_marker; } key++; value = strchr(key, ':'); if (!value) { MEM_freeN(str); goto next_stamp_marker; } *value = '\0'; /* need finish the key string */ value++; IMB_metadata_ensure(&ibuf->metadata); IMB_metadata_set_field(ibuf->metadata, key, value); ibuf->flags |= IB_metadata; MEM_freeN(str); next_stamp_marker: marker = marker->next; } jpeg_finish_decompress(cinfo); } jpeg_destroy((j_common_ptr) cinfo); if (ibuf) { ibuf->ftype = IMB_FTYPE_JPG; ibuf->foptions.quality = MIN2(ibuf_quality, 100); } } return(ibuf); }
CPLErr JPEG_Codec::DecompressJPEG(buf_mgr &dst, buf_mgr &isrc) #endif { int nbands = img.pagesize.c; // Locals, clean up after themselves jpeg_decompress_struct cinfo; MRFJPEGStruct sJPEGStruct; struct jpeg_error_mgr sJErr; BitMask mask(img.pagesize.x, img.pagesize.y); RLEC3Packer packer; mask.set_packer(&packer); memset(&cinfo, 0, sizeof(cinfo)); // Pass the mask address to the decompressor sJPEGStruct.mask = &mask; struct jpeg_source_mgr src; cinfo.err = jpeg_std_error( &sJErr ); sJErr.error_exit = errorExit; sJErr.emit_message = emitMessage; cinfo.client_data = (void *) &(sJPEGStruct); src.next_input_byte = (JOCTET *)isrc.buffer; src.bytes_in_buffer = isrc.size; src.term_source = stub_source_dec; src.init_source = stub_source_dec; src.skip_input_data = skip_input_data_dec; src.fill_input_buffer = fill_input_buffer_dec; src.resync_to_restart = jpeg_resync_to_restart; jpeg_create_decompress(&cinfo); if (setjmp(sJPEGStruct.setjmpBuffer)) { CPLError(CE_Failure, CPLE_AppDefined, "MRF: Error reading JPEG page"); jpeg_destroy_decompress(&cinfo); return CE_Failure; } cinfo.src = &src; jpeg_set_marker_processor(&cinfo, JPEG_APP0 + 3, MaskProcessor); jpeg_read_header(&cinfo, TRUE); /* In some cases, libjpeg needs to allocate a lot of memory */ /* http://www.libjpeg-turbo.org/pmwiki/uploads/About/TwoIssueswiththeJPEGStandard.pdf */ if( jpeg_has_multiple_scans(&(cinfo)) ) { /* In this case libjpeg will need to allocate memory or backing */ /* store for all coefficients */ /* See call to jinit_d_coef_controller() from master_selection() */ /* in libjpeg */ vsi_l_offset nRequiredMemory = static_cast<vsi_l_offset>(cinfo.image_width) * cinfo.image_height * cinfo.num_components * ((cinfo.data_precision+7)/8); /* BLOCK_SMOOTHING_SUPPORTED is generally defined, so we need */ /* to replicate the logic of jinit_d_coef_controller() */ if( cinfo.progressive_mode ) nRequiredMemory *= 3; #ifndef GDAL_LIBJPEG_LARGEST_MEM_ALLOC #define GDAL_LIBJPEG_LARGEST_MEM_ALLOC (100 * 1024 * 1024) #endif if( nRequiredMemory > GDAL_LIBJPEG_LARGEST_MEM_ALLOC && CPLGetConfigOption("GDAL_ALLOW_LARGE_LIBJPEG_MEM_ALLOC", nullptr) == nullptr ) { CPLError(CE_Failure, CPLE_NotSupported, "Reading this image would require libjpeg to allocate " "at least " CPL_FRMT_GUIB " bytes. " "This is disabled since above the " CPL_FRMT_GUIB " threshold. " "You may override this restriction by defining the " "GDAL_ALLOW_LARGE_LIBJPEG_MEM_ALLOC environment variable, " "or recompile GDAL by defining the " "GDAL_LIBJPEG_LARGEST_MEM_ALLOC macro to a value greater " "than " CPL_FRMT_GUIB, static_cast<GUIntBig>(nRequiredMemory), static_cast<GUIntBig>(GDAL_LIBJPEG_LARGEST_MEM_ALLOC), static_cast<GUIntBig>(GDAL_LIBJPEG_LARGEST_MEM_ALLOC)); jpeg_destroy_decompress(&cinfo); return CE_Failure; } } // Use float, it is actually faster than the ISLOW method by a tiny bit cinfo.dct_method = JDCT_FLOAT; // // Tolerate different input if we can do the conversion // Gray and RGB for example // This also means that a RGB MRF can be read as grayscale and vice versa // If libJPEG can't convert it will throw an error // if (nbands == 3 && cinfo.num_components != nbands) cinfo.out_color_space = JCS_RGB; if (nbands == 1 && cinfo.num_components != nbands) cinfo.out_color_space = JCS_GRAYSCALE; const int datasize = ((cinfo.data_precision == 8) ? 1 : 2); if( cinfo.image_width > static_cast<unsigned>(INT_MAX / (nbands * datasize)) ) { CPLError(CE_Failure, CPLE_AppDefined, "MRF: JPEG decompress buffer overflow"); jpeg_destroy_decompress(&cinfo); return CE_Failure; } int linesize = cinfo.image_width * nbands * datasize; // We have a mismatch between the real and the declared data format // warn and fail if output buffer is too small if (linesize > static_cast<int>(INT_MAX / cinfo.image_height)) { CPLError(CE_Failure, CPLE_AppDefined, "MRF: JPEG decompress buffer overflow"); jpeg_destroy_decompress(&cinfo); return CE_Failure; } if (linesize*cinfo.image_height != dst.size) { CPLError(CE_Warning, CPLE_AppDefined, "MRF: read JPEG size is wrong"); if (linesize*cinfo.image_height > dst.size) { CPLError(CE_Failure, CPLE_AppDefined, "MRF: JPEG decompress buffer overflow"); jpeg_destroy_decompress(&cinfo); return CE_Failure; } } struct jpeg_progress_mgr sJProgress; sJProgress.progress_monitor = ProgressMonitor; cinfo.progress = &sJProgress; jpeg_start_decompress(&cinfo); // Decompress, two lines at a time is what libjpeg does while (cinfo.output_scanline < cinfo.image_height) { char *rp[2]; rp[0] = (char *)dst.buffer + linesize*cinfo.output_scanline; rp[1] = rp[0] + linesize; // if this fails, it calls the error handler // which will report an error if( jpeg_read_scanlines(&cinfo, JSAMPARRAY(rp), 2) == 0 ) { jpeg_destroy_decompress(&cinfo); return CE_Failure; } } jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); // Apply the mask if (datasize == 1) apply_mask(sJPEGStruct, reinterpret_cast<char *>(dst.buffer), img.pagesize.c); else apply_mask(sJPEGStruct, reinterpret_cast<GUInt16 *>(dst.buffer), img.pagesize.c); return CE_None; }
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); /* 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 LoadJPEG(ACanvas *pC, const char *filename, ACanvas *pC1) { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; JDIMENSION l, x, y, num_scanlines; AStdFile file; bool success = false; /* Initialize the JPEG decompression object with default error handling. */ cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); #if 0 /* 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); #endif if (file.open(filename, "rb")) { /* Specify data source for decompression */ jpeg_stdio_src(&cinfo, file.GetFile()); /* Read file header, set default decompression parameters */ (void) jpeg_read_header(&cinfo, true); jpeg_start_decompress(&cinfo); if (!pC->Valid() || (pC->GetWidth() != (sint_t)cinfo.output_width) || (pC->GetHeight() != (sint_t)cinfo.output_height)) { pC->Delete(); pC->CreateCompatibleDC(pC1); pC->CreateCompatibleBitmap(pC1, cinfo.output_width, cinfo.output_height); } if (pC->Valid()) { JSAMPLE *buffer; if ((buffer = new JSAMPLE[cinfo.output_width * cinfo.output_components]) != NULL) { success = true; y = 0; /* Process data */ while (cinfo.output_scanline < cinfo.output_height) { num_scanlines = jpeg_read_scanlines(&cinfo, &buffer, 1); if (cinfo.output_components == 1) { for (l = 0; l < num_scanlines; l++, y++) { for (x = 0; x < cinfo.output_width; x++) { pC->SetPixelV(x, y, AColour(buffer[x], buffer[x], buffer[x])); } } } else if (cinfo.output_components == 3) { for (l = 0; l < num_scanlines; l++, y++) { for (x = 0; x < cinfo.output_width; x++) { pC->SetPixelV(x, y, AColour(buffer[x * 3], buffer[x * 3 + 1], buffer[x * 3 + 2])); } } } else { success = false; break; } } delete[] buffer; } /* Finish decompression and release memory. * Must do it in this order because output module has allocated memory * of lifespan JPOOL_IMAGE; it needs to finish before releasing memory. */ (void) jpeg_finish_decompress(&cinfo); } file.close(); } jpeg_destroy_decompress(&cinfo); return success; }