std::optional<ImageData2D> JpegImporter::doImage2D(UnsignedInt) { /* Initialize structures */ jpeg_decompress_struct file; JSAMPARRAY rows = nullptr; unsigned char* data = nullptr; /* Fugly error handling stuff */ /** @todo Get rid of this crap */ struct ErrorManager { jpeg_error_mgr jpegErrorManager; std::jmp_buf setjmpBuffer; } errorManager; file.err = jpeg_std_error(&errorManager.jpegErrorManager); errorManager.jpegErrorManager.error_exit = [](j_common_ptr info) { info->err->output_message(info); std::longjmp(reinterpret_cast<ErrorManager*>(info->err)->setjmpBuffer, 1); }; if(setjmp(errorManager.setjmpBuffer)) { Error() << "Trade::JpegImporter::image2D(): error while reading JPEG file"; jpeg_destroy_decompress(&file); delete[] rows; delete[] data; return std::nullopt; } /* Open file */ jpeg_create_decompress(&file); jpeg_mem_src(&file, _in.begin(), _in.size()); /* Read file header, start decompression */ jpeg_read_header(&file, true); jpeg_start_decompress(&file); /* Image size and type */ const Vector2i size(file.output_width, file.output_height); static_assert(BITS_IN_JSAMPLE == 8, "Only 8-bit JPEG is supported"); constexpr const ImageType type = ImageType::UnsignedByte; /* Image format */ ImageFormat format; switch(file.out_color_space) { case JCS_GRAYSCALE: CORRADE_INTERNAL_ASSERT(file.out_color_components == 1); #ifdef MAGNUM_TARGET_GLES format = Context::current() && Context::current()->isExtensionSupported<Extensions::GL::EXT::texture_rg>() ? ImageFormat::Red : ImageFormat::Luminance; #else format = ImageFormat::Red; #endif break; case JCS_RGB: CORRADE_INTERNAL_ASSERT(file.out_color_components == 3); format = ImageFormat::RGB; break; /** @todo RGBA (only in libjpeg-turbo and probably ignored) */ default: Error() << "Trade::JpegImporter::image2D(): unsupported color space" << file.out_color_space; } /* Initialize data array */ data = new unsigned char[size.product()*file.out_color_components*BITS_IN_JSAMPLE/8]; /* Read image row by row */ rows = new JSAMPROW[size.y()]; const Int stride = size.x()*file.out_color_components*BITS_IN_JSAMPLE/8; for(Int i = 0; i != size.y(); ++i) rows[i] = data + (size.y() - i - 1)*stride; while(file.output_scanline < file.output_height) jpeg_read_scanlines(&file, rows+file.output_scanline, file.output_height-file.output_scanline); delete[] rows; rows = nullptr; /* Cleanup */ jpeg_finish_decompress(&file); jpeg_destroy_decompress(&file); return Trade::ImageData2D(format, type, size, data); }
GLuint loadTextureFromJPEG(const char* filename, int &width, int &height){ AAsset* pAsset = NULL; struct jpeg_decompress_struct cInfo; struct jpeg_error_mgr jError; cInfo.err = jpeg_std_error(&jError); // register error handler 1 jError.error_exit = _JpegError; // register error handler 2 jpeg_create_decompress(&cInfo); // create a decompresser // load from asset pAsset = AAssetManager_open(mgr, filename, AASSET_MODE_UNKNOWN); if (!pAsset) { LOGD("!pAsset"); return NULL; } unsigned char* ucharRawData = (unsigned char*)AAsset_getBuffer(pAsset); long myAssetLength = (long)AAsset_getLength(pAsset); // the jpeg_stdio_src alternative func, which is also included in IJG's lib. jpeg_mem_src(&cInfo, ucharRawData, myAssetLength); uint32_t* pTexUint; int yy; int pixelSize, lineSize; char* lpbtBits; JSAMPLE tmp; int rectHeight, rectWidth; jpeg_read_header(&cInfo, TRUE); // read header jpeg_start_decompress(&cInfo); // start decompression //LOGD("cInfo %i - %i",cInfo.output_width,cInfo.output_height); width = cInfo.output_width; height = height = cInfo.output_height; pixelSize = cInfo.output_components; lineSize = width * pixelSize; pTexUint = (uint32_t*)calloc(sizeof(uint32_t), width * height); if (pTexUint == NULL){ AAsset_close(pAsset); return NULL; } JSAMPLE* pSample = (JSAMPLE*)calloc(sizeof(JSAMPLE), lineSize + 10); if (!pSample){ LOGE("Jpeg Lib","cannot alloc pSample"); if (pTexUint) free(pTexUint); AAsset_close(pAsset); return NULL; //error } JSAMPROW buffer[1]; buffer[0] = pSample; uint32_t* pPixelsUint = pTexUint; yy = 0; while(cInfo.output_scanline < cInfo.output_height){ if(yy >= cInfo.output_height) break; jpeg_read_scanlines(&cInfo, buffer, 1); int xx; int x3; for(xx = 0, x3 = 0; xx < width; xx++, x3 += 3) pPixelsUint[xx] = make8888(buffer[0][x3], buffer[0][x3 + 1], buffer[0][x3 + 2], 0xff); pPixelsUint = (uint32_t*)pPixelsUint + width; yy++; } //LOGD("sizeof(*pPixelsUint) = %i", sizeof(*pPixelsUint)); GLuint texture; glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)pTexUint); jpeg_finish_decompress(&cInfo); jpeg_destroy_decompress(&cInfo); if (pSample) free(pSample); AAsset_close(pAsset); //free(pTexUint); return texture; //return (unsigned char*)pTexUint; }
bool BitmapData::initWithJPGData(const unsigned char *data, ssize_t size) { struct jpeg_decompress_struct cinfo; JpgError jerr; JSAMPROW row_pointer[1] = {0}; unsigned long location = 0; unsigned int i = 0; cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = myErrorExit; if (setjmp(jerr.setjmp_buffer)) { jpeg_destroy_decompress(&cinfo); return false; } jpeg_create_decompress(&cinfo); #ifndef CC_TARGET_QT5 jpeg_mem_src( &cinfo, const_cast<unsigned char*>(data), size); #endif /* CC_TARGET_QT5 */ #if (JPEG_LIB_VERSION >= 90) jpeg_read_header( &cinfo, TRUE ); #else jpeg_read_header( &cinfo, true ); #endif if (cinfo.jpeg_color_space == JCS_GRAYSCALE) { _renderFormat = Texture2D::PixelFormat::I8; } else { cinfo.out_color_space = JCS_RGB; _renderFormat = Texture2D::PixelFormat::RGB888; } jpeg_start_decompress(&cinfo); _width = cinfo.output_width; _height = cinfo.output_height; row_pointer[0] = static_cast<unsigned char*>(malloc(cinfo.output_width*cinfo.output_components * sizeof(unsigned char))); _dataSize = cinfo.output_width*cinfo.output_height*cinfo.output_components; _data = static_cast<unsigned char*>(malloc(_dataSize * sizeof(unsigned char))); 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++) { _data[location++] = row_pointer[0][i]; } } jpeg_destroy_decompress(&cinfo); if (row_pointer[0] != nullptr) { free(row_pointer[0]); }; _alpha = false; return true; }
bool CJpegIO::Read(unsigned char* buffer, unsigned int bufSize, unsigned int minx, unsigned int miny) { struct my_error_mgr jerr; m_cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = jpeg_error_exit; if (buffer == NULL || !bufSize ) return false; jpeg_create_decompress(&m_cinfo); #if JPEG_LIB_VERSION < 80 x_mem_src(&m_cinfo, buffer, bufSize); #else jpeg_mem_src(&m_cinfo, buffer, bufSize); #endif if (setjmp(jerr.setjmp_buffer)) { jpeg_destroy_decompress(&m_cinfo); return false; } else { jpeg_save_markers (&m_cinfo, JPEG_APP0 + 1, 0xFFFF); jpeg_read_header(&m_cinfo, true); /* libjpeg can scale the image for us if it is too big. It must be in the format num/denom, where (for our purposes) that is [1-8]/8 where 8/8 is the unscaled image. The only way to know how big a resulting image will be is to try a ratio and test its resulting size. If the res is greater than the one desired, use that one since there's no need to decode a bigger one just to squish it back down. If the res is greater than the gpu can hold, use the previous one.*/ if (minx == 0 || miny == 0) { miny = g_advancedSettings.m_imageRes; if (g_advancedSettings.m_fanartRes > g_advancedSettings.m_imageRes) { // a separate fanart resolution is specified - check if the image is exactly equal to this res if (m_cinfo.image_width == (unsigned int)g_advancedSettings.m_fanartRes * 16/9 && m_cinfo.image_height == (unsigned int)g_advancedSettings.m_fanartRes) { // special case for fanart res miny = g_advancedSettings.m_fanartRes; } } minx = miny * 16/9; } m_cinfo.scale_denom = 8; m_cinfo.out_color_space = JCS_RGB; unsigned int maxtexsize = g_Windowing.GetMaxTextureSize(); for (unsigned int scale = 1; scale <= 8; scale++) { m_cinfo.scale_num = scale; jpeg_calc_output_dimensions(&m_cinfo); if ((m_cinfo.output_width > maxtexsize) || (m_cinfo.output_height > maxtexsize)) { m_cinfo.scale_num--; break; } if (m_cinfo.output_width >= minx && m_cinfo.output_height >= miny) break; } jpeg_calc_output_dimensions(&m_cinfo); m_width = m_cinfo.output_width; m_height = m_cinfo.output_height; if (m_cinfo.marker_list) m_orientation = GetExifOrientation(m_cinfo.marker_list->data, m_cinfo.marker_list->data_length); return true; } }
size_t Jpeg::Leanify(size_t size_leanified /*= 0*/) { struct jpeg_decompress_struct srcinfo; struct jpeg_compress_struct dstinfo; struct jpeg_error_mgr jsrcerr, jdsterr; srcinfo.err = jpeg_std_error(&jsrcerr); jsrcerr.error_exit = mozjpeg_error_handler; if (setjmp(setjmp_buffer)) { jpeg_destroy_compress(&dstinfo); jpeg_destroy_decompress(&srcinfo); return Format::Leanify(size_leanified); } jpeg_create_decompress(&srcinfo); dstinfo.err = jpeg_std_error(&jdsterr); jdsterr.error_exit = mozjpeg_error_handler; jpeg_create_compress(&dstinfo); if (is_verbose) { dstinfo.err->trace_level++; } if (is_fast) { jpeg_c_set_int_param(&dstinfo, JINT_COMPRESS_PROFILE, JCP_FASTEST); } /* Specify data source for decompression */ jpeg_mem_src(&srcinfo, fp_, size_); // Always save exif to show warning if orientation might change. jpeg_save_markers(&srcinfo, JPEG_APP0 + 1, 0xFFFF); if (keep_icc_profile_ || keep_all_metadata_) { jpeg_save_markers(&srcinfo, JPEG_APP0 + 2, 0xFFFF); } if (keep_all_metadata_) { // Save the rest APPn markers. for (int i = 3; i < 16; i++) jpeg_save_markers(&srcinfo, JPEG_APP0 + i, 0xFFFF); // Save comments. jpeg_save_markers(&srcinfo, JPEG_COM, 0xFFFF); } (void)jpeg_read_header(&srcinfo, true); /* Read source file as DCT coefficients */ auto coef_arrays = jpeg_read_coefficients(&srcinfo); /* Initialize destination compression parameters from source values */ jpeg_copy_critical_parameters(&srcinfo, &dstinfo); // use arithmetic coding if input file is arithmetic coded if (srcinfo.arith_code) { dstinfo.arith_code = true; dstinfo.optimize_coding = false; } else { dstinfo.optimize_coding = true; } uint8_t* outbuffer = nullptr; unsigned long outsize = 0; /* Specify data destination for compression */ jpeg_mem_dest(&dstinfo, &outbuffer, &outsize); /* Start compressor (note no image data is actually written here) */ jpeg_write_coefficients(&dstinfo, coef_arrays); for (auto marker = srcinfo.marker_list; marker; marker = marker->next) { if (marker->marker == JPEG_APP0 + 1 && !keep_exif_ && !keep_all_metadata_) { // Tag number: 0x0112, data format: unsigned short(3), number of components: 1 const uint8_t kExifOrientation[] = { 0x12, 0x01, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00 }; const uint8_t kExifOrientationMotorola[] = { 0x01, 0x12, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01 }; uint8_t* start = marker->data; uint8_t* end = start + marker->data_length; if (std::search(start, end, kExifOrientation, std::end(kExifOrientation)) != end || std::search(start, end, kExifOrientationMotorola, std::end(kExifOrientationMotorola)) != end) { std::cout << "Warning: The Exif being removed contains orientation data, result image might have wrong " "orientation, use --keep-exif to keep Exif." << std::endl; } continue; } jpeg_write_marker(&dstinfo, marker->marker, marker->data, marker->data_length); } /* Finish compression and release memory */ jpeg_finish_compress(&dstinfo); (void)jpeg_finish_decompress(&srcinfo); jpeg_destroy_decompress(&srcinfo); fp_ -= size_leanified; // use mozjpeg result if it's smaller than original if (outsize < size_) { memcpy(fp_, outbuffer, outsize); size_ = outsize; } else { memmove(fp_, fp_ + size_leanified, size_); } jpeg_destroy_compress(&dstinfo); return size_; }
int v4lconvert_decode_jpeg_libjpeg(struct v4lconvert_data *data, unsigned char *src, int src_size, unsigned char *dest, struct v4l2_format *fmt, unsigned int dest_pix_fmt) { unsigned int width = fmt->fmt.pix.width; unsigned int height = fmt->fmt.pix.height; int result = 0; /* libjpeg errors before decoding the first line should signal EAGAIN */ data->jerr_errno = EAGAIN; result = setjmp(data->jerr_jmp_state); if (result) { if (data->cinfo_initialized) jpeg_abort_decompress(&data->cinfo); errno = result; return -1; } init_libjpeg_cinfo(data); jpeg_mem_src(&data->cinfo, src, src_size); jpeg_read_header(&data->cinfo, TRUE); if (data->cinfo.image_width != width || data->cinfo.image_height != height) { V4LCONVERT_ERR("unexpected width / height in JPEG header" "expected: %ux%u, header: %ux%u\n", width, height, data->cinfo.image_width, data->cinfo.image_height); errno = EIO; return -1; } if (data->cinfo.num_components != 3) { V4LCONVERT_ERR("unexpected no components in JPEG: %d\n", data->cinfo.num_components); errno = EIO; return -1; } if (dest_pix_fmt == V4L2_PIX_FMT_RGB24 || dest_pix_fmt == V4L2_PIX_FMT_BGR24) { JSAMPROW row_pointer[1]; #ifdef JCS_EXTENSIONS if (dest_pix_fmt == V4L2_PIX_FMT_BGR24) data->cinfo.out_color_space = JCS_EXT_BGR; #endif row_pointer[0] = dest; jpeg_start_decompress(&data->cinfo); /* Make libjpeg errors report that we've got some data */ data->jerr_errno = EPIPE; while (data->cinfo.output_scanline < height) { jpeg_read_scanlines(&data->cinfo, row_pointer, 1); row_pointer[0] += 3 * width; } jpeg_finish_decompress(&data->cinfo); #ifndef JCS_EXTENSIONS if (dest_pix_fmt == V4L2_PIX_FMT_BGR24) v4lconvert_swap_rgb(dest, dest, width, height); #endif } else { int h_samp, v_samp; unsigned char *udest, *vdest; if (data->cinfo.max_h_samp_factor == 2 && data->cinfo.cur_comp_info[0]->h_samp_factor == 2 && data->cinfo.cur_comp_info[1]->h_samp_factor == 1 && data->cinfo.cur_comp_info[2]->h_samp_factor == 1) { h_samp = 2; #if 0 /* HDG: untested, disable for now */ } else if (data->cinfo.max_h_samp_factor == 1 && data->cinfo.cur_comp_info[0]->h_samp_factor == 1 && data->cinfo.cur_comp_info[1]->h_samp_factor == 1 && data->cinfo.cur_comp_info[2]->h_samp_factor == 1) { h_samp = 1; #endif } else { fprintf(stderr, "libv4lconvert: unsupported jpeg h-sampling " "factors %d:%d:%d, please report this to " "[email protected]\n", data->cinfo.cur_comp_info[0]->h_samp_factor, data->cinfo.cur_comp_info[1]->h_samp_factor, data->cinfo.cur_comp_info[2]->h_samp_factor); errno = EOPNOTSUPP; return -1; } if (data->cinfo.max_v_samp_factor == 2 && data->cinfo.cur_comp_info[0]->v_samp_factor == 2 && data->cinfo.cur_comp_info[1]->v_samp_factor == 1 && data->cinfo.cur_comp_info[2]->v_samp_factor == 1) { v_samp = 2; } else if (data->cinfo.max_v_samp_factor == 1 && data->cinfo.cur_comp_info[0]->v_samp_factor == 1 && data->cinfo.cur_comp_info[1]->v_samp_factor == 1 && data->cinfo.cur_comp_info[2]->v_samp_factor == 1) { v_samp = 1; } else { fprintf(stderr, "libv4lconvert: unsupported jpeg v-sampling " "factors %d:%d:%d, please report this to " "[email protected]\n", data->cinfo.cur_comp_info[0]->v_samp_factor, data->cinfo.cur_comp_info[1]->v_samp_factor, data->cinfo.cur_comp_info[2]->v_samp_factor); errno = EOPNOTSUPP; return -1; } /* We don't want any padding as that may overflow our dest */ if (width % (8 * h_samp) || height % (8 * v_samp)) { V4LCONVERT_ERR( "resolution is not a multiple of dctsize"); errno = EIO; return -1; } if (dest_pix_fmt == V4L2_PIX_FMT_YVU420) { vdest = dest + width * height; udest = vdest + (width * height) / 4; } else { udest = dest + width * height; vdest = udest + (width * height) / 4; } data->cinfo.raw_data_out = TRUE; data->cinfo.do_fancy_upsampling = FALSE; jpeg_start_decompress(&data->cinfo); /* Make libjpeg errors report that we've got some data */ data->jerr_errno = EPIPE; if (h_samp == 1) { result = decode_libjpeg_h_samp1(data, dest, udest, vdest, v_samp); } else { result = decode_libjpeg_h_samp2(data, dest, udest, vdest, v_samp); } if (result) jpeg_abort_decompress(&data->cinfo); else jpeg_finish_decompress(&data->cinfo); } return result; }
void 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. */ struct jpeg_error_mgr jerr; /* More stuff */ JSAMPARRAY buffer; /* Output row buffer */ unsigned int row_stride; /* physical row width in output buffer */ unsigned int pixelcount, memcount; unsigned int sindex, dindex; byte *out; 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. */ int len = ri->FS_ReadFile ( ( char * ) filename, &fbuffer.v); if (!fbuffer.b || len < 0) { return; } /* Step 1: allocate and initialize JPEG decompression object */ /* We have to set up the error handler first, in case the initialization * step fails. (Unlikely, but it could happen if you are out of memory.) * This routine fills in the contents of struct jerr, and returns jerr's * address which we place into the link field in cinfo. */ cinfo.err = jpeg_std_error(&jerr); cinfo.err->error_exit = R_JPGErrorExit; cinfo.err->output_message = R_JPGOutputMessage; /* Now we can initialize the JPEG decompression object. */ jpeg_create_decompress(&cinfo); /* Step 2: specify data source (eg, a file) */ 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); Com_Printf("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); return; } memcount = pixelcount * 4; row_stride = cinfo.output_width * cinfo.output_components; out = (byte *)Z_Malloc(memcount, TAG_TEMP_WORKSPACE, qfalse); *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 */ (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...) */ 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! */ }
qbyte *LoadJPG(vfsfile_t *fin) { qbyte *mem=NULL, *in, *out; int i; /* This struct contains the JPEG decompression parameters and pointers to * working space (which is allocated as needed by the JPEG library). */ struct jpeg_decompress_struct cinfo; /* We use our private extension JPEG error handler. * Note that this struct must live as long as the main JPEG parameter * struct, to avoid dangling-pointer problems. */ struct my_error_mgr jerr; /* More stuff */ JSAMPARRAY buffer; /* Output row buffer */ int size_stride; /* physical row width in output buffer */ qbyte *infile; int length; length = VFS_GETLEN(fin); infile = malloc(length); VFS_READ(fin, infile, length); VFS_CLOSE(fin); /* Step 1: allocate and initialize JPEG decompression object */ /* We set up the normal JPEG error routines, then override error_exit. */ cinfo.err = jpeg_std_error(&jerr.pub); jerr.pub.error_exit = my_error_exit; /* Establish the setjmp return context for my_error_exit to use. */ if (setjmp(jerr.setjmp_buffer)) { // If we get here, the JPEG code has signaled an error. jpeg_destroy_decompress(&cinfo); if (mem) free(mem); return 0; } jpeg_create_decompress(&cinfo); jpeg_mem_src(&cinfo, infile, length); (void) jpeg_read_header(&cinfo, TRUE); (void) jpeg_start_decompress(&cinfo); if (cinfo.output_components!=3) Sys_Error("Bad number of componants in jpeg"); size_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, size_stride, 1); out=mem=malloc(cinfo.output_height*cinfo.output_width*4); memset(out, 0, cinfo.output_height*cinfo.output_width*4); while (cinfo.output_scanline < cinfo.output_height) { (void) jpeg_read_scanlines(&cinfo, buffer, 1); in = buffer[0]; for (i = 0; i < cinfo.output_width; i++) {//rgb to rgba *out++ = *in++; *out++ = *in++; *out++ = *in++; *out++ = 255; } } (void) jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); image_width = cinfo.output_width; image_height = cinfo.output_height; return mem; }
bool CCImage::_initWithJpgData(void * data, int nSize) { /* 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] = {0}; unsigned long location = 0; unsigned int i = 0; bool bRet = false; do { /* 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 ); jpeg_mem_src( &cinfo, (unsigned char *) data, nSize ); /* reading the image header which contains image information */ jpeg_read_header( &cinfo, true ); // we only support RGB or grayscale if (cinfo.jpeg_color_space != JCS_RGB) { if (cinfo.jpeg_color_space == JCS_GRAYSCALE || cinfo.jpeg_color_space == JCS_YCbCr) { cinfo.out_color_space = JCS_RGB; } } else { break; } /* Start decompression jpeg here */ jpeg_start_decompress( &cinfo ); /* init image info */ m_nWidth = (short)(cinfo.image_width); m_nHeight = (short)(cinfo.image_height); m_bHasAlpha = false; m_bPreMulti = false; m_nBitsPerComponent = 8; row_pointer[0] = new unsigned char[cinfo.output_width*cinfo.output_components]; CC_BREAK_IF(! row_pointer[0]); m_pData = new unsigned char[cinfo.output_width*cinfo.output_height*cinfo.output_components]; CC_BREAK_IF(! m_pData); /* now actually read the jpeg into the raw buffer */ /* 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++) m_pData[location++] = row_pointer[0][i]; } jpeg_finish_decompress( &cinfo ); jpeg_destroy_decompress( &cinfo ); /* wrap up decompression, destroy objects, free pointers and close open files */ bRet = true; } while (0); CC_SAFE_DELETE_ARRAY(row_pointer[0]); return bRet; }
RawFrame *Mjpeg422Decoder::decode(void *data, size_t size, int scale_down) { JSAMPARRAY planes[3]; JDIMENSION scanlines_produced = 0; jpeg_mem_src(&cinfo, data, size); jpeg_save_markers(&cinfo, JPEG_COM, 64); jpeg_read_header(&cinfo, TRUE /* require_image */); /* search for a JPEG comment */ jpeg_saved_marker_ptr marker = cinfo.marker_list; while (marker != NULL) { if (marker->marker == JPEG_COM) { comment.assign((char *)marker->data, marker->data_length); break; } marker = marker->next; } cinfo.dct_method = JDCT_FASTEST; cinfo.raw_data_out = TRUE; /* less than 20, assume it's a ratio... otherwise, assume a max. width */ if (scale_down < 20) { cinfo.scale_num = 1; cinfo.scale_denom = scale_down; } else { /* crudely fit decompressed results into specified width */ cinfo.scale_num = 1; cinfo.scale_denom = 1; while ((int)(cinfo.image_width / cinfo.scale_denom) > scale_down) { cinfo.scale_denom++; } } if (cinfo.num_components != 3) { throw std::runtime_error("Mjpeg422Decoder: wrong number of components"); } if (cinfo.comp_info[0].v_samp_factor != 1 || cinfo.comp_info[0].h_samp_factor != 2) { throw std::runtime_error("JPEG not in 4:2:2 format"); } if (cinfo.comp_info[1].v_samp_factor != 1 || cinfo.comp_info[1].h_samp_factor != 1) { throw std::runtime_error("JPEG not in 4:2:2 format"); } if (cinfo.comp_info[2].v_samp_factor != 1 || cinfo.comp_info[2].h_samp_factor != 1) { throw std::runtime_error("JPEG not in 4:2:2 format"); } jpeg_start_decompress(&cinfo); if (cinfo.output_width > maxw || cinfo.output_height > maxh) { throw std::runtime_error("Mjpeg422Decoder: image too large"); } for (unsigned int i = 0; i < cinfo.output_height; i++) { y_scans[i] = y_plane + i * cinfo.output_width; cb_scans[i] = cb_plane + i * (cinfo.output_width / 2); cr_scans[i] = cr_plane + i * (cinfo.output_width / 2); } while (cinfo.output_scanline < cinfo.output_height) { planes[0] = y_scans + scanlines_produced; planes[1] = cb_scans + scanlines_produced; planes[2] = cr_scans + scanlines_produced; scanlines_produced += jpeg_read_raw_data(&cinfo, planes, cinfo.output_height - scanlines_produced); } jpeg_finish_decompress(&cinfo); RawFrame *result = new RawFrame(cinfo.output_width, cinfo.output_height, RawFrame::CbYCrY8422); result->pack->YCbCr8P422(y_plane, cb_plane, cr_plane); return result; }
/* * This function must be fed with a complete compressed frame. */ static picture_t *DecodeBlock(decoder_t *p_dec, block_t **pp_block) { decoder_sys_t *p_sys = p_dec->p_sys; block_t *p_block; picture_t *p_pic = 0; JSAMPARRAY p_row_pointers = NULL; if (!pp_block || !*pp_block) { return NULL; } p_block = *pp_block; if (p_block->i_flags & BLOCK_FLAG_DISCONTINUITY) { block_Release(p_block); *pp_block = NULL; return NULL; } /* libjpeg longjmp's there in case of error */ if (setjmp(p_sys->setjmp_buffer)) { goto error; } jpeg_create_decompress(&p_sys->p_jpeg); jpeg_mem_src(&p_sys->p_jpeg, p_block->p_buffer, p_block->i_buffer); jpeg_read_header(&p_sys->p_jpeg, TRUE); p_sys->p_jpeg.out_color_space = JCS_RGB; jpeg_start_decompress(&p_sys->p_jpeg); /* Set output properties */ p_dec->fmt_out.i_codec = VLC_CODEC_RGB24; p_dec->fmt_out.video.i_width = p_sys->p_jpeg.output_width; p_dec->fmt_out.video.i_height = p_sys->p_jpeg.output_height; p_dec->fmt_out.video.i_sar_num = 1; p_dec->fmt_out.video.i_sar_den = 1; p_dec->fmt_out.video.i_rmask = 0x000000ff; p_dec->fmt_out.video.i_gmask = 0x0000ff00; p_dec->fmt_out.video.i_bmask = 0x00ff0000; /* Get a new picture */ p_pic = decoder_NewPicture(p_dec); if (!p_pic) { goto error; } /* Decode picture */ p_row_pointers = malloc(sizeof(JSAMPROW) * p_sys->p_jpeg.output_height); if (!p_row_pointers) { goto error; } for (unsigned i = 0; i < p_sys->p_jpeg.output_height; i++) { p_row_pointers[i] = p_pic->p->p_pixels + p_pic->p->i_pitch * i; } while (p_sys->p_jpeg.output_scanline < p_sys->p_jpeg.output_height) { jpeg_read_scanlines(&p_sys->p_jpeg, p_row_pointers + p_sys->p_jpeg.output_scanline, p_sys->p_jpeg.output_height - p_sys->p_jpeg.output_scanline); } jpeg_finish_decompress(&p_sys->p_jpeg); jpeg_destroy_decompress(&p_sys->p_jpeg); free(p_row_pointers); p_pic->date = p_block->i_pts > VLC_TS_INVALID ? p_block->i_pts : p_block->i_dts; block_Release(p_block); *pp_block = NULL; return p_pic; error: jpeg_destroy_decompress(&p_sys->p_jpeg); free(p_row_pointers); block_Release(p_block); *pp_block = NULL; return NULL; }
/////////////////////////////////////////////////////////////// // // JpegDecode // // jpeg to XRGB // /////////////////////////////////////////////////////////////// bool JpegDecode ( const void* pData, uint uiDataSize, CBuffer& outBuffer, uint& uiOutWidth, uint& uiOutHeight ) { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; /* Initialize the JPEG decompression object with default error handling. */ cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); /* Specify data source for decompression */ jpeg_mem_src (&cinfo,(uchar*)pData,uiDataSize ); /* Read file header, set default decompression parameters */ (void) jpeg_read_header(&cinfo, TRUE); /* default decompression parameters */ // TODO /* Start decompressor */ (void) jpeg_start_decompress(&cinfo); /* Write output file header */ JDIMENSION uiWidth = cinfo.output_width; /* scaled image width */ JDIMENSION uiHeight = cinfo.output_height; /* scaled image height */ uiOutWidth = uiWidth; uiOutHeight = uiHeight; outBuffer.SetSize ( uiWidth * uiHeight * 4 ); char* pOutData = outBuffer.GetData (); /* Process data */ JSAMPROW row_pointer[1]; CBuffer rowBuffer; rowBuffer.SetSize ( uiWidth * 3 ); char* pRowTemp = rowBuffer.GetData (); while (cinfo.output_scanline < cinfo.output_height) { BYTE* pRowDest = (BYTE*)pOutData + cinfo.output_scanline * uiWidth * 4; row_pointer[0] = (JSAMPROW)pRowTemp; JDIMENSION num_scanlines = jpeg_read_scanlines(&cinfo, row_pointer, 1); for ( uint i = 0 ; i < uiWidth ; i++ ) { pRowDest[i*4+0] = pRowTemp[i*3+2]; pRowDest[i*4+1] = pRowTemp[i*3+1]; pRowDest[i*4+2] = pRowTemp[i*3+0]; pRowDest[i*4+3] = 255; } } // Finish decompression and release memory. (void) jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); if ( jerr.num_warnings ) return false; return true; }
jpeg_comp_dct_t *libjpeg_get_dct_data(const char *filepath) { int ic, ret; xyi_t ib; uint8_t *filedata; size_t filedata_size; struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; jvirt_barray_ptr *coefs; jpeg_comp_dct_t *out=NULL; JBLOCKARRAY dct; jpeg_component_info *compinf; filedata = load_raw_file(filepath, &filedata_size); if (filedata==NULL) return NULL; // allocate and initialize JPEG decompression object cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); jpeg_mem_src(&cinfo, filedata, filedata_size); //jpeg_stdio_src(&cinfo, file); // specify file ret = jpeg_read_header(&cinfo, TRUE); // read file header if (ret != 1) fprintf_rl(stderr, "File '%s' cannot be read by jpeg_read_header()\n", filepath); else { coefs = jpeg_read_coefficients(&cinfo); // read all the coefs (DCT, quantisation table etc) if (coefs) { out = calloc(3, sizeof(jpeg_comp_dct_t)); // copy every DCT block and the quantisation table for every component for (ic=0; ic<3; ic++) { compinf = &cinfo.comp_info[ic]; out[ic].image_dim = xyi(cinfo.image_width, cinfo.image_height); out[ic].block_dim = xyi(compinf->width_in_blocks, compinf->height_in_blocks); dct = (cinfo.mem->access_virt_barray) ((j_common_ptr) (&cinfo), coefs[ic], 0, compinf->v_samp_factor, FALSE); memcpy(out[ic].quant, compinf->quant_table->quantval, DCTSIZE2 * sizeof(uint16_t)); // copy quantisation table // copy DCT blocks out[ic].dct_block = calloc(mul_x_by_y_xyi(out[ic].block_dim), sizeof(int16_t *)); for (ib.y=0; ib.y < out[ic].block_dim.y; ib.y++) for (ib.x=0; ib.x < out[ic].block_dim.x; ib.x++) { out[ic].dct_block[ib.y * out[ic].block_dim.x + ib.x] = calloc(DCTSIZE2, sizeof(int16_t)); memcpy(out[ic].dct_block[ib.y * out[ic].block_dim.x + ib.x], dct[ib.y][ib.x], DCTSIZE2 * sizeof(int16_t)); } } } } // free the libjpeg stuff jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); free(filedata); return out; }
int main (int argc, char **argv) { struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; #ifdef PROGRESS_REPORT struct cdjpeg_progress_mgr progress; #endif int file_index; djpeg_dest_ptr dest_mgr = NULL; FILE * input_file; FILE * output_file; unsigned char *inbuffer = NULL; unsigned long insize = 0; JDIMENSION num_scanlines; /* On Mac, fetch a command line. */ #ifdef USE_CCOMMAND argc = ccommand(&argv); #endif progname = argv[0]; if (progname == NULL || progname[0] == 0) progname = "djpeg"; /* in case C library doesn't provide it */ /* Initialize the JPEG decompression object with default error handling. */ cinfo.err = jpeg_std_error(&jerr); jpeg_create_decompress(&cinfo); /* Add some application-specific error messages (from cderror.h) */ jerr.addon_message_table = cdjpeg_message_table; jerr.first_addon_message = JMSG_FIRSTADDONCODE; jerr.last_addon_message = JMSG_LASTADDONCODE; /* Insert custom marker processor for COM and APP12. * APP12 is used by some digital camera makers for textual info, * so we provide the ability to display it as text. * If you like, additional APPn marker types can be selected for display, * but don't try to override APP0 or APP14 this way (see libjpeg.txt). */ jpeg_set_marker_processor(&cinfo, JPEG_COM, print_text_marker); jpeg_set_marker_processor(&cinfo, JPEG_APP0+12, print_text_marker); /* Scan command line to find file names. */ /* It is convenient to use just one switch-parsing routine, but the switch * values read here are ignored; we will rescan the switches after opening * the input file. * (Exception: tracing level set here controls verbosity for COM markers * found during jpeg_read_header...) */ file_index = parse_switches(&cinfo, argc, argv, 0, FALSE); #ifdef TWO_FILE_COMMANDLINE /* Must have either -outfile switch or explicit output file name */ if (outfilename == NULL) { if (file_index != argc-2) { fprintf(stderr, "%s: must name one input and one output file\n", progname); usage(); } outfilename = argv[file_index+1]; } else { if (file_index != argc-1) { fprintf(stderr, "%s: must name one input and one output file\n", progname); usage(); } } #else /* Unix style: expect zero or one file name */ if (file_index < argc-1) { fprintf(stderr, "%s: only one input file\n", progname); usage(); } #endif /* TWO_FILE_COMMANDLINE */ /* Open the input file. */ if (file_index < argc) { if ((input_file = fopen(argv[file_index], READ_BINARY)) == NULL) { fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]); exit(EXIT_FAILURE); } } else { /* default input file is stdin */ input_file = read_stdin(); } /* Open the output file. */ if (outfilename != NULL) { if ((output_file = fopen(outfilename, WRITE_BINARY)) == NULL) { fprintf(stderr, "%s: can't open %s\n", progname, outfilename); exit(EXIT_FAILURE); } } else { /* default output file is stdout */ output_file = write_stdout(); } #ifdef PROGRESS_REPORT start_progress_monitor((j_common_ptr) &cinfo, &progress); #endif /* Specify data source for decompression */ #if JPEG_LIB_VERSION >= 80 || defined(MEM_SRCDST_SUPPORTED) if (memsrc) { size_t nbytes; do { inbuffer = (unsigned char *)realloc(inbuffer, insize + INPUT_BUF_SIZE); if (inbuffer == NULL) { fprintf(stderr, "%s: memory allocation failure\n", progname); exit(EXIT_FAILURE); } nbytes = JFREAD(input_file, &inbuffer[insize], INPUT_BUF_SIZE); if (nbytes < INPUT_BUF_SIZE && ferror(input_file)) { if (file_index < argc) fprintf(stderr, "%s: can't read from %s\n", progname, argv[file_index]); else fprintf(stderr, "%s: can't read from stdin\n", progname); } insize += (unsigned long)nbytes; } while (nbytes == INPUT_BUF_SIZE); fprintf(stderr, "Compressed size: %lu bytes\n", insize); jpeg_mem_src(&cinfo, inbuffer, insize); } else #endif jpeg_stdio_src(&cinfo, input_file); /* Read file header, set default decompression parameters */ (void) jpeg_read_header(&cinfo, TRUE); /* Adjust default decompression parameters by re-parsing the options */ file_index = parse_switches(&cinfo, argc, argv, 0, TRUE); /* Initialize the output module now to let it override any crucial * option settings (for instance, GIF wants to force color quantization). */ switch (requested_fmt) { #ifdef BMP_SUPPORTED case FMT_BMP: dest_mgr = jinit_write_bmp(&cinfo, FALSE); break; case FMT_OS2: dest_mgr = jinit_write_bmp(&cinfo, TRUE); break; #endif #ifdef GIF_SUPPORTED case FMT_GIF: dest_mgr = jinit_write_gif(&cinfo); break; #endif #ifdef PPM_SUPPORTED case FMT_PPM: dest_mgr = jinit_write_ppm(&cinfo); break; #endif #ifdef RLE_SUPPORTED case FMT_RLE: dest_mgr = jinit_write_rle(&cinfo); break; #endif #ifdef TARGA_SUPPORTED case FMT_TARGA: dest_mgr = jinit_write_targa(&cinfo); break; #endif default: ERREXIT(&cinfo, JERR_UNSUPPORTED_FORMAT); break; } dest_mgr->output_file = output_file; /* Start decompressor */ (void) jpeg_start_decompress(&cinfo); /* Strip decode */ if (strip || skip) { JDIMENSION tmp; /* Check for valid endY. We cannot check this value until after * jpeg_start_decompress() is called. Note that we have already verified * that startY <= endY. */ if (endY > cinfo.output_height - 1) { fprintf(stderr, "%s: strip %d-%d exceeds image height %d\n", progname, startY, endY, cinfo.output_height); exit(EXIT_FAILURE); } /* Write output file header. This is a hack to ensure that the destination * manager creates an image of the proper size for the partial decode. */ tmp = cinfo.output_height; cinfo.output_height = endY - startY + 1; if (skip) cinfo.output_height = tmp - cinfo.output_height; (*dest_mgr->start_output) (&cinfo, dest_mgr); cinfo.output_height = tmp; /* Process data */ if (skip) { while (cinfo.output_scanline < startY) { num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer, dest_mgr->buffer_height); (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); } jpeg_skip_scanlines(&cinfo, endY - startY + 1); while (cinfo.output_scanline < cinfo.output_height) { num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer, dest_mgr->buffer_height); (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); } } else { jpeg_skip_scanlines(&cinfo, startY); while (cinfo.output_scanline <= endY) { num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer, dest_mgr->buffer_height); (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); } jpeg_skip_scanlines(&cinfo, cinfo.output_height - endY + 1); } /* Normal full image decode */ } else { /* Write output file header */ (*dest_mgr->start_output) (&cinfo, dest_mgr); /* Process data */ while (cinfo.output_scanline < cinfo.output_height) { num_scanlines = jpeg_read_scanlines(&cinfo, dest_mgr->buffer, dest_mgr->buffer_height); (*dest_mgr->put_pixel_rows) (&cinfo, dest_mgr, num_scanlines); } } #ifdef PROGRESS_REPORT /* Hack: count final pass as done in case finish_output does an extra pass. * The library won't have updated completed_passes. */ progress.pub.completed_passes = progress.pub.total_passes; #endif /* Finish decompression and release memory. * I must do it in this order because output module has allocated memory * of lifespan JPOOL_IMAGE; it needs to finish before releasing memory. */ (*dest_mgr->finish_output) (&cinfo, dest_mgr); (void) jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); /* Close files, if we opened them */ if (input_file != stdin) fclose(input_file); if (output_file != stdout) fclose(output_file); #ifdef PROGRESS_REPORT end_progress_monitor((j_common_ptr) &cinfo); #endif if (memsrc && inbuffer != NULL) free(inbuffer); /* All done. */ exit(jerr.num_warnings ? EXIT_WARNING : EXIT_SUCCESS); return 0; /* suppress no-return-value warnings */ }
int JPEG2NV21(Uint8 *yuv, Uint8 *jpegdata, int jpeglen, int sx, int sy, bool needRotation, bool cameraMirrored, int rotationDegree) { int i, y; int inlen; struct jpeg_decompress_struct cinfo; struct my_error_mgr jerr; JSAMPARRAY scanline; unsigned char *wline; unsigned char *y_buffer; unsigned char *cbcr_buffer; Uint8* dst; if (needRotation || cameraMirrored) //if(rotationDegree != 0 || cameraMirrored) dst = (unsigned char*)malloc(sx*sy+2*((sx+1)/2)*((sy+1)/2)); else dst = yuv; 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)) { jpeg_destroy_decompress(&cinfo); return 0; } jpeg_create_decompress(&cinfo); jpeg_mem_src(&cinfo, jpegdata, jpeglen); (void) jpeg_read_header(&cinfo, TRUE); //cinfo.raw_data_out = TRUE; cinfo.out_color_space = JCS_YCbCr; (void) jpeg_start_decompress(&cinfo); y_buffer = dst; cbcr_buffer = y_buffer + cinfo.output_width * cinfo.output_height; scanline = (*cinfo.mem->alloc_sarray)((j_common_ptr) &cinfo, JPOOL_IMAGE, cinfo.output_width * cinfo.output_components, 1); wline = scanline[0]; while (cinfo.output_scanline < cinfo.output_height) { jpeg_read_scanlines(&cinfo, scanline, (JDIMENSION)1); for (i = 0; i < cinfo.output_width; i++) y_buffer[i] = wline[i*3]; y_buffer += cinfo.output_width; if (y++ & 1) { for (int i = 0; i < cinfo.output_width; i+=2) { cbcr_buffer[i] = wline[(i*3) + 2]; // V cbcr_buffer[i + 1] = wline[(i*3) + 1]; // U } cbcr_buffer += cinfo.output_width; } } (void) jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); if (needRotation || cameraMirrored) { int nRotate = 0; int flipUD = 0; if(rotationDegree == 180 || rotationDegree == 270) { cameraMirrored = !cameraMirrored; //used to support 4-side rotation flipUD = 1; //used to support 4-side rotation } if(rotationDegree == 90 || rotationDegree == 270) nRotate = 1; //used to support 4-side rotation // ToDo: not sure if it should be 'cameraMirrored, 0,' or '0, cameraMirrored,' TransformNV21(dst, yuv, sx, sy, NULL, cameraMirrored, flipUD, nRotate); free(dst); } return 1; }
uvc_error_t uvc_mjpeg2yuyv(uvc_frame_t *in, uvc_frame_t *out) { out->actual_bytes = 0; // XXX if (UNLIKELY(in->frame_format != UVC_FRAME_FORMAT_MJPEG)) return UVC_ERROR_INVALID_PARAM; if (uvc_ensure_frame_size(out, in->width * in->height * 2) < 0) return UVC_ERROR_NO_MEM; size_t lines_read = 0; int i, j; int num_scanlines; register uint8_t *yuyv, *ycbcr; out->width = in->width; out->height = in->height; out->frame_format = UVC_FRAME_FORMAT_YUYV; out->step = in->width * 2; out->sequence = in->sequence; out->capture_time = in->capture_time; out->source = in->source; struct jpeg_decompress_struct dinfo; struct error_mgr jerr; dinfo.err = jpeg_std_error(&jerr.super); jerr.super.error_exit = _error_exit; if (setjmp(jerr.jmp)) { goto fail; } jpeg_create_decompress(&dinfo); jpeg_mem_src(&dinfo, in->data, in->actual_bytes/*in->data_bytes*/); // XXX jpeg_read_header(&dinfo, TRUE); if (dinfo.dc_huff_tbl_ptrs[0] == NULL) { /* This frame is missing the Huffman tables: fill in the standard ones */ insert_huff_tables(&dinfo); } dinfo.out_color_space = JCS_YCbCr; dinfo.dct_method = JDCT_IFAST; // start decompressor jpeg_start_decompress(&dinfo); // these dinfo.xxx valiables are only valid after jpeg_start_decompress const int row_stride = dinfo.output_width * dinfo.output_components; // allocate buffer register JSAMPARRAY buffer = (*dinfo.mem->alloc_sarray) ((j_common_ptr) &dinfo, JPOOL_IMAGE, row_stride, MAX_READLINE); // local copy uint8_t *data = out->data; const int out_step = out->step; if (LIKELY(dinfo.output_height == out->height)) { for (; dinfo.output_scanline < dinfo.output_height ;) { // convert lines of mjpeg data to YCbCr num_scanlines = jpeg_read_scanlines(&dinfo, buffer, MAX_READLINE); // convert YCbCr to yuyv(YUV422) for (j = 0; j < num_scanlines; j++) { yuyv = data + (lines_read + j) * out_step; ycbcr = buffer[j]; for (i = 0; i < row_stride; i += 24) { // step by YCbCr x 8 pixels = 3 x 8 bytes YCbCr_YUYV_2(ycbcr + i, yuyv); YCbCr_YUYV_2(ycbcr + i + 6, yuyv); YCbCr_YUYV_2(ycbcr + i + 12, yuyv); YCbCr_YUYV_2(ycbcr + i + 18, yuyv); } } lines_read += num_scanlines; } out->actual_bytes = in->width * in->height * 2; // XXX } jpeg_finish_decompress(&dinfo); jpeg_destroy_decompress(&dinfo); return lines_read == out->height ? UVC_SUCCESS : UVC_ERROR_OTHER; fail: jpeg_destroy_decompress(&dinfo); return lines_read == out->height ? UVC_SUCCESS : UVC_ERROR_OTHER+1; }
/** @brief Convert an MJPEG frame to RGB * @ingroup frame * * @param in MJPEG frame * @param out RGB frame */ uvc_error_t uvc_mjpeg2rgb(uvc_frame_t *in, uvc_frame_t *out) { struct jpeg_decompress_struct dinfo; struct error_mgr jerr; size_t lines_read; // local copy uint8_t *data = out->data; const int out_step = out->step; int num_scanlines, i; lines_read = 0; unsigned char *buffer[MAX_READLINE]; out->actual_bytes = 0; // XXX if (UNLIKELY(in->frame_format != UVC_FRAME_FORMAT_MJPEG)) return UVC_ERROR_INVALID_PARAM; if (uvc_ensure_frame_size(out, in->width * in->height * 3) < 0) return UVC_ERROR_NO_MEM; out->width = in->width; out->height = in->height; out->frame_format = UVC_FRAME_FORMAT_RGB; out->step = in->width * 3; out->sequence = in->sequence; out->capture_time = in->capture_time; out->source = in->source; dinfo.err = jpeg_std_error(&jerr.super); jerr.super.error_exit = _error_exit; if (setjmp(jerr.jmp)) { goto fail; } jpeg_create_decompress(&dinfo); jpeg_mem_src(&dinfo, in->data, in->actual_bytes/*in->data_bytes*/); jpeg_read_header(&dinfo, TRUE); if (dinfo.dc_huff_tbl_ptrs[0] == NULL) { /* This frame is missing the Huffman tables: fill in the standard ones */ insert_huff_tables(&dinfo); } dinfo.out_color_space = JCS_RGB; dinfo.dct_method = JDCT_IFAST; jpeg_start_decompress(&dinfo); if (LIKELY(dinfo.output_height == out->height)) { for (; dinfo.output_scanline < dinfo.output_height ;) { buffer[0] = data + (lines_read) * out_step; for (i = 1; i < MAX_READLINE; i++) buffer[i] = buffer[i-1] + out_step; num_scanlines = jpeg_read_scanlines(&dinfo, buffer, MAX_READLINE); lines_read += num_scanlines; } out->actual_bytes = in->width * in->height * 3; // XXX } jpeg_finish_decompress(&dinfo); jpeg_destroy_decompress(&dinfo); return lines_read == out->height ? UVC_SUCCESS : UVC_ERROR_OTHER; // XXX fail: jpeg_destroy_decompress(&dinfo); return UVC_ERROR_OTHER+1; }
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; }
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; }