DTerr ImporterImageJPG::import(const FilePath &pathname, const std::string &args, DTuint &width, DTuint &height, std::shared_ptr<DTubyte> &data, DT3GLTextelFormat &format) { // // The following is based on the libpng manual. http://www.libpng.org/pub/png/libpng-1.2.5-manual.html#section-3.1 // // // Check the file header // // open the file BinaryFileStream file; DTerr err; if ((err = FileManager::open(file, pathname, true)) != DT3_ERR_NONE) return err; // This struct contains the JPEG decompression parameters and pointers to // working space (which is allocated as needed by the JPEG library). jpeg_decompress_struct cinfo; ImportSource csrc; // 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. ImportErr jerr; cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = ImporterImageJPG::error_handler; // 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); file.close(); return DT3_ERR_FILE_WRONG_TYPE; } // Now we can initialize the JPEG decompression object. jpeg_create_decompress(&cinfo); cinfo.src = (jpeg_source_mgr*) &csrc; // Step 2: specify data source (eg, a file) jpeg_stream_src(&cinfo, file); // Step 3: read file parameters with jpeg_read_header() jpeg_read_header(&cinfo, TRUE); // 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 jpeg_start_decompress(&cinfo); ASSERT(cinfo.out_color_components == 3 && cinfo.data_precision == 8); // Build a buffer for reading in the image width = cinfo.output_width; height = cinfo.output_height; format = DT3GL_FORMAT_RGB; // Change data format to 16 bit data = std::shared_ptr<DTubyte>(new DTubyte[width * height * 3]); DTubyte *buffer = data.get(); DTint row_stride = cinfo.output_width * cinfo.output_components; // Make a one-row-high sample array that will go away when done with image JSAMPARRAY scanline_buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); // Step 6: while (scan lines remain to be read) // 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. jpeg_read_scanlines(&cinfo, scanline_buffer, 1); // Copy Row into buffer DTubyte *src_data = (DTubyte*) scanline_buffer[0]; DTubyte *dst_data = (DTubyte*) &buffer[width * (height - cinfo.output_scanline) * 3]; // Copy row ::memcpy(dst_data, src_data, row_stride); } // 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); //#endif return DT3_ERR_NONE; }
/****************************************************************************** * * Function jpeg_to_ximage * * This routine converts compressed jpeg data associated with a _DtGrStream * into an XImage. * * No X color allocation is done. The image is quantized down to MAX_COLORS * during decompression, and an array of XColor structures with the red, * green, and blue fields initialized to the colors used in the image is * returned to the caller. Each pixel value in the XImage data is an index * into this array. The caller must use this information to allocate X * color cells and substitute the appropriate pixel values into the XImage * data array before using the XImage. * * The routine makes use of a custom source data manager to allow the JPEG * data source to be a _DtGrStream, a custom data destination manager to * allow the decompressed and post-processed data to be written to an XImage, * and a custom error handler to allow standard _DtGr error codes to be * returned to the caller in the event of a JPEG library error. * *****************************************************************************/ enum _DtGrLoadStatus jpeg_to_ximage ( _DtGrStream *stream, Screen *screen, Visual *visual, Dimension *in_out_width, Dimension *in_out_height, XImage **ximage, XColor **xcolors, int *ncolors, int *xres) { struct jpeg_decompress_struct cinfo; struct my_error_mgr jerr; djpeg_dest_ptr dest_mgr = NULL; ximg_dest_ptr dest; int i, num_scanlines, nullCount, ximWidth; unsigned char *ximData = NULL; Display *display = DisplayOfScreen(screen); int nplanes = DisplayPlanes(display,XScreenNumberOfScreen(screen)); XColor *colors = NULL; /* ** Initialize the return values */ *ximage = NULL; *xres = *ncolors = *in_out_width = *in_out_height = 0; /* ** Initialize the jpeg library error handler with our custom routines */ cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = my_error_exit; jerr.pub.output_message = my_output_message; /* ** 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 ** free memory, clean up the JPEG object, and return a failure code. */ if (*ximage != NULL) XDestroyImage (*ximage); if (colors != NULL) free (colors); jpeg_destroy_decompress(&cinfo); return (_DtGrCONVERT_FAILURE); } /* ** Create a jpeg decompression object */ jpeg_create_decompress(&cinfo); /* ** Create a custom source data manager */ jpeg_stream_src(&cinfo, stream); /* ** Read the jpeg header */ jpeg_read_header(&cinfo, TRUE); if (cinfo.X_density > 0 && (cinfo.density_unit == 1 || cinfo.density_unit == 2)) { if (cinfo.density_unit == 1) *xres = cinfo.X_density; else *xres = cinfo.X_density * 2.54 + 0.5; } /* ** Initialize our desired post-processing attributes */ cinfo.quantize_colors = TRUE; cinfo.desired_number_of_colors = MAX_COLORS; /* ** Create a custom data destination manager to allow our processed data ** to be channeled into an XImage. */ dest_mgr = init_jpeg_dest_mgr(&cinfo); /* ** Initialize the decompression state */ jpeg_start_decompress(&cinfo); (*dest_mgr->start_output) (&cinfo, dest_mgr); /* ** Create an XImage to hold the processed data */ nullCount = (4 - (cinfo.output_width % 4)) & 0x03; ximWidth = cinfo.output_width + nullCount; if (nplanes > 8 ) ximData = (unsigned char *) malloc(ximWidth * cinfo.output_height * 4 ); else ximData = (unsigned char *) malloc(ximWidth * cinfo.output_height ); if (!ximData) { jpeg_destroy_decompress(&cinfo); return (_DtGrNO_MEMORY); } *ximage = XCreateImage(display, visual, nplanes, (nplanes == 1) ? XYPixmap : ZPixmap, 0, (char *)ximData, cinfo.output_width, cinfo.output_height, 32, 0); if (!*ximage) { free (ximData); jpeg_destroy_decompress(&cinfo); return (_DtGrCONVERT_FAILURE); } /* ** Store the XImage in the custom destination manager */ dest = (ximg_dest_ptr) dest_mgr; dest->ximage = *ximage; /* ** Process scanlines until there are none left */ while (cinfo.output_scanline < cinfo.output_height) { num_scanlines = jpeg_read_scanlines(&cinfo, (JSAMPARRAY)dest_mgr->buffer, dest_mgr->buffer_height); (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); } /* ** Return the colormap info as an array of XColors which can be ** used later for X color allocation purposes. */ if (cinfo.actual_number_of_colors) { colors = (XColor *) malloc((unsigned) sizeof(XColor) * cinfo.actual_number_of_colors); if (!colors) { XDestroyImage (*ximage); jpeg_destroy_decompress(&cinfo); return (_DtGrNO_MEMORY); } for (i=0; i<cinfo.actual_number_of_colors; i++) { if (cinfo.out_color_space == JCS_GRAYSCALE) { colors[i].red = colors[i].green = colors[i].blue = INTERP_TO_XCOLORSPACE(cinfo.colormap[0][i]); } else /* JCS_RGB */ { colors[i].red = INTERP_TO_XCOLORSPACE(cinfo.colormap[0][i]); colors[i].green = INTERP_TO_XCOLORSPACE(cinfo.colormap[1][i]); colors[i].blue = INTERP_TO_XCOLORSPACE(cinfo.colormap[2][i]); } } *xcolors = colors; *ncolors = cinfo.actual_number_of_colors; } /* ** Set the other return parameters */ *in_out_width = cinfo.output_width; *in_out_height = cinfo.output_height; /* ** Shut down the decompression engine and free the allocated memory */ (*dest_mgr->finish_output) (&cinfo, dest_mgr); jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); /* ** Return success */ return (_DtGrSUCCESS); }
image_t* image_load_jpg(image_t* x, stream_t* stream) { image_t* im; TRACE1 ("loading jpeg file"); if (!stream) { im = NULL; } else { int load; im = image_instantiate_toplevel (x); struct jpeg_decompress_struct cinfo; myerror_mgr errmgr; errmgr.im = im; errmgr.image_is_owned_p = (im != x); if (setjmp (errmgr.env)) { jpeg_destroy_decompress(&cinfo); // coming back from an error return NULL; } /* insert here useless error test */ /* jpeg object initialisation */ jpeg_create_decompress (&cinfo); /* specify data source */ jpeg_stream_src (&cinfo, stream); /* standard error */ cinfo.err = jpeg_std_error (&errmgr.super); errmgr.super.error_exit = image_load_jpeg_error_exit; if (jpeg_read_header(&cinfo, TRUE) != JPEG_HEADER_OK) { return NULL; } if (jpeg_start_decompress(&cinfo) < 0) { return NULL; } if (!cinfo.output_width || !cinfo.output_height) { WARNING1("null size image."); return NULL; } image_new(im, cinfo.output_width, cinfo.output_height, cinfo.output_width); switch (cinfo.output_components) { case 1: /* GRAY */ load = 1; break; case 3: // RGB load = 1; break; default: /* don't know how to load that */ image_destroy (im); if(im != x) { image_retire (im); } im = NULL; load = 0; } if (load) { JSAMPARRAY scanline_buf; scanline_buf = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, cinfo.output_width * cinfo.output_components, cinfo.rec_outbuf_height); while (cinfo.output_scanline < cinfo.output_height) { int n; uint32_t* dest = im->pixels + im->pitch * cinfo.output_scanline; n = jpeg_read_scanlines(&cinfo, scanline_buf, cinfo.rec_outbuf_height); int s; for (s = 0; s < n; s++) { unsigned char* scanline = scanline_buf [s]; /* copy to image */ int i; for (i = 0; i < im->width; i++) { if(cinfo.output_components == 1) { dest[i] = 0xff000000 | (scanline[i] << 16) | (scanline[i] << 8) | (scanline[i]); } else if(cinfo.output_components == 3) { #if (BYTE_ORDER == LITTLE_ENDIAN && defined (PIXEL_RGBA8888)) || \ (BYTE_ORDER == BIG_ENDIAN && defined (PIXEL_BGRA8888)) dest[i] = 0xff000000 | (scanline [3*i + 0] << 16) | (scanline [3*i + 1] << 8) | (scanline [3*i + 2] << 0); #else /*dest[i] = 0xff000000 | //alpha (scanline [3*i + 2] << 0) | (scanline [3*i + 1] << 8) | (scanline [3*i + 2] << 16); */ dest[i] = 0xff000000 | // alpha (scanline [3 * i + 0] << 0) | // r (scanline [3 * i + 1] << 8) | // g (scanline [3 * i + 2] << 16); // b #endif } } dest += im->pitch; } } } jpeg_finish_decompress(&cinfo); } return im; }