static int bitmap_decode(struct jpeg_decompress_struct *cinfo, Vbitmap *vbitmap, YmagineFormatOptions *options) { int nlines = -1; cinfo->client_data = (void*) vbitmap; if (prepareDecompressor(cinfo, options) != YMAGINE_OK) { return nlines; } /* Intercept APP1 markers for PhotoSphere parsing */ jpeg_set_marker_processor(cinfo, JPEG_APP0 + 1, APP1_handler); if (startDecompressor(cinfo, VbitmapColormode(vbitmap)) != YMAGINE_OK) { return nlines; } YmagineFormatOptions_invokeCallback(options, YMAGINE_IMAGEFORMAT_JPEG, cinfo->image_width, cinfo->image_height); #if YMAGINE_DEBUG_JPEG ALOGD("bitmap_decode: in=%dx%d bm=%dx%d max=%dx%d", cinfo->image_width, cinfo->image_height, VbitmapWidth(vbitmap), VbitmapHeight(vbitmap), options->maxwidth, options->maxheight); #endif nlines = decompress_jpeg(cinfo, NULL, JCOPYOPT_NONE, vbitmap, options); return nlines; }
int VbitmapBpp(Vbitmap *vbitmap) { if (vbitmap == NULL) { return 0; } return colorBpp(VbitmapColormode(vbitmap)); }
int TransformerSetBitmap(Transformer *transformer, Vbitmap *vbitmap, int offsetx, int offsety) { int rc = YMAGINE_OK; if (transformer == NULL) { return YMAGINE_ERROR; } if (transformer->obitmap != NULL) { VbitmapUnlock(transformer->obitmap); } if (vbitmap != NULL) { rc = VbitmapLock(vbitmap); if (rc != YMAGINE_OK) { vbitmap = NULL; } } transformer->obitmap = vbitmap; if (vbitmap == NULL) { transformer->obitmap = NULL; transformer->obuffer = NULL; transformer->owidth = 0; transformer->oheight = 0; transformer->opitch = 0; transformer->omode = VBITMAP_COLOR_RGBA; transformer->obpp = 0; transformer->offsetx = 0; transformer->offsety = 0; } else { transformer->obitmap = vbitmap; transformer->obuffer = VbitmapBuffer(vbitmap); transformer->owidth = VbitmapWidth(vbitmap); transformer->oheight = VbitmapHeight(vbitmap); transformer->opitch = VbitmapPitch(vbitmap); transformer->omode = VbitmapColormode(vbitmap); transformer->obpp = colorBpp(transformer->omode); transformer->offsetx = offsetx; transformer->offsety = offsety; } return rc; }
int encodeWEBP(Vbitmap *vbitmap, Ychannel *channelout, YmagineFormatOptions *options) { int rc = YMAGINE_ERROR; #if HAVE_WEBP WebPConfig config; WebPPicture picture; WebPPreset preset = WEBP_PRESET_PHOTO; // One of DEFAULT, PICTURE, PHOTO, DRAWING, ICON or TEXT int width; int height; int pitch; int quality; const unsigned char *pixels; int colormode; /* * List of encoding options for WebP config * int lossless; // Lossless encoding (0=lossy(default), 1=lossless). * float quality; // between 0 (smallest file) and 100 (biggest) * int method; // quality/speed trade-off (0=fast, 6=slower-better) * * WebPImageHint image_hint; // Hint for image type (lossless only for now). * * // Parameters related to lossy compression only: * int target_size; // if non-zero, set the desired target size in bytes. * // Takes precedence over the 'compression' parameter. * float target_PSNR; // if non-zero, specifies the minimal distortion to * // try to achieve. Takes precedence over target_size. * int segments; // maximum number of segments to use, in [1..4] * int sns_strength; // Spatial Noise Shaping. 0=off, 100=maximum. * int filter_strength; // range: [0 = off .. 100 = strongest] * int filter_sharpness; // range: [0 = off .. 7 = least sharp] * int filter_type; // filtering type: 0 = simple, 1 = strong (only used * // if filter_strength > 0 or autofilter > 0) * int autofilter; // Auto adjust filter's strength [0 = off, 1 = on] * int alpha_compression; // Algorithm for encoding the alpha plane (0 = none, * // 1 = compressed with WebP lossless). Default is 1. * int alpha_filtering; // Predictive filtering method for alpha plane. * // 0: none, 1: fast, 2: best. Default if 1. * int alpha_quality; // Between 0 (smallest size) and 100 (lossless). * // Default is 100. * int pass; // number of entropy-analysis passes (in [1..10]). * * int show_compressed; // if true, export the compressed picture back. * // In-loop filtering is not applied. * int preprocessing; // preprocessing filter (0=none, 1=segment-smooth) * int partitions; // log2(number of token partitions) in [0..3] * // Default is set to 0 for easier progressive decoding. * int partition_limit; // quality degradation allowed to fit the 512k limit on * // prediction modes coding (0: no degradation, * // 100: maximum possible degradation). */ colormode = VbitmapColormode(vbitmap); if (colormode != VBITMAP_COLOR_RGBA && colormode != VBITMAP_COLOR_RGB) { ALOGD("currently only support RGB, RGBA webp encoding"); return rc; } quality = YmagineFormatOptions_normalizeQuality(options); if (!WebPConfigPreset(&config, preset, (float) quality)) { return YMAGINE_ERROR; // version error } if (options && options->accuracy >= 0) { int method = options->accuracy / 15; if (method > 6) { method = 6; } config.method = method; } if (!WebPValidateConfig(&config)) { // parameter ranges verification failed return YMAGINE_ERROR; } rc = VbitmapLock(vbitmap); if (rc < 0) { ALOGE("AndroidBitmap_lockPixels() failed"); return YMAGINE_ERROR; } width = VbitmapWidth(vbitmap); height = VbitmapHeight(vbitmap); pitch = VbitmapPitch(vbitmap); pixels = VbitmapBuffer(vbitmap); if (WebPPictureInit(&picture)) { picture.use_argb = 1; picture.width = width; picture.height = height; picture.writer = WebPYchannelWrite; picture.custom_ptr = channelout; if (colormode == VBITMAP_COLOR_RGBA) { WebPPictureImportRGBA(&picture, pixels, pitch); } else { WebPPictureImportRGB(&picture, pixels, pitch); } WebPEncode(&config, &picture); WebPPictureFree(&picture); } VbitmapUnlock(vbitmap); rc = YMAGINE_OK; #endif return rc; }
static int WEBPDecode(WEBPDec* pSrc, Vbitmap *vbitmap, YmagineFormatOptions *options) { int contentSize; int origWidth = 0; int origHeight = 0; int quality; unsigned char header[WEBP_HEADER_SIZE + 32]; int headerlen; int toRead; unsigned char *input = NULL; int inputlen; int oformat; int opitch; unsigned char *odata; int rc; Vrect srcrect; Vrect destrect; WebPIDecoder* idec; if (options == NULL) { /* Options argument is mandatory */ return 0; } headerlen = YchannelRead(pSrc->channel, (char *) header, sizeof(header)); if (headerlen < WEBP_HEADER_SIZE) { return 0; } /* Check WEBP header */ contentSize = WebpCheckHeader((const char*) header, headerlen); if (contentSize <= 0) { return 0; } if (WebPGetInfo(header, headerlen, &origWidth, &origHeight) == 0) { ALOGD("invalid VP8 header"); return 0; } if (origWidth <= 0 || origHeight <= 0) { return 0; } if (YmagineFormatOptions_invokeCallback(options, YMAGINE_IMAGEFORMAT_WEBP, origWidth, origHeight) != YMAGINE_OK) { return 0; } if (YmaginePrepareTransform(vbitmap, options, origWidth, origHeight, &srcrect, &destrect) != YMAGINE_OK) { return 0; } #if YMAGINE_DEBUG_WEBP ALOGD("size: %dx%d req: %dx%d %s -> output: %dx%d", origWidth, origHeight, destrect.width, destrect.height, (options->scalemode == YMAGINE_SCALE_CROP) ? "crop" : (options->scalemode == YMAGINE_SCALE_FIT ? "fit" : "letterbox"), destrect.width, destrect.height); #endif if (vbitmap != NULL) { if (options->resizable) { destrect.x = 0; destrect.y = 0; if (VbitmapResize(vbitmap, destrect.width, destrect.height) != YMAGINE_OK) { return 0; } } if (VbitmapType(vbitmap) == VBITMAP_NONE) { /* Decode bounds only, return positive number (number of lines) on success */ return VbitmapHeight(vbitmap); } } pSrc->bitmap = vbitmap; inputlen = contentSize; toRead = inputlen - headerlen; rc = VbitmapLock(vbitmap); if (rc != YMAGINE_OK) { ALOGE("VbitmapLock() failed (code %d)", rc); rc = YMAGINE_ERROR; } else { odata = VbitmapBuffer(vbitmap); opitch = VbitmapPitch(vbitmap); oformat = VbitmapColormode(vbitmap); pSrc->inwidth = origWidth; pSrc->inheight = origHeight; pSrc->outwidth = destrect.width; pSrc->outheight = destrect.height; if (odata == NULL) { ALOGD("failed to get reference to pixel buffer"); rc = YMAGINE_ERROR; } else { WebPDecoderConfig config; int supported = 1; int webpcolorspace; switch(oformat) { case VBITMAP_COLOR_RGBA: webpcolorspace = MODE_RGBA; break; case VBITMAP_COLOR_RGB: webpcolorspace = MODE_RGB; break; case VBITMAP_COLOR_rgbA: webpcolorspace = MODE_rgbA; break; case VBITMAP_COLOR_ARGB: webpcolorspace = MODE_ARGB; break; case VBITMAP_COLOR_Argb: webpcolorspace = MODE_Argb; break; case VBITMAP_COLOR_GRAYSCALE: case VBITMAP_COLOR_YUV: case VBITMAP_COLOR_CMYK: case VBITMAP_COLOR_YCbCr: default: supported = 0; break; } if (!supported) { ALOGD("currently only support RGB, RGBA webp decoding"); rc = YMAGINE_ERROR; } else { pSrc->isdirect = 1; pSrc->outformat = oformat; pSrc->outbpp = VbitmapBpp(vbitmap); pSrc->outstride = opitch; pSrc->outbuffer = odata + destrect.x * pSrc->outbpp + destrect.y * pSrc->outstride; WebPInitDecoderConfig(&config); quality = YmagineFormatOptions_normalizeQuality(options); if (quality < 90) { config.options.no_fancy_upsampling = 1; } if (quality < 60) { config.options.bypass_filtering = 1; } config.options.use_threads = 1; if (srcrect.x != 0 || srcrect.y != 0 || srcrect.width != origWidth || srcrect.height != origHeight) { /* Crop on source */ config.options.use_cropping = 1; config.options.crop_left = srcrect.x; config.options.crop_top = srcrect.y; config.options.crop_width = srcrect.width; config.options.crop_height = srcrect.height; } if (pSrc->outwidth != pSrc->inwidth || pSrc->outheight != pSrc->inheight) { config.options.use_scaling = 1; config.options.scaled_width = pSrc->outwidth; config.options.scaled_height = pSrc->outheight; } rc = YMAGINE_ERROR; // Specify the desired output colorspace: config.output.colorspace = webpcolorspace; // Have config.output point to an external buffer: config.output.u.RGBA.rgba = (uint8_t*) pSrc->outbuffer; config.output.u.RGBA.stride = pSrc->outstride; config.output.u.RGBA.size = pSrc->outstride * pSrc->outheight; config.output.is_external_memory = 1; idec = WebPIDecode(NULL, 0, &config); if (idec != NULL) { VP8StatusCode status; status = WebPIAppend(idec, header, headerlen); if (status == VP8_STATUS_OK || status == VP8_STATUS_SUSPENDED) { int bytes_remaining = toRead; int bytes_read; int bytes_req; unsigned char rbuf[8192]; // See WebPIUpdate(idec, buffer, size_of_transmitted_buffer); bytes_req = sizeof(rbuf); while (bytes_remaining > 0) { if (bytes_req > bytes_remaining) { bytes_req = bytes_remaining; } bytes_read = YchannelRead(pSrc->channel, rbuf, bytes_req); if (bytes_read <= 0) { break; } status = WebPIAppend(idec, (uint8_t*) rbuf, bytes_read); if (status == VP8_STATUS_OK) { rc = YMAGINE_OK; break; } else if (status == VP8_STATUS_SUSPENDED) { if (bytes_remaining > 0) { bytes_remaining -= bytes_read; } } else { /* error */ break; } // The above call decodes the current available buffer. // Part of the image can now be refreshed by calling // WebPIDecGetRGB()/WebPIDecGetYUVA() etc. } } } // the object doesn't own the image memory, so it can now be deleted. WebPIDelete(idec); WebPFreeDecBuffer(&config.output); } } VbitmapUnlock(vbitmap); } if (input) { Ymem_free((char*) input); } if (!pSrc->isdirect) { Ymem_free(pSrc->outbuffer); } if (rc == YMAGINE_OK) { return origHeight; } return 0; }
/* Methods */ int VbitmapResize(Vbitmap *vbitmap, int width, int height) { if (vbitmap == NULL) { return YMAGINE_ERROR; } if (width <= 0 || height <= 0) { return YMAGINE_ERROR; } if (width == vbitmap->width && height == vbitmap->height) { /* Size not changed, ignore */ return YMAGINE_OK; } if (vbitmap->bitmaptype == VBITMAP_NONE) { vbitmap->width = width; vbitmap->height = height; return YMAGINE_OK; } if (vbitmap->bitmaptype == VBITMAP_ANDROID) { AndroidBitmapInfo bitmapinfo; jobject jbitmap; jobject jbitmapref; int ret; JNIEnv *jenv = getEnv(vbitmap); if (jenv == NULL) { return YMAGINE_ERROR; } jbitmap = createAndroidBitmap(jenv, width, height); if (jbitmap == NULL) { return YMAGINE_ERROR; } ret = AndroidBitmap_getInfo(jenv, jbitmap, &bitmapinfo); if (ret < 0 || bitmapinfo.format != ANDROID_BITMAP_FORMAT_RGBA_8888 || bitmapinfo.width != width || bitmapinfo.height != height) { return YMAGINE_ERROR; } jbitmapref = (*jenv)->NewGlobalRef(jenv, jbitmap); if (jbitmapref == NULL) { return YMAGINE_ERROR; } /* Replace Bitmap */ if (vbitmap->jbitmap != NULL) { if (vbitmap->jkeepref) { (*jenv)->DeleteGlobalRef(jenv, vbitmap->jbitmap); vbitmap->jkeepref = 0; } vbitmap->jbitmap = NULL; } #if VBITMAP_ENABLE_GLOBAL_REF vbitmap->jbitmap = jbitmapref; vbitmap->jkeepref = 1; #else vbitmap->jbitmap = jbitmap; vbitmap->jkeepref = 0; (*jenv)->DeleteGlobalRef(jenv, jbitmapref); #endif vbitmap->width = bitmapinfo.width; vbitmap->height = bitmapinfo.height; vbitmap->pitch = bitmapinfo.stride; return YMAGINE_OK; } if (vbitmap->bitmaptype == VBITMAP_MEMORY) { int bpp = colorBpp(VbitmapColormode(vbitmap)); int pitch = width * bpp; unsigned char *pixels = NULL; if (pitch > 0) { pixels = Ymem_malloc(pitch * height); } if (pixels == NULL) { return YMAGINE_ERROR; } if (vbitmap->pixels != NULL) { Ymem_free(vbitmap->pixels); } vbitmap->pixels = pixels; vbitmap->width = width; vbitmap->height = height; vbitmap->pitch = pitch; return YMAGINE_OK; } if (vbitmap->bitmaptype == VBITMAP_STATIC) { /* Can't resize a static bitmap */ return YMAGINE_ERROR; } return YMAGINE_ERROR; }
int Vbitmap_sobel(Vbitmap *outbitmap, Vbitmap *vbitmap) { int width; int height; int pitch; int bpp; unsigned char *pixels; int owidth; int oheight; int opitch; int obpp; unsigned char *opixels; int i, j; unsigned char *inp; unsigned char *outp; if (vbitmap == NULL) { return YMAGINE_ERROR; } if (VbitmapLock(vbitmap) >= 0) { pixels = VbitmapBuffer(vbitmap); width = VbitmapWidth(vbitmap); height = VbitmapHeight(vbitmap); pitch = VbitmapPitch(vbitmap); bpp = colorBpp(VbitmapColormode(vbitmap)); if (VbitmapLock(outbitmap) >= 0) { opixels = VbitmapBuffer(outbitmap); owidth = VbitmapWidth(outbitmap); oheight = VbitmapHeight(outbitmap); opitch = VbitmapPitch(outbitmap); obpp = colorBpp(VbitmapColormode(outbitmap)); if (width != owidth || height != oheight) { VbitmapUnlock(outbitmap); if (VbitmapResize(outbitmap, width, height) == YMAGINE_OK) { if (VbitmapLock(outbitmap) < 0) { VbitmapUnlock(vbitmap); return YMAGINE_ERROR; } opixels = VbitmapBuffer(outbitmap); owidth = VbitmapWidth(outbitmap); oheight = VbitmapHeight(outbitmap); opitch = VbitmapPitch(outbitmap); obpp = colorBpp(VbitmapColormode(outbitmap)); } } if (width == owidth && height == oheight && bpp >= 3) { for (j = 0; j < height; j++) { inp = pixels + pitch * j; outp = opixels + opitch * j; outp[0] = EnergySobel(inp, bpp, pitch, 0, j, width, height); outp += obpp; inp += bpp; if (j != 0 && j != height-1) { for (i = 1; i < width - 1; i++) { outp[0] = EnergySobelFast(inp, bpp, pitch); outp += obpp; inp += bpp; } } else { for (i = 1; i < width - 1; i++) { outp[0] = EnergySobel(inp, bpp, pitch, i, j, width, height); outp += obpp; inp += bpp; } } outp[0] = EnergySobel(inp, bpp, pitch, width - 1, j, width, height); } if (obpp >= 3) { for (j = 0; j < height; j++) { outp = opixels + opitch * j; for (i = 0; i < width; i++) { outp[1] = outp[0]; outp[2] = outp[0]; if (obpp == 4) { outp[0] = 0xff; } outp += obpp; } } } } VbitmapUnlock(outbitmap); } VbitmapUnlock(vbitmap); } return YMAGINE_OK; }
int encodeJPEG(Vbitmap *vbitmap, Ychannel *channelout, YmagineFormatOptions *options) { struct jpeg_compress_struct cinfoout; struct noop_error_mgr jerr; int result = YMAGINE_ERROR; int rc; int nlines = 0; JSAMPROW row_pointer[1]; unsigned char *pixels; int width; int height; int pitch; int colormode; int i; if (!YchannelWritable(channelout)) { return result; } if (vbitmap == NULL) { return result; } rc = VbitmapLock(vbitmap); if (rc != YMAGINE_OK) { ALOGE("AndroidBitmap_lockPixels() failed"); return result; } memset(&cinfoout, 0, sizeof(struct jpeg_compress_struct)); cinfoout.err = noop_jpeg_std_error(&jerr.pub); if (setjmp(jerr.setjmp_buffer)) { /* If we get here, the JPEG code has signaled an error in encoder */ noop_append_jpeg_message((j_common_ptr) &cinfoout); } else { /* Equivalent to: jpeg_CreateCompress(&cinfoout, JPEG_LIB_VERSION, (size_t) sizeof(struct jpeg_compress_struct)); */ jpeg_create_compress(&cinfoout); if (ymaginejpeg_output(&cinfoout, channelout) >= 0) { /* Other compression settings */ int optimize = 0; int progressive = 0; int grayscale = 0; int quality = YmagineFormatOptions_normalizeQuality(options); if (quality >= 90) { optimize = 1; } width = VbitmapWidth(vbitmap); height = VbitmapHeight(vbitmap); pitch = VbitmapPitch(vbitmap); colormode = VbitmapColormode(vbitmap); cinfoout.image_width = width; cinfoout.image_height = height; set_colormode(&cinfoout, colormode); jpeg_set_defaults(&cinfoout); jpeg_set_quality(&cinfoout, quality, FALSE); if (grayscale) { /* Force a monochrome JPEG file to be generated. */ jpeg_set_colorspace(&cinfoout, JCS_GRAYSCALE); } if (optimize) { /* Enable entropy parm optimization. */ cinfoout.optimize_coding = TRUE; } if (progressive) { /* Select simple progressive mode. */ jpeg_simple_progression(&cinfoout); } setCompressorOptions(&cinfoout, options); jpeg_start_compress(&cinfoout, TRUE); pixels = VbitmapBuffer(vbitmap); for (i = 0; i < height; i++) { row_pointer[0] = pixels + i * pitch; jpeg_write_scanlines(&cinfoout, row_pointer, 1); nlines++; } if (nlines > 0) { rc = YMAGINE_OK; } /* Clean up compressor */ jpeg_finish_compress(&cinfoout); } } jpeg_destroy_compress(&cinfoout); VbitmapUnlock(vbitmap); return rc; }
static YOPTIMIZE_SPEED int decompress_jpeg(struct jpeg_decompress_struct *cinfo, struct jpeg_compress_struct *cinfoout, JCOPY_OPTION copyoption, Vbitmap *vbitmap, YmagineFormatOptions *options) { int scanlines; int nlines; int totallines; int j; int scalenum = -1; JSAMPARRAY buffer; Vrect srcrect; Vrect destrect; size_t row_stride; Transformer *transformer; PixelShader *shader = NULL; int iwidth, iheight; float sharpen = 0.0f; if (vbitmap == NULL && cinfoout == NULL) { /* No output specified */ return 0; } if (options == NULL) { /* Options argument is mandatory */ return 0; } iwidth = cinfo->image_width; iheight = cinfo->image_height; if (YmaginePrepareTransform(vbitmap, options, iwidth, iheight, &srcrect, &destrect) != YMAGINE_OK) { return 0; } shader = options->pixelshader; sharpen = options->sharpen; /* Define if image can be pre-subsampled by a ratio n/8 (n=1..7) */ scalenum = GetScaleNum(destrect.width, destrect.height, srcrect.width, srcrect.height, options->scalemode); if (scalenum > 0 && scalenum < 8) { cinfo->scale_num = scalenum; cinfo->scale_denom = 8; } /* Compute actual output dimension for image returned by decoder */ jpeg_calc_output_dimensions(cinfo); #if YMAGINE_DEBUG_JPEG ALOGD("src=%dx%d@%d,%d dst=%dx%d@%d,%d", srcrect.width, srcrect.height, srcrect.x, srcrect.y, destrect.width, destrect.height, destrect.x, destrect.y); ALOGD("size: %dx%d req: %dx%d %s -> scale: %d/%d output: %dx%d components: %d", iwidth, iheight, destrect.width, destrect.height, Ymagine_scaleModeStr(options->scalemode), cinfo->scale_num, cinfo->scale_denom, cinfo->output_width, cinfo->output_height, cinfo->output_components); #endif /* Scale the crop region to reflect scaling ratio applied by JPEG decoder */ if (cinfo->image_width != cinfo->output_width) { srcrect.x = (srcrect.x * cinfo->output_width) / cinfo->image_width; srcrect.width = (srcrect.width * cinfo->output_width) / cinfo->image_width; } if (cinfo->image_height != cinfo->output_height) { srcrect.y = (srcrect.y * cinfo->output_height) / cinfo->image_height; srcrect.height = (srcrect.height * cinfo->output_height) / cinfo->image_height; } /* Number of scan lines to handle per pass. Making it larger actually doesn't help much */ row_stride = cinfo->output_width * cinfo->output_components; scanlines = (32 * 1024) / row_stride; if (scanlines < 1) { scanlines = 1; } if (scanlines > cinfo->output_height) { scanlines = cinfo->output_height; } #if YMAGINE_DEBUG_JPEG ALOGD("BITMAP @(%d,%d) %dx%d bpp=%d -> @(%dx%d) %dx%d (%d lines)", srcrect.x, srcrect.y, srcrect.width, srcrect.height, JpegPixelSize(cinfo->out_color_space), destrect.x, destrect.y, destrect.width, destrect.height, scanlines); #endif /* Resize encoder */ if (cinfoout != NULL) { cinfoout->image_width = destrect.width; cinfoout->image_height = destrect.height; jpeg_start_compress(cinfoout, TRUE); if (copyoption != JCOPYOPT_NONE) { /* Copy to the output file any extra markers that we want to preserve */ jcopy_markers_execute(cinfo, cinfoout, copyoption); } } /* Resize target bitmap */ if (vbitmap != NULL) { if (options->resizable) { destrect.x = 0; destrect.y = 0; if (VbitmapResize(vbitmap, destrect.width, destrect.height) != YMAGINE_OK) { return 0; } } if (VbitmapType(vbitmap) == VBITMAP_NONE) { /* Decode bounds only, return positive number (number of lines) on success */ return VbitmapHeight(vbitmap); } } if (!jpeg_start_decompress(cinfo)) { if (cinfoout != NULL) { jpeg_abort_compress(cinfoout); } return 0; } buffer = (JSAMPARRAY) (*cinfo->mem->alloc_sarray)((j_common_ptr) cinfo, JPOOL_IMAGE, row_stride, scanlines); if (buffer == NULL) { if (cinfoout != NULL) { jpeg_abort_compress(cinfoout); } jpeg_abort_decompress(cinfo); return 0; } totallines = 0; transformer = TransformerCreate(); if (transformer != NULL) { TransformerSetScale(transformer, cinfo->output_width, cinfo->output_height, destrect.width, destrect.height); TransformerSetRegion(transformer, srcrect.x, srcrect.y, srcrect.width, srcrect.height); if (vbitmap != NULL) { TransformerSetMode(transformer, JpegPixelMode(cinfo->out_color_space), VbitmapColormode(vbitmap)); TransformerSetBitmap(transformer, vbitmap, destrect.x, destrect.y); } else { TransformerSetMode(transformer, JpegPixelMode(cinfo->out_color_space), JpegPixelMode(cinfoout->in_color_space)); TransformerSetWriter(transformer, JpegWriter, cinfoout); } TransformerSetShader(transformer, shader); TransformerSetSharpen(transformer, sharpen); } while (transformer != NULL && cinfo->output_scanline < cinfo->output_height) { nlines = jpeg_read_scanlines(cinfo, buffer, scanlines); if (nlines <= 0) { /* Decoding error */ ALOGD("decoding error (nlines=%d)", nlines); break; } for (j = 0; j < nlines; j++) { if (TransformerPush(transformer, (const char*) buffer[j]) != YMAGINE_OK) { TransformerRelease(transformer); transformer = NULL; break; } totallines++; } } /* Clean up */ if (transformer != NULL) { TransformerRelease(transformer); } if (cinfo->output_scanline > 0 && cinfo->output_scanline == cinfo->output_height) { /* Do normal cleanup if whole image has been read and decoded */ jpeg_finish_decompress(cinfo); if (cinfoout != NULL) { jpeg_finish_compress(cinfoout); } } else { /* else early abort */ jpeg_abort_decompress(cinfo); if (cinfoout != NULL) { jpeg_abort_compress(cinfoout); } totallines = 0; } return totallines; }