static gpointer gdk_pixbuf__jpeg_image_begin_load (GdkPixbufModuleSizeFunc size_func, GdkPixbufModulePreparedFunc prepared_func, GdkPixbufModuleUpdatedFunc updated_func, gpointer user_data, GError **error) { JpegProgContext *context; my_source_mgr *src; context = g_new0 (JpegProgContext, 1); context->size_func = size_func; context->prepared_func = prepared_func; context->updated_func = updated_func; context->user_data = user_data; context->pixbuf = NULL; context->got_header = FALSE; context->did_prescan = FALSE; context->src_initialized = FALSE; context->in_output = FALSE; /* From jpeglib.h: "NB: you must set up the error-manager * BEFORE calling jpeg_create_xxx". */ context->cinfo.err = jpeg_std_error (&context->jerr.pub); context->jerr.pub.error_exit = fatal_error_handler; context->jerr.pub.output_message = output_message_handler; context->jerr.error = error; if (sigsetjmp (context->jerr.setjmp_buffer, 1)) { jpeg_destroy_decompress (&context->cinfo); g_free(context); /* error should have been set by fatal_error_handler () */ return NULL; } /* create libjpeg structures */ jpeg_create_decompress (&context->cinfo); context->cinfo.src = (struct jpeg_source_mgr *) g_try_malloc (sizeof (my_source_mgr)); if (!context->cinfo.src) { g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, _("Couldn't allocate memory for loading JPEG file")); return NULL; } memset (context->cinfo.src, 0, sizeof (my_source_mgr)); src = (my_src_ptr) context->cinfo.src; src->pub.init_source = init_source; src->pub.fill_input_buffer = fill_input_buffer; src->pub.skip_input_data = skip_input_data; src->pub.resync_to_restart = jpeg_resync_to_restart; src->pub.term_source = term_source; src->pub.bytes_in_buffer = 0; src->pub.next_input_byte = NULL; context->jerr.error = NULL; return (gpointer) context; }
/* ================= SaveJPGToBuffer Encodes JPEG from image in image_buffer and writes to buffer. Expects RGB input data ================= */ size_t RE_SaveJPGToBuffer(byte *buffer, size_t bufSize, int quality, int image_width, int image_height, byte *image_buffer, int padding) { struct jpeg_compress_struct cinfo; q_jpeg_error_mgr_t jerr; JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ my_dest_ptr dest; int row_stride; /* physical row width in image buffer */ size_t outcount; /* Step 1: allocate and initialize JPEG compression object */ cinfo.err = jpeg_std_error(&jerr.pub); cinfo.err->error_exit = R_JPGErrorExit; cinfo.err->output_message = R_JPGOutputMessage; /* Establish the setjmp return context for R_JPGErrorExit 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 and return. */ jpeg_destroy_compress(&cinfo); ri.Printf(PRINT_ALL, "\n"); return 0; } /* Now we can initialize the JPEG compression object. */ jpeg_create_compress(&cinfo); /* Step 2: specify data destination (eg, a file) */ /* Note: steps 2 and 3 can be done in either order. */ jpegDest(&cinfo, buffer, bufSize); /* Step 3: set parameters for compression */ cinfo.image_width = image_width; /* image width and height, in pixels */ cinfo.image_height = image_height; cinfo.input_components = 3; /* # of color components per pixel */ cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); /* If quality is set high, disable chroma subsampling */ if (quality >= 85) { cinfo.comp_info[0].h_samp_factor = 1; cinfo.comp_info[0].v_samp_factor = 1; } /* Step 4: Start compressor */ jpeg_start_compress(&cinfo, TRUE); /* Step 5: while (scan lines remain to be written) */ /* jpeg_write_scanlines(...); */ row_stride = image_width * cinfo.input_components + padding; /* JSAMPLEs per row in image_buffer */ while (cinfo.next_scanline < cinfo.image_height) { /* jpeg_write_scanlines expects an array of pointers to scanlines. * Here the array is only one element long, but you could pass * more than one scanline at a time if that's more convenient. */ row_pointer[0] = &image_buffer[((cinfo.image_height-1)*row_stride)-cinfo.next_scanline * row_stride]; (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); } /* Step 6: Finish compression */ jpeg_finish_compress(&cinfo); dest = (my_dest_ptr) cinfo.dest; outcount = dest->size - dest->pub.free_in_buffer; /* Step 7: release JPEG compression object */ jpeg_destroy_compress(&cinfo); /* And we're done! */ return outcount; }
/* Shared library entry point */ static GdkPixbuf * gdk_pixbuf__jpeg_image_load (FILE *f, GError **error) { gint i; char otag_str[5]; GdkPixbuf * volatile pixbuf = NULL; guchar *dptr; guchar *lines[4]; /* Used to expand rows, via rec_outbuf_height, * from the header file: * " Usually rec_outbuf_height will be 1 or 2, * at most 4." */ guchar **lptr; struct jpeg_decompress_struct cinfo; struct error_handler_data jerr; stdio_src_ptr src; gchar *icc_profile_base64; JpegExifContext *exif_context; /* setup error handler */ cinfo.err = jpeg_std_error (&jerr.pub); jerr.pub.error_exit = fatal_error_handler; jerr.pub.output_message = output_message_handler; jerr.error = error; if (sigsetjmp (jerr.setjmp_buffer, 1)) { /* Whoops there was a jpeg error */ if (pixbuf) g_object_unref (pixbuf); jpeg_destroy_decompress (&cinfo); /* error should have been set by fatal_error_handler () */ return NULL; } /* load header, setup */ jpeg_create_decompress (&cinfo); cinfo.src = (struct jpeg_source_mgr *) (*cinfo.mem->alloc_small) ((j_common_ptr) &cinfo, JPOOL_PERMANENT, sizeof (stdio_source_mgr)); src = (stdio_src_ptr) cinfo.src; src->buffer = (JOCTET *) (*cinfo.mem->alloc_small) ((j_common_ptr) &cinfo, JPOOL_PERMANENT, JPEG_PROG_BUF_SIZE * sizeof (JOCTET)); src->pub.init_source = stdio_init_source; src->pub.fill_input_buffer = stdio_fill_input_buffer; src->pub.skip_input_data = stdio_skip_input_data; src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ src->pub.term_source = stdio_term_source; src->infile = f; src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ src->pub.next_input_byte = NULL; /* until buffer loaded */ jpeg_save_markers (&cinfo, JPEG_APP0+1, 0xffff); jpeg_save_markers (&cinfo, JPEG_APP0+2, 0xffff); jpeg_read_header (&cinfo, TRUE); /* parse exif data */ exif_context = g_new0 (JpegExifContext, 1); jpeg_parse_exif (exif_context, &cinfo); jpeg_start_decompress (&cinfo); cinfo.do_fancy_upsampling = FALSE; cinfo.do_block_smoothing = FALSE; pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, cinfo.out_color_components == 4 ? TRUE : FALSE, 8, cinfo.output_width, cinfo.output_height); if (!pixbuf) { jpeg_destroy_decompress (&cinfo); /* broken check for *error == NULL for robustness against * crappy JPEG library */ if (error && *error == NULL) { g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, _("Insufficient memory to load image, try exiting some applications to free memory")); } return NULL; } /* if orientation tag was found */ if (exif_context->orientation != 0) { g_snprintf (otag_str, sizeof (otag_str), "%d", exif_context->orientation); gdk_pixbuf_set_option (pixbuf, "orientation", otag_str); } /* if icc profile was found */ if (exif_context->icc_profile != NULL) { icc_profile_base64 = g_base64_encode ((const guchar *) exif_context->icc_profile, exif_context->icc_profile_size); gdk_pixbuf_set_option (pixbuf, "icc-profile", icc_profile_base64); g_free (icc_profile_base64); } dptr = pixbuf->pixels; /* decompress all the lines, a few at a time */ while (cinfo.output_scanline < cinfo.output_height) { lptr = lines; for (i = 0; i < cinfo.rec_outbuf_height; i++) { *lptr++ = dptr; dptr += pixbuf->rowstride; } jpeg_read_scanlines (&cinfo, lines, cinfo.rec_outbuf_height); switch (cinfo.out_color_space) { case JCS_GRAYSCALE: explode_gray_into_buf (&cinfo, lines); break; case JCS_RGB: /* do nothing */ break; case JCS_CMYK: convert_cmyk_to_rgb (&cinfo, lines); break; default: g_object_unref (pixbuf); if (error && *error == NULL) { g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_UNKNOWN_TYPE, _("Unsupported JPEG color space (%s)"), colorspace_name (cinfo.out_color_space)); } jpeg_destroy_decompress (&cinfo); return NULL; } } jpeg_finish_decompress (&cinfo); jpeg_destroy_decompress (&cinfo); jpeg_destroy_exif_context (exif_context); return pixbuf; }
static int jpeg_image_control(ErlDrvData handle, unsigned int command, char* buf, int count, char** res, int res_size) { JSAMPROW row; ErlDrvBinary* bin = 0; switch (command) { case 0: { /* Read */ struct jpeg_decompress_struct cinfo; int row_stride; /* physical row width in output buffer */ unsigned char* rbuf; struct my_error_mgr jerr; 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. */ char buffer[JMSG_LENGTH_MAX]; /* Create the message */ (cinfo.err->format_message)((j_common_ptr) &cinfo, buffer); jpeg_destroy_decompress(&cinfo); bin = driver_alloc_binary(4+strlen(buffer)); rbuf = bin->orig_bytes; ((unsigned *)rbuf)[0] = 0; rbuf += 4; memcpy(rbuf, buffer, strlen(buffer)); *res = (void *) bin; return 0; } jpeg_create_decompress(&cinfo); jpeg_buffer_src(&cinfo, buf, count); (void) jpeg_read_header(&cinfo, TRUE); (void) jpeg_start_decompress(&cinfo); row_stride = cinfo.output_width * cinfo.output_components; res_size = row_stride * cinfo.output_height; bin = driver_alloc_binary(res_size+12); rbuf = bin->orig_bytes; ((unsigned *)rbuf)[0] = cinfo.output_width; ((unsigned *)rbuf)[1] = cinfo.output_height; ((unsigned *)rbuf)[2] = cinfo.output_components; rbuf += 12; while (cinfo.output_scanline < cinfo.output_height) { row = (JSAMPROW) rbuf; (void) jpeg_read_scanlines(&cinfo, &row, 1); rbuf += row_stride; } (void) jpeg_finish_decompress(&cinfo); *res = (void *) bin; return 0; } case 1: { /* Write */ struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; int row_stride; /* physical row width */ bin = driver_alloc_binary(count); cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpeg_buffer_dest(&cinfo, bin); cinfo.image_width = ((unsigned *)buf)[0]; cinfo.image_height = ((unsigned *)buf)[1]; cinfo.input_components = ((unsigned *)buf)[2]; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&cinfo); buf += 12; count -= 12; jpeg_start_compress(&cinfo, TRUE); row_stride = cinfo.input_components * cinfo.image_width; while (cinfo.next_scanline < cinfo.image_height) { row = (JSAMPROW) buf; (void) jpeg_write_scanlines(&cinfo, &row, 1); buf += row_stride; } jpeg_finish_compress(&cinfo); bin = jpeg_buffer_dest_get_bin(&cinfo); jpeg_destroy_compress(&cinfo); *res = (void *) bin; return 0; } default: return -1; /* Error return, throws exception in erlang */ } }
u_char *decode_jpeg (const char *file_name, fb_info *jpeg_inf) { register JSAMPARRAY lineBuf; struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr err_mgr; int bytesPerPix; FILE *inFile; u_char *retBuf; FILE * f; jpeg_file = open(file_name, O_RDONLY); if (NULL == jpeg_file) { fprintf (stderr, "Error Open %s: %s\n", filename, strerror(errno)); return NULL; } cinfo.err = jpeg_std_error (&err_mgr); err_mgr.error_exit = jpeg_error_exit; jpeg_create_decompress (&cinfo); jpeg_stdio_src (&cinfo, inFile); jpeg_read_header (&cinfo, 1); cinfo.do_fancy_upsampling = 0; cinfo.do_block_smoothing = 0; jpeg_start_decompress (&cinfo); /* 2010.2.6 and some... */ jpeg_inf->w = cinfo.output_width; jpeg_inf->h = cinfo.output_height; short w,h; short *widthPtr = &w; short *heightPtr = &h; w = jpeg_inf->w; h = jpeg_inf->h; bytesPerPix = cinfo.output_components; lineBuf = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE, (*widthPtr * bytesPerPix), 1); retBuf = (u_char *) malloc (3 * (*widthPtr * *heightPtr)); if (NULL == retBuf) { perror (NULL); return NULL; } if (3 == bytesPerPix) { int y; for (y = 0; y < cinfo.output_height; ++y) { jpeg_read_scanlines (&cinfo, lineBuf, 1); memcpy ((retBuf + y * *widthPtr * 3),lineBuf[0],3 * *widthPtr); } } else if (1 == bytesPerPix) { unsigned int col; int lineOffset = (*widthPtr * 3); int lineBufIndex; int x ; int y; for (y = 0; y < cinfo.output_height; ++y) { jpeg_read_scanlines (&cinfo, lineBuf, 1); lineBufIndex = 0; for (x = 0; x < lineOffset; ++x) { col = lineBuf[0][lineBufIndex]; retBuf[(lineOffset * y) + x] = col; ++x; retBuf[(lineOffset * y) + x] = col; ++x; retBuf[(lineOffset * y) + x] = col; ++lineBufIndex; } } } else { fprintf (stderr, "Error: the number of color channels is %d. This program only handles 1 or 3\n", bytesPerPix); return NULL; } jpeg_finish_decompress (&cinfo); jpeg_destroy_decompress (&cinfo); fclose (inFile); return retBuf; }
//! creates a surface from the file IImage* CImageLoaderJPG::loadImage(irr::io::IReadFile* file) { #ifndef _IRR_COMPILE_WITH_LIBJPEG_ return 0; #else u8 **rowPtr=0; u8* input = new u8[file->getSize()]; file->read(input, file->getSize()); // allocate and initialize JPEG decompression object struct jpeg_decompress_struct cinfo; struct irr_jpeg_error_mgr jerr; //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.pub); cinfo.err->error_exit = error_exit; cinfo.err->output_message = output_message; // compatibility fudge: // we need to use setjmp/longjmp for error handling as gcc-linux // crashes when throwing within external c code if (setjmp(jerr.setjmp_buffer)) { // If we get here, the JPEG code has signaled an error. // We need to clean up the JPEG object and return. jpeg_destroy_decompress(&cinfo); delete [] input; // if the row pointer was created, we delete it. if (rowPtr) delete [] rowPtr; // return null pointer return 0; } // Now we can initialize the JPEG decompression object. jpeg_create_decompress(&cinfo); // specify data source jpeg_source_mgr jsrc; // Set up data pointer jsrc.bytes_in_buffer = file->getSize(); jsrc.next_input_byte = (JOCTET*)input; cinfo.src = &jsrc; jsrc.init_source = init_source; jsrc.fill_input_buffer = fill_input_buffer; jsrc.skip_input_data = skip_input_data; jsrc.resync_to_restart = jpeg_resync_to_restart; jsrc.term_source = term_source; // Decodes JPG input from whatever source // Does everything AFTER jpeg_create_decompress // and BEFORE jpeg_destroy_decompress // Caller is responsible for arranging these + setting up cinfo // read file parameters with jpeg_read_header() jpeg_read_header(&cinfo, TRUE); cinfo.out_color_space=JCS_RGB; cinfo.out_color_components=3; cinfo.do_fancy_upsampling=FALSE; // Start decompressor jpeg_start_decompress(&cinfo); // Get image data u16 rowspan = cinfo.image_width * cinfo.out_color_components; u32 width = cinfo.image_width; u32 height = cinfo.image_height; // Allocate memory for buffer u8* output = new u8[rowspan * height]; // 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. // Create array of row pointers for lib rowPtr = new u8* [height]; for( u32 i = 0; i < height; i++ ) rowPtr[i] = &output[ i * rowspan ]; u32 rowsRead = 0; while( cinfo.output_scanline < cinfo.output_height ) rowsRead += jpeg_read_scanlines( &cinfo, &rowPtr[rowsRead], cinfo.output_height - rowsRead ); delete [] rowPtr; // Finish decompression jpeg_finish_decompress(&cinfo); // Release JPEG decompression object // This is an important step since it will release a good deal of memory. jpeg_destroy_decompress(&cinfo); // convert image IImage* image = new CImage(ECF_R8G8B8, core::dimension2d<s32>(width, height), output); delete [] input; return image; #endif }
int write_image(dt_imageio_module_data_t *jpg_tmp, const char *filename, const void *in_tmp, void *exif, int exif_len, int imgid) { dt_imageio_jpeg_t *jpg = (dt_imageio_jpeg_t *)jpg_tmp; const uint8_t *in = (const uint8_t *)in_tmp; struct dt_imageio_jpeg_error_mgr jerr; jpg->cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = dt_imageio_jpeg_error_exit; if(setjmp(jerr.setjmp_buffer)) { jpeg_destroy_compress(&(jpg->cinfo)); return 1; } jpeg_create_compress(&(jpg->cinfo)); FILE *f = fopen(filename, "wb"); if(!f) return 1; jpeg_stdio_dest(&(jpg->cinfo), f); jpg->cinfo.image_width = jpg->width; jpg->cinfo.image_height = jpg->height; jpg->cinfo.input_components = 3; jpg->cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&(jpg->cinfo)); jpeg_set_quality(&(jpg->cinfo), jpg->quality, TRUE); if(jpg->quality > 90) jpg->cinfo.comp_info[0].v_samp_factor = 1; if(jpg->quality > 92) jpg->cinfo.comp_info[0].h_samp_factor = 1; if(jpg->quality > 95) jpg->cinfo.dct_method = JDCT_FLOAT; if(jpg->quality < 50) jpg->cinfo.dct_method = JDCT_IFAST; if(jpg->quality < 80) jpg->cinfo.smoothing_factor = 20; if(jpg->quality < 60) jpg->cinfo.smoothing_factor = 40; if(jpg->quality < 40) jpg->cinfo.smoothing_factor = 60; jpg->cinfo.optimize_coding = 1; // according to specs density_unit = 0, X_density = 1, Y_density = 1 should be fine and valid since it // describes an image with unknown unit and square pixels. // however, some applications (like the Telekom cloud thingy) seem to be confused by that, so let's set // these calues to the same as stored in exiv :/ int resolution = dt_conf_get_int("metadata/resolution"); if(resolution > 0) { jpg->cinfo.density_unit = 1; jpg->cinfo.X_density = resolution; jpg->cinfo.Y_density = resolution; } else { jpg->cinfo.density_unit = 0; jpg->cinfo.X_density = 1; jpg->cinfo.Y_density = 1; } jpeg_start_compress(&(jpg->cinfo), TRUE); if(imgid > 0) { cmsHPROFILE out_profile = dt_colorspaces_create_output_profile(imgid); uint32_t len = 0; cmsSaveProfileToMem(out_profile, 0, &len); if(len > 0) { unsigned char buf[len]; cmsSaveProfileToMem(out_profile, buf, &len); write_icc_profile(&(jpg->cinfo), buf, len); } dt_colorspaces_cleanup_profile(out_profile); } if(exif && exif_len > 0 && exif_len < 65534) jpeg_write_marker(&(jpg->cinfo), JPEG_APP0 + 1, exif, exif_len); uint8_t row[3 * jpg->width]; const uint8_t *buf; while(jpg->cinfo.next_scanline < jpg->cinfo.image_height) { JSAMPROW tmp[1]; buf = in + (size_t)jpg->cinfo.next_scanline * jpg->cinfo.image_width * 4; for(int i = 0; i < jpg->width; i++) for(int k = 0; k < 3; k++) row[3 * i + k] = buf[4 * i + k]; tmp[0] = row; jpeg_write_scanlines(&(jpg->cinfo), tmp, 1); } jpeg_finish_compress(&(jpg->cinfo)); jpeg_destroy_compress(&(jpg->cinfo)); fclose(f); return 0; }
res_gltex_cache_t * Res_CacheInGLTEX_jpg( res_gltex_register_t *reg ) { struct jpeg_decompress_struct cinfo; ib_file_t *h; unsigned char *buffer; int row_stride; struct my_error_mgr jerr; FILE *b; int pixels; unsigned char *image, *ptr; res_gltex_cache_t *gltex; h = IB_Open( reg->path ); // b = fopen( "test.jpg", "rb" ); if( !h ) { __error( "load of '%s' failed\n", reg->path ); } // memset( &cinfo, 0, sizeof( struct jpeg_decompress_struct )); cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = jpeg_error_exit; if (setjmp (jerr.setjmp_buffer)) { jpeg_destroy_decompress (&cinfo); if( h ) IB_Close( h ); __error( "XJT: JPEG load error\n"); } printf( "%p\n", cinfo.err ); // step 1 jpeg_create_decompress(&cinfo); // cinfo.err = jpeg_std_error (&jerr.pub); // printf( "%p\n", cinfo.err ); // step 2 jpeg_ibase_src(&cinfo, h); // jpeg_stdio_src( &cinfo, b ); // printf( "back\n" ); // step 3 jpeg_read_header(&cinfo, TRUE); /* if( cinfo.jpeg_color_space != JCS_RGB ) { __error( "colorspace is not RGB\n" ); } */ jpeg_start_decompress( &cinfo ); // printf( "jpeg: %d %d %d\n", cinfo.image_width, cinfo.image_height, cinfo.output_components ); if( cinfo.output_components != 3 ) { __error( "jpeg file '%s' is not RGB\n", reg->path ); } pixels = cinfo.output_width * cinfo.output_height; image = MM_Malloc( pixels * 3 ); row_stride = cinfo.output_width * 3; ptr = image + ( row_stride * (cinfo.output_height - 1) ); buffer = alloca( row_stride ); // printf( "row_stride: %d\n", row_stride ); while( cinfo.output_scanline < cinfo.output_height ) { // __named_message( "%d\n", cinfo.output_scanline ); jpeg_read_scanlines( &cinfo, &buffer, 1 ); memcpy( ptr, buffer, row_stride ); ptr -= row_stride; } // memset( image, 0, pixels *3 ); jpeg_finish_decompress( &cinfo ); jpeg_destroy_decompress( &cinfo ); IB_Close( h ); gltex = NEWTYPE( res_gltex_cache_t ); gltex->width = cinfo.output_width; gltex->height = cinfo.output_height; __message( "%s: %d %d\n", reg->path, gltex->width, gltex->height ); gltex->comp = resGltexComponents_rgb; Res_CreateGLTEX_rgb( cinfo.output_width, cinfo.output_height, image ); // __error( "good\n" ); return gltex; }
LOGICAL JpgImageFile( Image image, uint8_t **buf, size_t *size, int Q ) { /* This struct contains the JPEG compression parameters and pointers to * working space (which is allocated as needed by the JPEG library). * It is possible to have several such structures, representing multiple * compression/decompression processes, in existence at once. We refer * to any one struct (and its associated working data) as a "JPEG object". */ struct jpeg_compress_struct cinfo; /* 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; unsigned char *outbuf; unsigned long outsize; /* More stuff */ uint8_t* tmpbuf = NewArray( uint8_t, image->width * image->height * 3 ); JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ int row_stride; /* physical row width in image buffer */ { int n; int m = image->pwidth * image->height; uint8_t* in = (uint8_t*)image->image; uint8_t* out = tmpbuf; for( n = 0; n < m; n++ ) { if( bGLColorMode ) { out[0] = (*in++); out[1] = (*in++); out[2] = (*in++); } else { out[2] = (*in++); out[1] = (*in++); out[0] = (*in++); } (*in++); out += 3; } } /* Step 1: allocate and initialize JPEG compression 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 compression object. */ jpeg_create_compress(&cinfo); /* Step 2: specify data destination (eg, a file) */ /* Note: steps 2 and 3 can be done in either order. */ /* Here we use the library-supplied code to send compressed data to a * stdio stream. You can also write your own code to do something else. * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that * requires it in order to write binary files. */ //jpeg_stdio_dest(&cinfo, outfile); outbuf = NULL; outsize = 0; jpeg_mem_dest( &cinfo, &outbuf, &outsize ); /* Step 3: set parameters for compression */ /* First we supply a description of the input image. * Four fields of the cinfo struct must be filled in: */ cinfo.image_width = image->width; /* image width and height, in pixels */ cinfo.image_height = image->height; cinfo.input_components = 3; /* # of color components per pixel */ cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ /* Now use the library's routine to set default compression parameters. * (You must set at least cinfo.in_color_space before calling this, * since the defaults depend on the source color space.) */ jpeg_set_defaults(&cinfo); /* Now you can set any non-default parameters you wish to. * Here we just illustrate the use of quality (quantization table) scaling: */ jpeg_set_quality(&cinfo, Q, TRUE /* limit to baseline-JPEG values */); /* Step 4: Start compressor */ /* TRUE ensures that we will write a complete interchange-JPEG file. * Pass TRUE unless you are very sure of what you're doing. */ jpeg_start_compress(&cinfo, TRUE); /* Step 5: while (scan lines remain to be written) */ /* jpeg_write_scanlines(...); */ /* Here we use the library's state variable cinfo.next_scanline as the * loop counter, so that we don't have to keep track ourselves. * To keep things simple, we pass one scanline per call; you can pass * more if you wish, though. */ row_stride = image->pwidth * 3; /* JSAMPLEs per row in image_buffer */ while (cinfo.next_scanline < cinfo.image_height) { /* jpeg_write_scanlines expects an array of pointers to scanlines. * Here the array is only one element long, but you could pass * more than one scanline at a time if that's more convenient. */ row_pointer[0] = & tmpbuf[cinfo.next_scanline * row_stride]; (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); } /* Step 6: Finish compression */ jpeg_finish_compress(&cinfo); /* After finish_compress, we can close the output file. */ //fclose(outfile); Deallocate( uint8_t*, tmpbuf ); /* Step 7: release JPEG compression object */ (*buf) = outbuf; (*size) = outsize; /* This is an important step since it will release a good deal of memory. */ jpeg_destroy_compress(&cinfo); return TRUE; /* And we're done! */ }
int main(int argc, char *argv[]) { int quality = 75; if (argc == 2) { quality = atoi(argv[1]); if (quality < 10 || quality > 100) { fprintf(stderr, "invalid quality. must be between 10 and 100\n"); return 1; } } bcm_host_init(); uint32_t screen = 0; DISPMANX_DISPLAY_HANDLE_T display = vc_dispmanx_display_open(screen); DISPMANX_MODEINFO_T info; int ret = vc_dispmanx_display_get_info(display, &info); assert(ret == 0); /* DispmanX expects buffer rows to be aligned to a 32 bit boundary */ int pitch = ALIGN_UP(2 * info.width, 32); uint32_t vc_image_ptr; VC_IMAGE_TYPE_T type = VC_IMAGE_RGB565; DISPMANX_RESOURCE_HANDLE_T resource = vc_dispmanx_resource_create( type, info.width, info.height, &vc_image_ptr ); VC_IMAGE_TRANSFORM_T transform = 0; vc_dispmanx_snapshot(display, resource, transform); VC_RECT_T rect; vc_dispmanx_rect_set(&rect, 0, 0, info.width, info.height); unsigned char *image = malloc(pitch * info.height); assert(image); vc_dispmanx_resource_read_data(resource, &rect, image, info.width * 2); ret = vc_dispmanx_resource_delete(resource); assert(ret == 0); ret = vc_dispmanx_display_close(display); assert(ret == 0); struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPROW row_pointer[1]; cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, stdout); cinfo.image_width = info.width; cinfo.image_height = info.height; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, quality, TRUE); jpeg_start_compress(&cinfo, TRUE); int row_stride = cinfo.image_width * 3; while (cinfo.next_scanline < cinfo.image_height) { unsigned char row[row_stride]; unsigned char *dst = &row[0]; uint16_t *src = (uint16_t*)(image + pitch * cinfo.next_scanline); for (int x = 0; x < cinfo.image_width; x++, src++) { *dst++ = ((*src & 0xf800) >> 11) << 3; *dst++ = ((*src & 0x07e0) >> 5) << 2; *dst++ = ((*src & 0x001f) >> 0) << 3; } row_pointer[0] = row; jpeg_write_scanlines(&cinfo, row_pointer, 1); } jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); return 0; }
void GL_ScreenShot_JPG (byte *buffer) { struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPROW s[1]; FILE *f; char picname[80], checkname[MAX_OSPATH]; int i, offset, w3; // create the scrnshots directory if it doesn't exist Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot/", ri.FS_Gamedir()); FS_CreatePath (checkname); for (i = 0; i < 999; i++) { sprintf (picname, "%s/scrnshot/quake%.3d.jpg", ri.FS_Gamedir(), i); f = fopen (picname, "rb"); if (!f) break; fclose (f); } f = fopen (picname, "wb"); if (!f) { ri.Con_Printf (PRINT_ALL, "Couldn't open %s for writing.\n", picname); return; } // Initialise the JPEG compression object cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, f); // Setup JPEG Parameters cinfo.image_width = vid.width; cinfo.image_height = vid.height; cinfo.in_color_space = JCS_RGB; cinfo.input_components = 3; jpeg_set_defaults(&cinfo); // Niceass: 85 is the quality. 0-100 jpeg_set_quality(&cinfo, Q_ftol(gl_jpg_quality->value), TRUE); // Start Compression jpeg_start_compress(&cinfo, true); // Feed scanline data w3 = cinfo.image_width * 3; offset = w3 * cinfo.image_height - w3; while (cinfo.next_scanline < cinfo.image_height) { s[0] = &buffer[offset - cinfo.next_scanline * w3]; jpeg_write_scanlines(&cinfo, s, 1); } // Finish Compression jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); fclose(f); free(buffer); ri.Con_Printf (PRINT_ALL, "Wrote %s\n", picname); }
G_MODULE_EXPORT gboolean tracker_extract_get_metadata (TrackerExtractInfo *info) { struct jpeg_decompress_struct cinfo; struct tej_error_mgr tejerr; struct jpeg_marker_struct *marker; TrackerSparqlBuilder *preupdate, *metadata; TrackerXmpData *xd = NULL; TrackerExifData *ed = NULL; TrackerIptcData *id = NULL; MergeData md = { 0 }; GFile *file; FILE *f; goffset size; gchar *filename, *uri; gchar *comment = NULL; const gchar *dlna_profile, *dlna_mimetype, *graph, *urn; GPtrArray *keywords; gboolean success = TRUE; guint i; metadata = tracker_extract_info_get_metadata_builder (info); preupdate = tracker_extract_info_get_preupdate_builder (info); graph = tracker_extract_info_get_graph (info); urn = tracker_extract_info_get_urn (info); file = tracker_extract_info_get_file (info); filename = g_file_get_path (file); size = tracker_file_get_size (filename); if (size < 18) { g_free (filename); return FALSE; } f = tracker_file_open (filename); g_free (filename); if (!f) { return FALSE; } uri = g_file_get_uri (file); tracker_sparql_builder_predicate (metadata, "a"); tracker_sparql_builder_object (metadata, "nfo:Image"); tracker_sparql_builder_predicate (metadata, "a"); tracker_sparql_builder_object (metadata, "nmm:Photo"); cinfo.err = jpeg_std_error (&tejerr.jpeg); tejerr.jpeg.error_exit = extract_jpeg_error_exit; if (setjmp (tejerr.setjmp_buffer)) { success = FALSE; goto fail; } jpeg_create_decompress (&cinfo); jpeg_save_markers (&cinfo, JPEG_COM, 0xFFFF); jpeg_save_markers (&cinfo, JPEG_APP0 + 1, 0xFFFF); jpeg_save_markers (&cinfo, JPEG_APP0 + 13, 0xFFFF); jpeg_stdio_src (&cinfo, f); jpeg_read_header (&cinfo, TRUE); /* FIXME? It is possible that there are markers after SOS, * but there shouldn't be. Should we decompress the whole file? * * jpeg_start_decompress(&cinfo); * jpeg_finish_decompress(&cinfo); * * jpeg_calc_output_dimensions(&cinfo); */ marker = (struct jpeg_marker_struct *) &cinfo.marker_list; while (marker) { gchar *str; gsize len; #ifdef HAVE_LIBIPTCDATA gsize offset; guint sublen; #endif /* HAVE_LIBIPTCDATA */ switch (marker->marker) { case JPEG_COM: g_free (comment); comment = g_strndup ((gchar*) marker->data, marker->data_length); break; case JPEG_APP0 + 1: str = (gchar*) marker->data; len = marker->data_length; #ifdef HAVE_LIBEXIF if (strncmp (EXIF_NAMESPACE, str, EXIF_NAMESPACE_LENGTH) == 0) { ed = tracker_exif_new ((guchar *) marker->data, len, uri); } #endif /* HAVE_LIBEXIF */ #ifdef HAVE_EXEMPI if (strncmp (XMP_NAMESPACE, str, XMP_NAMESPACE_LENGTH) == 0) { xd = tracker_xmp_new (str + XMP_NAMESPACE_LENGTH, len - XMP_NAMESPACE_LENGTH, uri); } #endif /* HAVE_EXEMPI */ break; case JPEG_APP0 + 13: str = (gchar*) marker->data; len = marker->data_length; #ifdef HAVE_LIBIPTCDATA if (len > 0 && strncmp (PS3_NAMESPACE, str, PS3_NAMESPACE_LENGTH) == 0) { offset = iptc_jpeg_ps3_find_iptc (str, len, &sublen); if (offset > 0 && sublen > 0) { id = tracker_iptc_new (str + offset, sublen, uri); } } #endif /* HAVE_LIBIPTCDATA */ break; default: marker = marker->next; continue; } marker = marker->next; } if (!ed) { ed = g_new0 (TrackerExifData, 1); } if (!xd) { xd = g_new0 (TrackerXmpData, 1); } if (!id) { id = g_new0 (TrackerIptcData, 1); } md.title = tracker_coalesce_strip (4, xd->title, ed->document_name, xd->title2, xd->pdf_title); md.orientation = tracker_coalesce_strip (3, xd->orientation, ed->orientation, id->image_orientation); md.copyright = tracker_coalesce_strip (4, xd->copyright, xd->rights, ed->copyright, id->copyright_notice); md.white_balance = tracker_coalesce_strip (2, xd->white_balance, ed->white_balance); md.fnumber = tracker_coalesce_strip (2, xd->fnumber, ed->fnumber); md.flash = tracker_coalesce_strip (2, xd->flash, ed->flash); md.focal_length = tracker_coalesce_strip (2, xd->focal_length, ed->focal_length); md.artist = tracker_coalesce_strip (3, xd->artist, ed->artist, xd->contributor); md.exposure_time = tracker_coalesce_strip (2, xd->exposure_time, ed->exposure_time); md.iso_speed_ratings = tracker_coalesce_strip (2, xd->iso_speed_ratings, ed->iso_speed_ratings); md.date = tracker_coalesce_strip (5, xd->date, xd->time_original, ed->time, id->date_created, ed->time_original); md.description = tracker_coalesce_strip (2, xd->description, ed->description); md.metering_mode = tracker_coalesce_strip (2, xd->metering_mode, ed->metering_mode); md.city = tracker_coalesce_strip (2, xd->city, id->city); md.state = tracker_coalesce_strip (2, xd->state, id->state); md.address = tracker_coalesce_strip (2, xd->address, id->sublocation); md.country = tracker_coalesce_strip (2, xd->country, id->country_name); /* FIXME We are not handling the altitude ref here for xmp */ md.gps_altitude = tracker_coalesce_strip (2, xd->gps_altitude, ed->gps_altitude); md.gps_latitude = tracker_coalesce_strip (2, xd->gps_latitude, ed->gps_latitude); md.gps_longitude = tracker_coalesce_strip (2, xd->gps_longitude, ed->gps_longitude); md.gps_direction = tracker_coalesce_strip (2, xd->gps_direction, ed->gps_direction); md.creator = tracker_coalesce_strip (3, xd->creator, id->byline, id->credit); md.comment = tracker_coalesce_strip (2, comment, ed->user_comment); md.make = tracker_coalesce_strip (2, xd->make, ed->make); md.model = tracker_coalesce_strip (2, xd->model, ed->model); /* Prioritize on native dimention in all cases */ tracker_sparql_builder_predicate (metadata, "nfo:width"); tracker_sparql_builder_object_int64 (metadata, cinfo.image_width); /* TODO: add ontology and store ed->software */ tracker_sparql_builder_predicate (metadata, "nfo:height"); tracker_sparql_builder_object_int64 (metadata, cinfo.image_height); if (guess_dlna_profile (cinfo.image_width, cinfo.image_height, &dlna_profile, &dlna_mimetype)) { tracker_sparql_builder_predicate (metadata, "nmm:dlnaProfile"); tracker_sparql_builder_object_string (metadata, dlna_profile); tracker_sparql_builder_predicate (metadata, "nmm:dlnaMime"); tracker_sparql_builder_object_string (metadata, dlna_mimetype); } if (id->contact) { gchar *uri = tracker_sparql_escape_uri_printf ("urn:contact:%s", id->contact); tracker_sparql_builder_insert_open (preupdate, NULL); if (graph) { tracker_sparql_builder_graph_open (preupdate, graph); } tracker_sparql_builder_subject_iri (preupdate, uri); tracker_sparql_builder_predicate (preupdate, "a"); tracker_sparql_builder_object (preupdate, "nco:Contact"); tracker_sparql_builder_predicate (preupdate, "nco:fullname"); tracker_sparql_builder_object_unvalidated (preupdate, id->contact); if (graph) { tracker_sparql_builder_graph_close (preupdate); } tracker_sparql_builder_insert_close (preupdate); tracker_sparql_builder_predicate (metadata, "nco:representative"); tracker_sparql_builder_object_iri (metadata, uri); g_free (uri); } keywords = g_ptr_array_new_with_free_func ((GDestroyNotify) g_free); if (xd->keywords) { tracker_keywords_parse (keywords, xd->keywords); } if (xd->pdf_keywords) { tracker_keywords_parse (keywords, xd->pdf_keywords); } if (xd->subject) { tracker_keywords_parse (keywords, xd->subject); } if (xd->publisher) { gchar *uri = tracker_sparql_escape_uri_printf ("urn:contact:%s", xd->publisher); tracker_sparql_builder_insert_open (preupdate, NULL); if (graph) { tracker_sparql_builder_graph_open (preupdate, graph); } tracker_sparql_builder_subject_iri (preupdate, uri); tracker_sparql_builder_predicate (preupdate, "a"); tracker_sparql_builder_object (preupdate, "nco:Contact"); tracker_sparql_builder_predicate (preupdate, "nco:fullname"); tracker_sparql_builder_object_unvalidated (preupdate, xd->publisher); if (graph) { tracker_sparql_builder_graph_close (preupdate); } tracker_sparql_builder_insert_close (preupdate); tracker_sparql_builder_predicate (metadata, "nco:publisher"); tracker_sparql_builder_object_iri (metadata, uri); g_free (uri); } if (xd->type) { tracker_sparql_builder_predicate (metadata, "dc:type"); tracker_sparql_builder_object_unvalidated (metadata, xd->type); } if (xd->rating) { tracker_sparql_builder_predicate (metadata, "nao:numericRating"); tracker_sparql_builder_object_unvalidated (metadata, xd->rating); } if (xd->format) { tracker_sparql_builder_predicate (metadata, "dc:format"); tracker_sparql_builder_object_unvalidated (metadata, xd->format); } if (xd->identifier) { tracker_sparql_builder_predicate (metadata, "dc:identifier"); tracker_sparql_builder_object_unvalidated (metadata, xd->identifier); } if (xd->source) { tracker_sparql_builder_predicate (metadata, "dc:source"); tracker_sparql_builder_object_unvalidated (metadata, xd->source); } if (xd->language) { tracker_sparql_builder_predicate (metadata, "dc:language"); tracker_sparql_builder_object_unvalidated (metadata, xd->language); } if (xd->relation) { tracker_sparql_builder_predicate (metadata, "dc:relation"); tracker_sparql_builder_object_unvalidated (metadata, xd->relation); } if (xd->coverage) { tracker_sparql_builder_predicate (metadata, "dc:coverage"); tracker_sparql_builder_object_unvalidated (metadata, xd->coverage); } if (xd->license) { tracker_sparql_builder_predicate (metadata, "nie:license"); tracker_sparql_builder_object_unvalidated (metadata, xd->license); } if (xd->regions) { tracker_xmp_apply_regions (preupdate, metadata, graph, xd); } if (id->keywords) { tracker_keywords_parse (keywords, id->keywords); } for (i = 0; i < keywords->len; i++) { gchar *escaped, *subject; const gchar *p; p = g_ptr_array_index (keywords, i); escaped = tracker_sparql_escape_string (p); subject = g_strdup_printf ("_:tag%d", i + 1); /* ensure tag with specified label exists */ tracker_sparql_builder_insert_open (preupdate, graph); tracker_sparql_builder_subject (preupdate, subject); tracker_sparql_builder_predicate (preupdate, "a"); tracker_sparql_builder_object (preupdate, "nao:Tag"); tracker_sparql_builder_predicate (preupdate, "nao:prefLabel"); tracker_sparql_builder_object_unvalidated (preupdate, escaped); tracker_sparql_builder_insert_close (preupdate); tracker_sparql_builder_append (preupdate, "WHERE { FILTER (NOT EXISTS { " "?tag a nao:Tag ; nao:prefLabel \""); tracker_sparql_builder_append (preupdate, escaped); tracker_sparql_builder_append (preupdate, "\" }) }\n"); /* associate file with tag */ tracker_sparql_builder_insert_open (preupdate, graph); tracker_sparql_builder_subject_iri (preupdate, urn); tracker_sparql_builder_predicate (preupdate, "nao:hasTag"); tracker_sparql_builder_object (preupdate, "?tag"); tracker_sparql_builder_insert_close (preupdate); tracker_sparql_builder_where_open (preupdate); tracker_sparql_builder_subject (preupdate, "?tag"); tracker_sparql_builder_predicate (preupdate, "a"); tracker_sparql_builder_object (preupdate, "nao:Tag"); tracker_sparql_builder_predicate (preupdate, "nao:prefLabel"); tracker_sparql_builder_object_unvalidated (preupdate, escaped); tracker_sparql_builder_where_close (preupdate); g_free (subject); g_free (escaped); } g_ptr_array_free (keywords, TRUE); if (md.make || md.model) { gchar *equip_uri; equip_uri = tracker_sparql_escape_uri_printf ("urn:equipment:%s:%s:", md.make ? md.make : "", md.model ? md.model : ""); tracker_sparql_builder_insert_open (preupdate, NULL); if (graph) { tracker_sparql_builder_graph_open (preupdate, graph); } tracker_sparql_builder_subject_iri (preupdate, equip_uri); tracker_sparql_builder_predicate (preupdate, "a"); tracker_sparql_builder_object (preupdate, "nfo:Equipment"); if (md.make) { tracker_sparql_builder_predicate (preupdate, "nfo:manufacturer"); tracker_sparql_builder_object_unvalidated (preupdate, md.make); } if (md.model) { tracker_sparql_builder_predicate (preupdate, "nfo:model"); tracker_sparql_builder_object_unvalidated (preupdate, md.model); } if (graph) { tracker_sparql_builder_graph_close (preupdate); } tracker_sparql_builder_insert_close (preupdate); tracker_sparql_builder_predicate (metadata, "nfo:equipment"); tracker_sparql_builder_object_iri (metadata, equip_uri); g_free (equip_uri); } tracker_guarantee_title_from_file (metadata, "nie:title", md.title, uri, NULL); if (md.orientation) { tracker_sparql_builder_predicate (metadata, "nfo:orientation"); tracker_sparql_builder_object (metadata, md.orientation); } if (md.copyright) { tracker_sparql_builder_predicate (metadata, "nie:copyright"); tracker_sparql_builder_object_unvalidated (metadata, md.copyright); } if (md.white_balance) { tracker_sparql_builder_predicate (metadata, "nmm:whiteBalance"); tracker_sparql_builder_object (metadata, md.white_balance); } if (md.fnumber) { gdouble value; value = g_strtod (md.fnumber, NULL); tracker_sparql_builder_predicate (metadata, "nmm:fnumber"); tracker_sparql_builder_object_double (metadata, value); } if (md.flash) { tracker_sparql_builder_predicate (metadata, "nmm:flash"); tracker_sparql_builder_object (metadata, md.flash); } if (md.focal_length) { gdouble value; value = g_strtod (md.focal_length, NULL); tracker_sparql_builder_predicate (metadata, "nmm:focalLength"); tracker_sparql_builder_object_double (metadata, value); } if (md.artist) { gchar *uri = tracker_sparql_escape_uri_printf ("urn:contact:%s", md.artist); tracker_sparql_builder_insert_open (preupdate, NULL); if (graph) { tracker_sparql_builder_graph_open (preupdate, graph); } tracker_sparql_builder_subject_iri (preupdate, uri); tracker_sparql_builder_predicate (preupdate, "a"); tracker_sparql_builder_object (preupdate, "nco:Contact"); tracker_sparql_builder_predicate (preupdate, "nco:fullname"); tracker_sparql_builder_object_unvalidated (preupdate, md.artist); if (graph) { tracker_sparql_builder_graph_close (preupdate); } tracker_sparql_builder_insert_close (preupdate); tracker_sparql_builder_predicate (metadata, "nco:contributor"); tracker_sparql_builder_object_iri (metadata, uri); g_free (uri); } if (md.exposure_time) { gdouble value; value = g_strtod (md.exposure_time, NULL); tracker_sparql_builder_predicate (metadata, "nmm:exposureTime"); tracker_sparql_builder_object_double (metadata, value); } if (md.iso_speed_ratings) { gdouble value; value = g_strtod (md.iso_speed_ratings, NULL); tracker_sparql_builder_predicate (metadata, "nmm:isoSpeed"); tracker_sparql_builder_object_double (metadata, value); } tracker_guarantee_date_from_file_mtime (metadata, "nie:contentCreated", md.date, uri); if (md.description) { tracker_sparql_builder_predicate (metadata, "nie:description"); tracker_sparql_builder_object_unvalidated (metadata, md.description); } if (md.metering_mode) { tracker_sparql_builder_predicate (metadata, "nmm:meteringMode"); tracker_sparql_builder_object (metadata, md.metering_mode); } if (md.creator) { gchar *uri = tracker_sparql_escape_uri_printf ("urn:contact:%s", md.creator); tracker_sparql_builder_insert_open (preupdate, NULL); if (graph) { tracker_sparql_builder_graph_open (preupdate, graph); } tracker_sparql_builder_subject_iri (preupdate, uri); tracker_sparql_builder_predicate (preupdate, "a"); tracker_sparql_builder_object (preupdate, "nco:Contact"); tracker_sparql_builder_predicate (preupdate, "nco:fullname"); tracker_sparql_builder_object_unvalidated (preupdate, md.creator); if (graph) { tracker_sparql_builder_graph_close (preupdate); } tracker_sparql_builder_insert_close (preupdate); /* NOTE: We only have affiliation with * nco:PersonContact and we are using * nco:Contact here. */ /* if (id->byline_title) { */ /* tracker_sparql_builder_insert_open (preupdate, NULL); */ /* tracker_sparql_builder_subject (preupdate, "_:affiliation_by_line"); */ /* tracker_sparql_builder_predicate (preupdate, "a"); */ /* tracker_sparql_builder_object (preupdate, "nco:Affiliation"); */ /* tracker_sparql_builder_predicate (preupdate, "nco:title"); */ /* tracker_sparql_builder_object_unvalidated (preupdate, id->byline_title); */ /* tracker_sparql_builder_insert_close (preupdate); */ /* tracker_sparql_builder_predicate (preupdate, "a"); */ /* tracker_sparql_builder_object (preupdate, "nco:Contact"); */ /* tracker_sparql_builder_predicate (preupdate, "nco:hasAffiliation"); */ /* tracker_sparql_builder_object (preupdate, "_:affiliation_by_line"); */ /* } */ tracker_sparql_builder_predicate (metadata, "nco:creator"); tracker_sparql_builder_object_iri (metadata, uri); g_free (uri); } if (md.comment) { tracker_sparql_builder_predicate (metadata, "nie:comment"); tracker_sparql_builder_object_unvalidated (metadata, md.comment); } if (md.address || md.state || md.country || md.city || md.gps_altitude || md.gps_latitude || md.gps_longitude) { tracker_sparql_builder_predicate (metadata, "slo:location"); tracker_sparql_builder_object_blank_open (metadata); /* GeoPoint */ tracker_sparql_builder_predicate (metadata, "a"); tracker_sparql_builder_object (metadata, "slo:GeoLocation"); if (md.address || md.state || md.country || md.city) { gchar *addruri; addruri = tracker_sparql_get_uuid_urn (); tracker_sparql_builder_predicate (metadata, "slo:postalAddress"); tracker_sparql_builder_object_iri (metadata, addruri); tracker_sparql_builder_insert_open (preupdate, NULL); if (graph) { tracker_sparql_builder_graph_open (preupdate, graph); } tracker_sparql_builder_subject_iri (preupdate, addruri); g_free (addruri); tracker_sparql_builder_predicate (preupdate, "a"); tracker_sparql_builder_object (preupdate, "nco:PostalAddress"); if (md.address) { tracker_sparql_builder_predicate (preupdate, "nco:streetAddress"); tracker_sparql_builder_object_unvalidated (preupdate, md.address); } if (md.state) { tracker_sparql_builder_predicate (preupdate, "nco:region"); tracker_sparql_builder_object_unvalidated (preupdate, md.state); } if (md.city) { tracker_sparql_builder_predicate (preupdate, "nco:locality"); tracker_sparql_builder_object_unvalidated (preupdate, md.city); } if (md.country) { tracker_sparql_builder_predicate (preupdate, "nco:country"); tracker_sparql_builder_object_unvalidated (preupdate, md.country); } if (graph) { tracker_sparql_builder_graph_close (preupdate); } tracker_sparql_builder_insert_close (preupdate); } if (md.gps_altitude) { tracker_sparql_builder_predicate (metadata, "slo:altitude"); tracker_sparql_builder_object_unvalidated (metadata, md.gps_altitude); } if (md.gps_latitude) { tracker_sparql_builder_predicate (metadata, "slo:latitude"); tracker_sparql_builder_object_unvalidated (metadata, md.gps_latitude); } if (md.gps_longitude) { tracker_sparql_builder_predicate (metadata, "slo:longitude"); tracker_sparql_builder_object_unvalidated (metadata, md.gps_longitude); } tracker_sparql_builder_object_blank_close (metadata); /* GeoLocation */ } if (md.gps_direction) { tracker_sparql_builder_predicate (metadata, "nfo:heading"); tracker_sparql_builder_object_unvalidated (metadata, md.gps_direction); } if (cinfo.density_unit != 0 || ed->x_resolution) { gdouble value; if (cinfo.density_unit == 0) { if (ed->resolution_unit != 3) value = g_strtod (ed->x_resolution, NULL); else value = g_strtod (ed->x_resolution, NULL) * CM_TO_INCH; } else { if (cinfo.density_unit == 1) value = cinfo.X_density; else value = cinfo.X_density * CM_TO_INCH; } tracker_sparql_builder_predicate (metadata, "nfo:horizontalResolution"); tracker_sparql_builder_object_double (metadata, value); } if (cinfo.density_unit != 0 || ed->y_resolution) { gdouble value; if (cinfo.density_unit == 0) { if (ed->resolution_unit != 3) value = g_strtod (ed->y_resolution, NULL); else value = g_strtod (ed->y_resolution, NULL) * CM_TO_INCH; } else { if (cinfo.density_unit == 1) value = cinfo.Y_density; else value = cinfo.Y_density * CM_TO_INCH; } tracker_sparql_builder_predicate (metadata, "nfo:verticalResolution"); tracker_sparql_builder_object_double (metadata, value); } jpeg_destroy_decompress (&cinfo); tracker_exif_free (ed); tracker_xmp_free (xd); tracker_iptc_free (id); g_free (comment); fail: tracker_file_close (f, FALSE); g_free (uri); return success; }
int LoadJPG( const char *filename, 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 */ fileHandle_t infile; /* source file */ JSAMPARRAY buffer; /* Output row buffer */ int row_stride; /* physical row width in output buffer */ unsigned char *out; /* 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. */ FS_FOpenFileRead( filename, &infile, qfalse ); if (infile == 0) { return 0; } /* 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, 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; out = Z_Malloc(cinfo.output_width*cinfo.output_height*cinfo.output_components); *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. */ buffer = (JSAMPARRAY)out+(row_stride*cinfo.output_scanline); (void) jpeg_read_scanlines(&cinfo, buffer, 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...) */ FS_FCloseFile(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 1; }
void JP4::open(const string& _filename) { this->_filename = string(_filename); struct jpeg_error_mgr jerr; struct jpeg_decompress_struct dinfo; JSAMPARRAY buffer; FILE *ifp = NULL; dinfo.err = jpeg_std_error (&jerr); ifp = fopen(filename().c_str(), "rb"); jpeg_create_decompress (&dinfo); jpeg_stdio_src (&dinfo, ifp); // instruct it to save EXIF at APP1 (0xe1) data (up to 64k) jpeg_save_markers(&dinfo, 0xe1, 0xffff); jpeg_read_header (&dinfo, TRUE); dinfo.do_block_smoothing = FALSE; dinfo.out_color_space = JCS_GRAYSCALE; // save raw APP1 data (if any) if (dinfo.marker_list) { _raw_app1_length = dinfo.marker_list[0].data_length; _raw_app1 = new unsigned char[_raw_app1_length]; memcpy(_raw_app1, dinfo.marker_list[0].data, _raw_app1_length); } this->_width = dinfo.image_width; this->_height = dinfo.image_height; buffer = (*dinfo.mem->alloc_sarray)((j_common_ptr)&dinfo, JPOOL_IMAGE, width(), 1); _data = new unsigned short[width()*height()]; jpeg_start_decompress (&dinfo); unsigned short* temp = new unsigned short[width()*height()]; for (unsigned int line = 0; line < height(); line++) { jpeg_read_scanlines (&dinfo, buffer, 1); for (unsigned int column = 0; column < width(); column++) temp[line*width() + column] = buffer[0][column]; } // EXIF readMakerNote(); // JP4 deblocking // from http://code.google.com/p/gst-plugins-elphel/source/browse/trunk/jp462bayer/src/gstjp462bayer.c unsigned int y, x; unsigned int b_of = 0; unsigned int h_of; unsigned int i, j; unsigned int index1[16]={0,8,1,9,2,10,3,11,4,12,5,13,6,14,7,15}; unsigned int index2[16]; for (j = 0;j < 16; ++j) index2[j] = index1[j] * width(); for (y = 0; y < height(); y += 16, b_of += width() << 4) for (x = 0; x < width(); x += 16) for (j = 0, h_of = 0; j < 16; ++j, h_of += width()) for (i = 0; i < 16; ++i) _data[x + i + h_of + b_of] = temp[x + index1[i] + index2[j] + b_of]; jpeg_finish_decompress (&dinfo); fclose(ifp); delete[] temp; }
int jpeg_read(const char* filename,jpeg_datap result){ auto jpegData = D2D::FileUtil::getInstacne()->getDataFromFile(filename,true); assert(!jpegData.isNull()); /* these are standard libjpeg structures for reading(decompression) */ 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 MyErrorMgr jerr; /* libjpeg data structure for storing one row, that is, scanline of an image */ JSAMPROW row_pointer[1] = {0}; unsigned long location = 0; unsigned int i = 0; /* We set up the normal JPEG error routines, then override error_exit. */ cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = myErrorExit; /* Establish the setjmp return context for MyErrorExit 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); printf("decompress jpeg : %s error.\n",filename); abort(); return -1; } /* setup decompression process and source, then read JPEG header */ jpeg_create_decompress( &cinfo ); jpeg_mem_src( &cinfo, const_cast<unsigned char*>(jpegData.getBytes()),jpegData.getSize()); /* reading the image header which contains image information */ #if (JPEG_LIB_VERSION >= 90) // libjpeg 0.9 adds stricter types. jpeg_read_header( &cinfo, TRUE ); #else jpeg_read_header( &cinfo, true ); #endif // we only support RGB or grayscale if (cinfo.jpeg_color_space == JCS_GRAYSCALE) { result->format = Texture2D::PixelFormat::I8; }else { cinfo.out_color_space = JCS_RGB; result->format = Texture2D::PixelFormat::RGB888; } /* Start decompression jpeg here */ jpeg_start_decompress( &cinfo ); /* init image info */ result->width = cinfo.output_width; result->height = cinfo.output_height; row_pointer[0] = static_cast<unsigned char*>(malloc(cinfo.output_width*cinfo.output_components * sizeof(unsigned char))); ssize_t dataLen = cinfo.output_width * cinfo.output_height*cinfo.output_components; result->data = static_cast<unsigned char*>(malloc(dataLen * sizeof(unsigned char))); /* now actually read the jpeg into the raw buffer */ /* read one scan line at a time */ while( cinfo.output_scanline < cinfo.output_height ){ jpeg_read_scanlines( &cinfo, row_pointer, 1 ); for( i=0; i<cinfo.output_width*cinfo.output_components;i++) { result->data[location++] = row_pointer[0][i]; } } /* When read image file with broken data, jpeg_finish_decompress() may cause error. * Besides, jpeg_destroy_decompress() shall deallocate and release all memory associated * with the decompression object. * So it doesn't need to call jpeg_finish_decompress(). */ //jpeg_finish_decompress( &cinfo ); jpeg_destroy_decompress( &cinfo ); if (row_pointer[0] != nullptr) { free(row_pointer[0]); }; return 0; }
static int read_image_jpeg(FILE *file, png24_image *image) { int retval; unsigned int width,height,row_stride; unsigned int bpp; unsigned int x,y,i; struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); // decompress jpeg_stdio_src(&cinfo,file); retval=jpeg_read_header(&cinfo,TRUE); if(retval != 1) { return 1; } jpeg_start_decompress(&cinfo); width=cinfo.output_width; height=cinfo.output_height; bpp=cinfo.output_components; row_stride=width*bpp; // grayscale images not handled currently if (bpp == 1) { fprintf(stderr, "Error: grayscale JPEG images not handled currently."); return 1; } // allocate buffer size (always use RGBA) unsigned char* buffer = calloc(width*height*bpp,1); while(cinfo.output_scanline < height) { unsigned char *buffer_array[1]; buffer_array[0] = buffer + cinfo.output_scanline*row_stride; jpeg_read_scanlines(&cinfo,buffer_array,1); } //convert to RGBA image->rgba_data = calloc(width*height*4,1); image->row_pointers = calloc(height,sizeof(unsigned char*)); for(y=0; y<height; y++) { for(x=0; x<width; x++) { for(i=0; i<bpp; i++) { image->rgba_data[(y*width*4)+(x*4)+i] = buffer[(y*width*bpp)+(x*bpp)+i]; } // default alpha 255 image->rgba_data[(y*width*4) + (x*4) + 3] = 0xFF; } image->row_pointers[y] = &image->rgba_data[y*width*4]; } image->width=width; image->height=height; jpeg_destroy_decompress(&cinfo); free(buffer); return 0; }
static void save_jpg_entry_helper(ALLEGRO_FILE *fp, ALLEGRO_BITMAP *bmp, struct save_jpg_entry_helper_data *data) { struct jpeg_compress_struct cinfo; struct my_err_mgr jerr; ALLEGRO_LOCKED_REGION *lock; data->error = false; cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = my_error_exit; if (setjmp(jerr.jmpenv)) { /* Longjmp'd. */ data->error = true; goto longjmp_error; } data->buffer = al_malloc(BUFFER_SIZE); if (!data->buffer) { data->error = true; goto error; } jpeg_create_compress(&cinfo); jpeg_packfile_dest(&cinfo, fp, data->buffer); cinfo.image_width = al_get_bitmap_width(bmp); cinfo.image_height = al_get_bitmap_height(bmp); cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&cinfo); jpeg_start_compress(&cinfo, 1); /* See comment in load_jpg_entry_helper. */ #ifdef ALLEGRO_BIG_ENDIAN lock = al_lock_bitmap(bmp, ALLEGRO_PIXEL_FORMAT_RGB_888, ALLEGRO_LOCK_READONLY); #else lock = al_lock_bitmap(bmp, ALLEGRO_PIXEL_FORMAT_BGR_888, ALLEGRO_LOCK_READONLY); #endif while (cinfo.next_scanline < cinfo.image_height) { unsigned char *row[1]; row[0] = ((unsigned char *)lock->data) + (signed)cinfo.next_scanline * lock->pitch; jpeg_write_scanlines(&cinfo, (void *)row, 1); } error: jpeg_finish_compress(&cinfo); longjmp_error: jpeg_destroy_compress(&cinfo); if (al_is_bitmap_locked(bmp)) { al_unlock_bitmap(bmp); } al_free(data->buffer); }
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; /* On Mac, fetch a command line. */ #ifdef USE_CCOMMAND argc = ccommand(&argv); #endif progname = argv[0]; if (progname == NULL || progname[0] == 0) progname = "jpegtran"; /* in case C library doesn't provide it */ /* Initialize the JPEG decompression object with default error handling. */ srcinfo.err = jpeg_std_error(&jsrcerr); jpeg_create_decompress(&srcinfo); /* Initialize the JPEG compression object with default error handling. */ dstinfo.err = jpeg_std_error(&jdsterr); jpeg_create_compress(&dstinfo); /* Now safe to enable signal catcher. * Note: we assume only the decompression object will have virtual arrays. */ #ifdef NEED_SIGNAL_CATCHER enable_signal_catcher((j_common_ptr) &srcinfo); #endif /* Scan command line to find file names. * It is convenient to use just one switch-parsing routine, but the switch * values read here are mostly ignored; we will rescan the switches after * opening the input file. Also note that most of the switches affect the * destination JPEG object, so we parse into that and then copy over what * needs to affects the source too. */ file_index = parse_switches(&dstinfo, argc, argv, 0, FALSE); jsrcerr.trace_level = jdsterr.trace_level; srcinfo.mem->max_memory_to_use = dstinfo.mem->max_memory_to_use; #ifdef TWO_FILE_COMMANDLINE /* Must have either -outfile switch or explicit output file name */ if (outfilename == NULL) { if (file_index != argc-2) { fprintf(stderr, "%s: must name one input and one output file\n", progname); usage(); } outfilename = argv[file_index+1]; } else { if (file_index != argc-1) { fprintf(stderr, "%s: must name one input and one output file\n", progname); usage(); } } #else /* Unix style: expect zero or one file name */ if (file_index < argc-1) { fprintf(stderr, "%s: only one input file\n", progname); usage(); } #endif /* TWO_FILE_COMMANDLINE */ /* Open the input file. */ if (file_index < argc) { if ((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 */ 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); /* Adjust default decompression parameters */ if (scaleoption != NULL) if (sscanf(scaleoption, "%d/%d", &srcinfo.scale_num, &srcinfo.scale_denom) < 1) usage(); /* 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 */ 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); 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 */ }
GLOBAL(int) read_JPEG_file (char * filename, char *dest) { struct jpeg_decompress_struct cinfo; struct error_mgr jerr; FILE *infile; FILE *outfile; JSAMPARRAY buffer; int row_stride, lines=0; if ((infile = fopen(filename, "rb")) == NULL) { fprintf(stderr, "Can't open: %s\n", filename); return 0; } if ((outfile = fopen(dest, "wb+")) == NULL) { fprintf(stderr, "Can't open: %s\n", filename); return 0; } cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = my_error_exit; if (setjmp(jerr.setjmp_buffer)) { jpeg_destroy_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); fclose(infile); fclose (outfile); return 0; } jpeg_create_decompress(&cinfo); jpeg_stdio_src(&cinfo, infile); (void) jpeg_read_header(&cinfo, TRUE); (void) jpeg_start_decompress(&cinfo); row_stride = cinfo.output_width * cinfo.output_components; fprintf (stderr, "Information about: %s:\n", filename); fprintf (stderr, "Width : %d\n", cinfo.output_width); fprintf (stderr, "Height: %d\n", cinfo.output_height); fprintf (stderr, "Components: %d\n", cinfo.output_components); fprintf (stderr, "Size: %d\n", row_stride*cinfo.output_height); buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); /* put a header in the image ( a pnm header ) */ fprintf (outfile,"P6\n%d %d\n255\n", cinfo.output_width, cinfo.output_height); /* read line per line */ while (cinfo.output_scanline < cinfo.output_height) { (void) jpeg_read_scanlines(&cinfo, buffer, 1); fwrite (buffer[0], row_stride, 1, outfile); lines++; } (void) jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); fclose(infile); fclose (outfile); }
static uint32_t jpeg_write(const char * name, uint8_t * buffer) { FILE *outfile; struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPROW row_pointer[1]; int row_stride; if ( !buffer ) return 1; if ( (outfile = fopen(name, "wb") ) == NULL ) { mp_msg(MSGT_VO, MSGL_ERR, "\n%s: %s\n", info.short_name, MSGTR_VO_CantCreateFile); mp_msg(MSGT_VO, MSGL_ERR, "%s: %s: %s\n", info.short_name, MSGTR_VO_GenericError, strerror(errno) ); exit_player(EXIT_ERROR); } cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, outfile); cinfo.image_width = image_width; cinfo.image_height = image_height; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&cinfo); /* Important: Header info must be set AFTER jpeg_set_defaults() */ cinfo.write_JFIF_header = TRUE; cinfo.JFIF_major_version = 1; cinfo.JFIF_minor_version = 2; cinfo.density_unit = 1; /* 0=unknown, 1=dpi, 2=dpcm */ /* Image DPI is determined by Y_density, so we leave that at jpeg_dpi if possible and crunch X_density instead (PAR > 1) */ cinfo.X_density = jpeg_dpi*image_width/image_d_width; cinfo.Y_density = jpeg_dpi*image_height/image_d_height; cinfo.write_Adobe_marker = TRUE; jpeg_set_quality(&cinfo,jpeg_quality, jpeg_baseline); cinfo.optimize_coding = jpeg_optimize; cinfo.smoothing_factor = jpeg_smooth; if ( jpeg_progressive_mode ) { jpeg_simple_progression(&cinfo); } jpeg_start_compress(&cinfo, TRUE); row_stride = image_width * 3; while (cinfo.next_scanline < cinfo.image_height) { row_pointer[0] = &buffer[cinfo.next_scanline * row_stride]; (void)jpeg_write_scanlines(&cinfo, row_pointer,1); } jpeg_finish_compress(&cinfo); fclose(outfile); jpeg_destroy_compress(&cinfo); return 0; }
Image ImageJpgFile (uint8_t * buf, uint32_t size) { ImageFile *Image; struct jpeg_decompress_struct cinfo; struct my_error_mgr jerr; int row_stride; /* physical row width in output buffer */ JSAMPARRAY buffer; int bufp; int i; // RGBcolor *out; /* ==== 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; if (setjmp(jerr.setjmp_buffer)) { jpeg_destroy_decompress(&cinfo); return NULL; } /* Now we can initialize the JPEG decompression object. */ jpeg_create_decompress (&cinfo); /* ==== Step 2: specify data source (memory buffer, in this case) */ jpeg_memory_src (&cinfo, (char *)buf, size); /* ==== Step 3: read file parameters with jpeg_read_header() */ (void) jpeg_read_header(&cinfo, TRUE); /* ==== Step 4: set parameters for decompression */ // We want max quality, doesnt matter too much it can be a bit slow // We almost always want RGB output (no grayscale, yuv etc) if (cinfo.jpeg_color_space != JCS_GRAYSCALE) cinfo.out_color_space = JCS_RGB; // Recalculate output image dimensions jpeg_calc_output_dimensions (&cinfo); /* ==== Step 5: Start decompressor */ (void) 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. * In this example, we need to make an output work buffer of the right size. */ Image = MakeImageFile(cinfo.output_width, cinfo.output_height); /* 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, cinfo.output_height); // read into the buffer upside down... for( i = 0; i < Image->height; i++ ) { if( Image->flags & IF_FLAG_INVERTED ) buffer[i] = (JSAMPROW)(Image->image + ( ( (Image->height - i) - 1 ) * Image->width )); else buffer[i] = (JSAMPROW)(Image->image + ( i * Image->width )); } /* ==== 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. */ bufp = 0; while (cinfo.output_scanline < cinfo.output_height) jpeg_read_scanlines( &cinfo, buffer + cinfo.output_scanline, cinfo.image_height ); /* blah! we're in 32 bit color space - and this reads * into 24 bit space - WHY oh WHY is that... ahh well * we need to update this */ for( i = 0; i < Image->height; i++ ) { int j; char *row; row = (char*)buffer[i]; for( j = Image->width; j > 0; j-- ) { row[j * 4 - 1] = (uint8_t)0xff; if( bGLColorMode ) { row[j * 4 - 2] = row[j*3-1]; row[j * 4 - 3] = row[j*3-2]; row[j * 4 - 4] = row[j*3-3]; } else { row[j * 4 - 2] = row[j*3-3]; row[j * 4 - 3] = row[j*3-2]; row[j * 4 - 4] = row[j*3-1]; } } } /* ==== Step 7: Finish decompression */ (void) jpeg_finish_decompress(&cinfo); /* We can ignore the return value since suspension is not possible * with the buffer 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); /* 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 Image; }
static gboolean real_save_jpeg (GdkPixbuf *pixbuf, gchar **keys, gchar **values, GError **error, gboolean to_callback, FILE *f, GdkPixbufSaveFunc save_func, gpointer user_data) { /* FIXME error handling is broken */ struct jpeg_compress_struct cinfo; guchar *buf = NULL; guchar *ptr; guchar *pixels = NULL; JSAMPROW *jbuf; int y = 0; volatile int quality = 75; /* default; must be between 0 and 100 */ int i, j; int w, h = 0; int rowstride = 0; int n_channels; struct error_handler_data jerr; ToFunctionDestinationManager to_callback_destmgr; gchar *icc_profile = NULL; gchar *data; gint retval = TRUE; gsize icc_profile_size = 0; to_callback_destmgr.buffer = NULL; if (keys && *keys) { gchar **kiter = keys; gchar **viter = values; while (*kiter) { if (strcmp (*kiter, "quality") == 0) { char *endptr = NULL; quality = strtol (*viter, &endptr, 10); if (endptr == *viter) { g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_BAD_OPTION, _("JPEG quality must be a value between 0 and 100; value '%s' could not be parsed."), *viter); retval = FALSE; goto cleanup; } if (quality < 0 || quality > 100) { /* This is a user-visible error; * lets people skip the range-checking * in their app. */ g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_BAD_OPTION, _("JPEG quality must be a value between 0 and 100; value '%d' is not allowed."), quality); retval = FALSE; goto cleanup; } } else if (strcmp (*kiter, "icc-profile") == 0) { /* decode from base64 */ icc_profile = (gchar*) g_base64_decode (*viter, &icc_profile_size); if (icc_profile_size < 127) { /* This is a user-visible error */ g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_BAD_OPTION, _("Color profile has invalid length '%u'."), (guint) icc_profile_size); retval = FALSE; goto cleanup; } } else { g_warning ("Unrecognized parameter (%s) passed to JPEG saver.", *kiter); } ++kiter; ++viter; } } rowstride = gdk_pixbuf_get_rowstride (pixbuf); n_channels = gdk_pixbuf_get_n_channels (pixbuf); w = gdk_pixbuf_get_width (pixbuf); h = gdk_pixbuf_get_height (pixbuf); pixels = gdk_pixbuf_get_pixels (pixbuf); /* Allocate a small buffer to convert image data, * and a larger buffer if doing to_callback save. */ buf = g_try_malloc (w * 3 * sizeof (guchar)); if (!buf) { g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, _("Couldn't allocate memory for loading JPEG file")); retval = FALSE; goto cleanup; } if (to_callback) { to_callback_destmgr.buffer = g_try_malloc (TO_FUNCTION_BUF_SIZE); if (!to_callback_destmgr.buffer) { g_set_error_literal (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, _("Couldn't allocate memory for loading JPEG file")); retval = FALSE; goto cleanup; } } /* set up error handling */ cinfo.err = jpeg_std_error (&(jerr.pub)); jerr.pub.error_exit = fatal_error_handler; jerr.pub.output_message = output_message_handler; jerr.error = error; if (sigsetjmp (jerr.setjmp_buffer, 1)) { jpeg_destroy_compress (&cinfo); retval = FALSE; goto cleanup; } /* setup compress params */ jpeg_create_compress (&cinfo); if (to_callback) { to_callback_destmgr.pub.init_destination = to_callback_init; to_callback_destmgr.pub.empty_output_buffer = to_callback_empty_output_buffer; to_callback_destmgr.pub.term_destination = to_callback_terminate; to_callback_destmgr.error = error; to_callback_destmgr.save_func = save_func; to_callback_destmgr.user_data = user_data; cinfo.dest = (struct jpeg_destination_mgr*) &to_callback_destmgr; } else { jpeg_stdio_dest (&cinfo, f); } cinfo.image_width = w; cinfo.image_height = h; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; /* set up jepg compression parameters */ jpeg_set_defaults (&cinfo); jpeg_set_quality (&cinfo, quality, TRUE); jpeg_start_compress (&cinfo, TRUE); /* write ICC profile data */ if (icc_profile != NULL) { /* optimise for the common case where only one APP2 segment is required */ if (icc_profile_size < 0xffef) { data = g_new (gchar, icc_profile_size + 14); memcpy (data, "ICC_PROFILE\000\001\001", 14); memcpy (data + 14, icc_profile, icc_profile_size); jpeg_write_marker (&cinfo, JPEG_APP0+2, (const JOCTET *) data, icc_profile_size + 14); g_free (data); } else { guint segments; guint size = 0xffef; guint offset; segments = (guint) ceilf ((gfloat) icc_profile_size / (gfloat) 0xffef); data = g_new (gchar, 0xffff); memcpy (data, "ICC_PROFILE\000", 12); data[13] = segments; for (i=0; i<=segments; i++) { data[12] = i; offset = 0xffef * i; /* last segment */ if (i == segments) size = icc_profile_size % 0xffef; memcpy (data + 14, icc_profile + offset, size); jpeg_write_marker (&cinfo, JPEG_APP0+2, (const JOCTET *) data, size + 14); } g_free (data); } } /* get the start pointer */ ptr = pixels; /* go one scanline at a time... and save */ i = 0; while (cinfo.next_scanline < cinfo.image_height) { /* convert scanline from ARGB to RGB packed */ for (j = 0; j < w; j++) memcpy (&(buf[j*3]), &(ptr[i*rowstride + j*n_channels]), 3); /* write scanline */ jbuf = (JSAMPROW *)(&buf); jpeg_write_scanlines (&cinfo, jbuf, 1); i++; y++; } /* finish off */ jpeg_finish_compress (&cinfo); jpeg_destroy_compress(&cinfo); cleanup: g_free (buf); g_free (to_callback_destmgr.buffer); g_free (icc_profile); return retval; }
/* Callback function for the render out button. */ void AnimatedSGWindow::renderCB(Fl_Widget *w, void *data) { VOID_TO_ASGWIN(data); std::cout << "Rendering out animation to local directory." << std::endl; aSGWin->timeline->value(0); AnimatedSGWindow::timelineCB(aSGWin->timeline, data); Fl::flush(); for (int count = 0; count <= aSGWin->timeline->maximum(); count++) { ////////////////////////////////////////////////////////// // Code for outputing FL_GL_Window to a jpeg file!!! std::string s; std::stringstream out; // a stream for outputing to a string out << count; // make the current count into a string s = out.str(); std::string filename = "anim\\testing_" + s + ".jpg"; // compose the file name // Make the BYTE array, factor of 3 because it's RBG. int width = aSGWin->glWin->w(); int height = aSGWin->glWin->h(); BYTE* pixels = new BYTE[3 * width * height]; glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, pixels); struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; /* this is a pointer to one row of image data */ JSAMPROW row_pointer[1]; FILE *outfile = NULL; fopen_s(&outfile, filename.c_str(), "wb"); if (!outfile) { std::cout << "Error opening output jpeg file:" << filename << std::endl; return; } cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, outfile); /* Setting the parameters of the output file here */ cinfo.image_width = width; cinfo.image_height = height; cinfo.input_components = 3; // bytes_per_pixel; cinfo.in_color_space = JCS_RGB; // color_space; /* default compression parameters, we shouldn't be worried about these */ jpeg_set_defaults(&cinfo); /* Now do the compression .. */ jpeg_start_compress(&cinfo, TRUE); /* like reading a file, this time write one row at a time */ std::list<JDIMENSION> lines; // switch the image to right side up unsigned int cnt = 0; while (cnt < cinfo.image_height) { lines.push_front(cnt); cnt++; } std::list<JDIMENSION>::iterator it; for (it = lines.begin(); it != lines.end(); ++it){ row_pointer[0] = &pixels[(*it) * cinfo.image_width * cinfo.input_components]; jpeg_write_scanlines(&cinfo, row_pointer, 1); } /* similar to read file, clean up after we're done compressing */ jpeg_finish_compress(&cinfo); jpeg_destroy_compress(&cinfo); fclose(outfile); delete[] pixels; ///////////////////////////////////////////////////////////////////// /* Move the animation forwards */ AnimatedSGWindow::forwardCB(aSGWin->forwardB, data); /* Forces out the redraw */ Fl::flush(); } aSGWin->timeline->value(0); AnimatedSGWindow::timelineCB(aSGWin->timeline, data); std::cout << "Rendering out complete." << std::endl; }
/*read jpeg*/ unsigned char* image_read_jpeg_file( char *filename ) { //int** imageMat = NULL; unsigned char *raw_image = NULL; /* 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. */ /*get input image width and height*/ width = cinfo.image_width; height = cinfo.image_height; components_per_pixel = cinfo.num_components; color_space = cinfo.jpeg_color_space; /* decompression of the jpeg */ 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 ); /* 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]; } /* 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 ); return raw_image; }
int loadJPG(ePtr<gPixmap> &result, const char *filename, ePtr<gPixmap> alpha) { struct jpeg_decompress_struct cinfo; struct my_error_mgr jerr; JSAMPARRAY buffer; int row_stride; CFile infile(filename, "rb"); result = 0; if (alpha) { if (alpha->surface->bpp != 8) { eWarning("[loadJPG] alpha channel for jpg must be 8bit"); alpha = 0; } } if (!infile) return -1; cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = my_error_exit; if (setjmp(jerr.setjmp_buffer)) { result = 0; jpeg_destroy_decompress(&cinfo); return -1; } jpeg_create_decompress(&cinfo); jpeg_stdio_src(&cinfo, infile); (void) jpeg_read_header(&cinfo, TRUE); cinfo.out_color_space = JCS_RGB; cinfo.scale_denom = 1; (void) jpeg_start_decompress(&cinfo); int grayscale = cinfo.output_components == 1; if (alpha) { if (((int)cinfo.output_width != alpha->surface->x) || ((int)cinfo.output_height != alpha->surface->y)) { eWarning("[loadJPG] alpha channel size (%dx%d) must match jpeg size (%dx%d)", alpha->surface->x, alpha->surface->y, cinfo.output_width, cinfo.output_height); alpha = 0; } if (grayscale) { eWarning("[loadJPG] no support for grayscale + alpha at the moment"); alpha = 0; } } result = new gPixmap(eSize(cinfo.output_width, cinfo.output_height), grayscale ? 8 : 32); row_stride = cinfo.output_width * cinfo.output_components; buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); while (cinfo.output_scanline < cinfo.output_height) { int y = cinfo.output_scanline; (void) jpeg_read_scanlines(&cinfo, buffer, 1); unsigned char *dst = ((unsigned char*)result->surface->data) + result->surface->stride * y; unsigned char *src = (unsigned char*)buffer[0]; unsigned char *palpha = alpha ? ((unsigned char*)alpha->surface->data + alpha->surface->stride * y) : 0; if (grayscale) memcpy(dst, src, cinfo.output_width); else { if (palpha) { for (int x = (int)cinfo.output_width; x != 0; --x) { *dst++ = src[2]; *dst++ = src[1]; *dst++ = src[0]; *dst++ = *palpha++; src += 3; } } else { for (int x = (int)cinfo.output_width; x != 0; --x) { *dst++ = src[2]; *dst++ = src[1]; *dst++ = src[0]; *dst++ = 0xFF; src += 3; } } } } (void) jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); return 0; }
void serializeImage(const ImageData &im, file::buffer &bf, const char *format) { #ifdef OX_HAVE_LIBJPEG char *filename = (char *)"test_jpeg.jpg"; int quality = 50; struct jpeg_compress_struct cinfo; // basic info for JPEG properties struct jpeg_error_mgr jerr; // in case of error FILE * outfile = 0; // target file JSAMPROW row_pointer[1]; // pointer to JSAMPLE row[s] int row_stride; // physical row width in image buffer //## ALLOCATE AND INITIALIZE JPEG COMPRESSION OBJECT cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); //## OPEN FILE FOR DATA DESTINATION: /* if ((outfile = fopen(filename, "wb")) == NULL) { fprintf(stderr, "ERROR: can't open %s\n", filename); exit(1); } */ cinfo.dest = 0; //## SET PARAMETERS FOR COMPRESSION: cinfo.image_width = 20; // |-- image width and height in pixels cinfo.image_height = 20; // | cinfo.input_components = 3; // number of color components per pixel cinfo.in_color_space = JCS_RGB; // colorspace of input image as RGB jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, quality, TRUE); //## CREATE IMAGE BUFFER TO WRITE FROM AND MODIFY THE IMAGE TO LOOK LIKE CHECKERBOARD: unsigned char *image_buffer = NULL; image_buffer = (unsigned char*)malloc( cinfo.image_width*cinfo.image_height*cinfo.num_components ); for(size_t y=0;y<cinfo.image_height; y++) for(size_t x=0;x<cinfo.image_width; x++) { unsigned int pixelIdx = ((y*cinfo.image_height)+x) * cinfo.input_components; if(x%2==y%2) { image_buffer[pixelIdx+0] = 255; // r |-- set r,g,b components to image_buffer[pixelIdx+1] = 0; // g | make this pixel red image_buffer[pixelIdx+2] = 0; // b | (255,0,0) } else { image_buffer[pixelIdx+0] = 255; // r |-- set r,g,b components to image_buffer[pixelIdx+1] = 255; // g | make this pixel white image_buffer[pixelIdx+2] = 255; // b | (255,255,255) } } //## START COMPRESSION: jpeg_start_compress(&cinfo, TRUE); row_stride = cinfo.image_width * 3; // JSAMPLEs per row in image_buffer while (cinfo.next_scanline < cinfo.image_height) { row_pointer[0] = &image_buffer[cinfo.next_scanline * row_stride]; (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); } // NOTE: jpeg_write_scanlines expects an array of pointers to scanlines. // Here the array is only one element long, but you could pass // more than one scanline at a time if that's more convenient. //## FINISH COMPRESSION AND CLOSE FILE: jpeg_finish_compress(&cinfo); fclose(outfile); jpeg_destroy_compress(&cinfo); printf("SUCCESS\n"); #endif }
static gboolean _gdk_pixbuf_save_as_jpeg (GdkPixbuf *pixbuf, const char *filename, char **keys, char **values, GError **error) { struct jpeg_compress_struct cinfo; struct error_handler_data jerr; FILE *file; guchar *buf = NULL; guchar *ptr; guchar *pixels = NULL; volatile int quality = 85; /* default; must be between 0 and 100 */ volatile int smoothing = 0; volatile gboolean optimize = FALSE; volatile gboolean progressive = FALSE; int i, j; int w, h = 0; int rowstride = 0; volatile int bpp; if (keys && *keys) { char **kiter = keys; char **viter = values; while (*kiter) { if (strcmp (*kiter, "quality") == 0) { char *endptr = NULL; quality = strtol (*viter, &endptr, 10); if (endptr == *viter) { g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_BAD_OPTION, "JPEG quality must be a value between 0 and 100; value '%s' could not be parsed.", *viter); return FALSE; } if (quality < 0 || quality > 100) { g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_BAD_OPTION, "JPEG quality must be a value between 0 and 100; value '%d' is not allowed.", quality); return FALSE; } } else if (strcmp (*kiter, "smooth") == 0) { char *endptr = NULL; smoothing = strtol (*viter, &endptr, 10); if (endptr == *viter) { g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_BAD_OPTION, "JPEG smoothing must be a value between 0 and 100; value '%s' could not be parsed.", *viter); return FALSE; } if (smoothing < 0 || smoothing > 100) { g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_BAD_OPTION, "JPEG smoothing must be a value between 0 and 100; value '%d' is not allowed.", smoothing); return FALSE; } } else if (strcmp (*kiter, "optimize") == 0) { if (strcmp (*viter, "yes") == 0) optimize = TRUE; else if (strcmp (*viter, "no") == 0) optimize = FALSE; else { g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_BAD_OPTION, "JPEG optimize option must be 'yes' or 'no', value is: %s", *viter); return FALSE; } } else if (strcmp (*kiter, "progressive") == 0) { if (strcmp (*viter, "yes") == 0) progressive = TRUE; else if (strcmp (*viter, "no") == 0) progressive = FALSE; else { g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_BAD_OPTION, "JPEG progressive option must be 'yes' or 'no', value is: %s", *viter); return FALSE; } } else { g_warning ("Bad option name '%s' passed to JPEG saver", *kiter); return FALSE; } ++kiter; ++viter; } } file = fopen (filename, "wb"); if (file == NULL) { g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED, "Can't write image to file '%s'", filename); return FALSE; } rowstride = gdk_pixbuf_get_rowstride (pixbuf); w = gdk_pixbuf_get_width (pixbuf); h = gdk_pixbuf_get_height (pixbuf); if (gdk_pixbuf_get_has_alpha (pixbuf)) bpp = 4; else bpp = 3; /* no image data? abort */ pixels = gdk_pixbuf_get_pixels (pixbuf); g_return_val_if_fail (pixels != NULL, FALSE); /* allocate a small buffer to convert image data */ buf = g_try_malloc (w * bpp * sizeof (guchar)); if (! buf) { g_set_error (error, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, "Couldn't allocate memory for loading JPEG file"); return FALSE; } /* set up error handling */ cinfo.err = jpeg_std_error (&(jerr.pub)); jerr.pub.error_exit = fatal_error_handler; jerr.pub.output_message = output_message_handler; jerr.error = error; if (sigsetjmp (jerr.setjmp_buffer, 1)) { jpeg_destroy_compress (&cinfo); g_free (buf); return FALSE; } /* setup compress params */ jpeg_create_compress (&cinfo); jpeg_stdio_dest (&cinfo, file); cinfo.image_width = w; cinfo.image_height = h; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; /* set up jepg compression parameters */ jpeg_set_defaults (&cinfo); jpeg_set_quality (&cinfo, quality, TRUE); cinfo.smoothing_factor = smoothing; cinfo.optimize_coding = optimize; #ifdef HAVE_PROGRESSIVE_JPEG if (progressive) jpeg_simple_progression (&cinfo); #endif /* HAVE_PROGRESSIVE_JPEG */ jpeg_start_compress (&cinfo, TRUE); /* get the start pointer */ ptr = pixels; /* go one scanline at a time... and save */ i = 0; while (cinfo.next_scanline < cinfo.image_height) { JSAMPROW *jbuf; /* convert scanline from ARGB to RGB packed */ for (j = 0; j < w; j++) memcpy (&(buf[j * 3]), &(ptr[i * rowstride + j * bpp]), 3); /* write scanline */ jbuf = (JSAMPROW *)(&buf); jpeg_write_scanlines (&cinfo, jbuf, 1); i++; } /* finish off */ jpeg_finish_compress (&cinfo); fclose (file); jpeg_destroy_compress(&cinfo); g_free (buf); return TRUE; }
static void load_jpg_entry_helper(ALLEGRO_FILE *fp, struct load_jpg_entry_helper_data *data, int flags) { struct jpeg_decompress_struct cinfo; struct my_err_mgr jerr; ALLEGRO_LOCKED_REGION *lock; int w, h, s; /* ALLEGRO_NO_PREMULTIPLIED_ALPHA does not apply. * ALLEGRO_KEEP_INDEX does not apply. */ (void)flags; data->error = false; cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = my_error_exit; if (setjmp(jerr.jmpenv) != 0) { /* Longjmp'd. */ data->error = true; goto longjmp_error; } data->buffer = al_malloc(BUFFER_SIZE); if (!data->buffer) { data->error = true; goto error; } jpeg_create_decompress(&cinfo); jpeg_packfile_src(&cinfo, fp, data->buffer); jpeg_read_header(&cinfo, true); jpeg_start_decompress(&cinfo); w = cinfo.output_width; h = cinfo.output_height; s = cinfo.output_components; /* Only one and three components make sense in a JPG file. */ if (s != 1 && s != 3) { data->error = true; ALLEGRO_ERROR("%d components makes no sense\n", s); goto error; } data->bmp = al_create_bitmap(w, h); if (!data->bmp) { data->error = true; ALLEGRO_ERROR("%dx%d bitmap creation failed\n", w, h); goto error; } /* Allegro's pixel format is endian independent, so that in * ALLEGRO_PIXEL_FORMAT_RGB_888 the lower 8 bits always hold the Blue * component. On a little endian system this is in byte 0. On a big * endian system this is in byte 2. * * libjpeg expects byte 0 to hold the Red component, byte 1 to hold the * Green component, byte 2 to hold the Blue component. Hence on little * endian systems we need the opposite format, ALLEGRO_PIXEL_FORMAT_BGR_888. */ #ifdef ALLEGRO_BIG_ENDIAN lock = al_lock_bitmap(data->bmp, ALLEGRO_PIXEL_FORMAT_RGB_888, ALLEGRO_LOCK_WRITEONLY); #else lock = al_lock_bitmap(data->bmp, ALLEGRO_PIXEL_FORMAT_BGR_888, ALLEGRO_LOCK_WRITEONLY); #endif if (s == 3) { /* Colour. */ int y; for (y = cinfo.output_scanline; y < h; y = cinfo.output_scanline) { unsigned char *out[1]; out[0] = ((unsigned char *)lock->data) + y * lock->pitch; jpeg_read_scanlines(&cinfo, (void *)out, 1); } } else if (s == 1) { /* Greyscale. */ unsigned char *in; unsigned char *out; int x, y; data->row = al_malloc(w); for (y = cinfo.output_scanline; y < h; y = cinfo.output_scanline) { jpeg_read_scanlines(&cinfo, (void *)&data->row, 1); in = data->row; out = ((unsigned char *)lock->data) + y * lock->pitch; for (x = 0; x < w; x++) { *out++ = *in; *out++ = *in; *out++ = *in; in++; } } } error: jpeg_finish_decompress(&cinfo); longjmp_error: jpeg_destroy_decompress(&cinfo); if (data->bmp) { if (al_is_bitmap_locked(data->bmp)) { al_unlock_bitmap(data->bmp); } if (data->error) { al_destroy_bitmap(data->bmp); data->bmp = NULL; } } al_free(data->buffer); al_free(data->row); }
void R_LoadJPG(const char *filename, 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 = {NULL}; /* 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. */ q_jpeg_error_mgr_t jerr; /* More stuff */ JSAMPARRAY buffer; /* Output row buffer */ unsigned int row_stride; /* physical row width in output buffer */ unsigned int pixelcount, memcount; unsigned int sindex, dindex; byte *out; int len; union { byte *b; void *v; } fbuffer; byte *buf; /* In this example we want to open the input file before doing anything else, * so that the setjmp() error recovery below can assume the file is open. * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that * requires it in order to read binary files. */ len = ri.FS_ReadFile ( ( char * ) filename, &fbuffer.v); if (!fbuffer.b || len < 0) { return; } /* Step 1: allocate and initialize JPEG decompression object */ /* We have to set up the error handler first, in case the initialization * step fails. (Unlikely, but it could happen if you are out of memory.) * This routine fills in the contents of struct jerr, and returns jerr's * address which we place into the link field in cinfo. */ cinfo.err = jpeg_std_error(&jerr.pub); cinfo.err->error_exit = R_JPGErrorExit; cinfo.err->output_message = R_JPGOutputMessage; /* Establish the setjmp return context for R_JPGErrorExit 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); ri.FS_FreeFile(fbuffer.v); /* Append the filename to the error for easier debugging */ ri.Printf(PRINT_ALL, ", loading file %s\n", filename); return; } /* Now we can initialize the JPEG decompression object. */ jpeg_create_decompress(&cinfo); /* Step 2: specify data source (eg, a file) */ jpeg_mem_src(&cinfo, fbuffer.b, len); /* 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 */ /* * Make sure it always converts images to RGB color space. This will * automatically convert 8-bit greyscale images to RGB as well. */ cinfo.out_color_space = JCS_RGB; /* Step 5: Start decompressor */ (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 */ pixelcount = cinfo.output_width * cinfo.output_height; if(!cinfo.output_width || !cinfo.output_height || ((pixelcount * 4) / cinfo.output_width) / 4 != cinfo.output_height || pixelcount > 0x1FFFFFFF || cinfo.output_components != 3 ) { // Free the memory to make sure we don't leak memory ri.FS_FreeFile (fbuffer.v); jpeg_destroy_decompress(&cinfo); ri.Error(ERR_DROP, "LoadJPG: %s has an invalid image format: %dx%d*4=%d, components: %d", filename, cinfo.output_width, cinfo.output_height, pixelcount * 4, cinfo.output_components); } memcount = pixelcount * 4; row_stride = cinfo.output_width * cinfo.output_components; out = ri.Malloc(memcount); *width = cinfo.output_width; *height = cinfo.output_height; /* Step 6: while (scan lines remain to be read) */ /* jpeg_read_scanlines(...); */ /* Here we use the library's state variable cinfo.output_scanline as the * loop counter, so that we don't have to keep track ourselves. */ while (cinfo.output_scanline < cinfo.output_height) { /* jpeg_read_scanlines expects an array of pointers to scanlines. * Here the array is only one element long, but you could ask for * more than one scanline at a time if that's more convenient. */ buf = ((out+(row_stride*cinfo.output_scanline))); buffer = &buf; (void) jpeg_read_scanlines(&cinfo, buffer, 1); } buf = out; // Expand from RGB to RGBA sindex = pixelcount * cinfo.output_components; dindex = memcount; do { buf[--dindex] = 255; buf[--dindex] = buf[--sindex]; buf[--dindex] = buf[--sindex]; buf[--dindex] = buf[--sindex]; } while(sindex); *pic = out; /* Step 7: Finish decompression */ jpeg_finish_decompress(&cinfo); /* We can ignore the return value since suspension is not possible * with the stdio data source. */ /* Step 8: Release JPEG decompression object */ /* This is an important step since it will release a good deal of memory. */ jpeg_destroy_decompress(&cinfo); /* After finish_decompress, we can close the input file. * Here we postpone it until after no more JPEG errors are possible, * so as to simplify the setjmp error logic above. (Actually, I don't * think that jpeg_destroy can do an error exit, but why assume anything...) */ ri.FS_FreeFile (fbuffer.v); /* At this point you may want to check to see whether any corrupt-data * warnings occurred (test whether jerr.pub.num_warnings is nonzero). */ /* And we're done! */ }
cairo_surface_t* guacenc_jpeg_decoder(unsigned char* data, int length) { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; /* Create decompressor with standard error handling */ jpeg_create_decompress(&cinfo); cinfo.err = jpeg_std_error(&jerr); /* Read JPEG directly from memory buffer */ jpeg_mem_src(&cinfo, data, length); /* Read and validate JPEG header */ if (!jpeg_read_header(&cinfo, TRUE)) { guacenc_log(GUAC_LOG_WARNING, "Invalid JPEG data"); jpeg_destroy_decompress(&cinfo); return NULL; } /* Begin decompression */ cinfo.out_color_space = JCS_RGB; jpeg_start_decompress(&cinfo); /* Pull JPEG dimensions from decompressor */ int width = cinfo.output_width; int height = cinfo.output_height; /* Allocate sufficient buffer space for one JPEG scanline */ unsigned char* jpeg_scanline = malloc(width * 3); /* Create blank Cairo surface (no transparency in JPEG) */ cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, width, height); /* Pull underlying buffer and its stride */ int stride = cairo_image_surface_get_stride(surface); unsigned char* row = cairo_image_surface_get_data(surface); /* Read JPEG into surface */ while (cinfo.output_scanline < height) { /* Read single scanline */ unsigned char* buffers[1] = { jpeg_scanline }; jpeg_read_scanlines(&cinfo, buffers, 1); /* Copy scanline to Cairo surface */ guacenc_jpeg_copy_scanline(row, jpeg_scanline, width); /* Advance to next row of Cairo surface */ row += stride; } /* Scanline buffer is no longer needed */ free(jpeg_scanline); /* End decompression */ jpeg_finish_decompress(&cinfo); /* Free decompressor */ jpeg_destroy_decompress(&cinfo); /* JPEG was read successfully */ return surface; }