/* * API to manage shader effects */ static void TransformerReleaseCallback(void *ptr) { Transformer *transformer = (Transformer*)ptr; if (transformer == NULL) { return; } if (transformer->destbuf != NULL) { Ymem_free(transformer->destbuf); transformer->destbuf = NULL; transformer->destaligned = NULL; } if (transformer->bltmap != NULL) { Ymem_free(transformer->bltmap); transformer->bltmap = NULL; } if (transformer->statsbuf != NULL) { Ymem_free(transformer->statsbuf); transformer->statsbuf = NULL; } Ymem_free(transformer); }
static void vbitmap_release_callback(void *ptr) { Vbitmap *vbitmap; if (ptr == NULL) { return; } vbitmap = (Vbitmap*)ptr; if (vbitmap->bitmaptype == VBITMAP_MEMORY) { if (vbitmap->pixels != NULL) { Ymem_free(vbitmap->pixels); } if (vbitmap->region != NULL) { Ymem_free(vbitmap->region); } } if (vbitmap->bitmaptype == VBITMAP_ANDROID) { if (vbitmap->jbitmap != NULL) { if (vbitmap->jkeepref) { JNIEnv *jenv = getEnv(vbitmap); if (jenv != NULL) { (*jenv)->DeleteGlobalRef(jenv, vbitmap->jbitmap); } } vbitmap->jbitmap = NULL; } } Ymem_free(vbitmap); }
Ybuffer* Ybuffer_init(int initiallength) { char *data; Ybuffer *membuf; membuf = (Ybuffer*) Ymem_malloc(sizeof(Ybuffer)); if (membuf == NULL) { return NULL; } if (initiallength <= 0) { membuf->data = NULL; membuf->datalen = 0; membuf->dataincr = 64; } else { data = (char*) Ymem_malloc(initiallength); if (data == NULL) { Ymem_free(membuf); return NULL; } membuf->data = data; membuf->datalen = initiallength; membuf->dataincr = initiallength; } membuf->pos = 0; membuf->status = YBUFFER_STATUS_OK; return membuf; }
void Ybuffer_fini(Ybuffer *stream) { char *data; data = Ybuffer_detach(stream, NULL); if (data != NULL) { Ymem_free(data); } }
int VbitmapRegionReset(Vbitmap *vbitmap) { if (vbitmap != NULL) { if (vbitmap->region != NULL) { Ymem_free(vbitmap->region); vbitmap->region = NULL; } return YMAGINE_OK; } return YMAGINE_ERROR; }
YOSAL_OBJECT_END static void vformat_release_callback(void *ptr) { Vformat *vformat; if (ptr == NULL) { return; } vformat = (Vformat*) ptr; Ymem_free(vformat); }
static boolean APP1_handler (j_decompress_ptr cinfo) { int length; int i; unsigned char *data = NULL; if (cinfo == NULL) { return FALSE; } length = jpeg_getc(cinfo) << 8; length += jpeg_getc(cinfo); if (length < 2) { return FALSE; } length -= 2; /* Read marker data in memory. Also get sure buffer is null terminated Null terminates buffer to make it printable for debugging */ data = Ymem_malloc(length + 1); if (data == NULL) { return FALSE; } for (i = 0; i < length; i++) { data[i] = (unsigned char) jpeg_getc(cinfo); } data[length] = '\0'; int l = strlen(XMP_MARKER); if (length >= l + 1 && memcmp(data, XMP_MARKER, l) == 0 && data[l] == '\0') { VbitmapXmp xmp; Vbitmap *vbitmap = (Vbitmap*) cinfo->client_data; char *xmpbuf = (char*) (data + l + 1); int xmplen = length - (l + 1); /* Parse XML data */ if (parseXMP(&xmp, xmpbuf, xmplen) == YMAGINE_OK) { if (vbitmap != NULL) { VbitmapSetXMP(vbitmap, &xmp); } } } Ymem_free(data); return TRUE; }
char* Ybuffer_detach(Ybuffer *stream, int *datalen) { char *data; if (stream == NULL) { data = NULL; if (datalen != NULL) { *datalen = 0; } } else { data = stream->data; if (datalen != NULL) { *datalen = stream->pos; } Ymem_free(stream); } return data; }
int getThemeColors(Vbitmap *vbitmap, int ncol, int *colors, int *scores) { int ncolors = 0; int i; if (vbitmap == NULL || ncol <= 0) { return 0; } Vcolor *vcolors = Ymem_malloc(ncol * sizeof(Vcolor)); if (vcolors != NULL) { ncolors = quantizeWithOptions(vbitmap, ncol, vcolors, scores, YMAGINE_THEME_SATURATION); for (i = 0; i < ncolors; i++) { colors[i] = RGBA(vcolors[i].red, vcolors[i].green, vcolors[i].blue, vcolors[i].alpha); } Ymem_free(vcolors); } return ncolors; }
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; }
/* A fast, yet not gaussian blurring algorithm. To approximate gaussian blur accurately, one can call blurSuperfast with a small radius and higher number of iterations */ int Ymagine_blurSuperfast(unsigned char *pix, int w, int h, int pitch, int colormode, int radius, int niter) { unsigned char *dv = NULL; int *vbuf = NULL; unsigned char *rgba = NULL; int wm, hm; int wh; int div; unsigned char *r, *g, *b, *a; int rsum, gsum, bsum, asum;; int x, y; int i, n; int p, p1, p2; int yi, zi, yw; int maxwh; int *vmin; int *vmax; int alpha = 255; int alpha2 = 255; int rc = YMAGINE_ERROR; int bpp; int roffset, goffset, boffset, aoffset; int premultiply = 0; if (radius <= 0 || niter <= 0) { return YMAGINE_OK; } if (w <= 0 || h <= 0) { return YMAGINE_OK; } switch (colormode) { case VBITMAP_COLOR_RGBA: bpp = 4; roffset = 0; goffset = 1; boffset = 2; aoffset = 3; premultiply = 0; break; case VBITMAP_COLOR_rgbA: bpp = 4; roffset = 0; goffset = 1; boffset = 2; aoffset = 3; premultiply = 1; break; case VBITMAP_COLOR_ARGB: bpp = 4; roffset = 1; goffset = 2; boffset = 3; aoffset = 0; premultiply = 0; break; case VBITMAP_COLOR_Argb: bpp = 4; roffset = 1; goffset = 2; boffset = 3; aoffset = 0; premultiply = 1; break; case VBITMAP_COLOR_RGB: bpp = 3; roffset = 0; goffset = 1; boffset = 2; aoffset = -1; premultiply = 0; break; default: return YMAGINE_ERROR; } maxwh = MAX(w, h); wm = w - 1; hm = h - 1; wh = w * h; div = radius + radius + 1; /* TODO: dont recalculate if calling multiple time with same radius */ dv = (unsigned char*) Ymem_malloc(256*div*sizeof(dv[0])); if (dv == NULL) { goto cleanup; } for (i = 0 ; i < 256 * div; i++) { dv[i] = (i / div); } vbuf = (int*) Ymem_malloc(maxwh * sizeof(vbuf[0]) * 2); if (vbuf == NULL) { goto cleanup; } rgba = Ymem_malloc(wh * 4); if (rgba == NULL) { goto cleanup; } r = rgba; g = r + wh; b = g + wh; a = b + wh; vmin = vbuf; vmax = vbuf + maxwh; for (n = 0; n < niter; n++) { yw = 0; /* Vertical pass */ for (y = 0; y < h; y++) { rsum = 0; gsum = 0; bsum = 0; asum = 0; yi = y * pitch; zi = y * w; for (i = -radius; i <= radius; i++) { p = yi + (MIN(wm, MAX(i,0)) * bpp); if (aoffset >= 0) { alpha = pix[p + aoffset]; } if (alpha == 255 || premultiply) { rsum += pix[p + roffset]; gsum += pix[p + goffset]; bsum += pix[p + boffset]; } else if (alpha != 0) { rsum += (pix[p + roffset] * alpha) / 255; gsum += (pix[p + goffset] * alpha) / 255; bsum += (pix[p + boffset] * alpha) / 255; } asum += alpha; } for (x = 0; x < w; x++) { r[zi] = dv[rsum]; g[zi] = dv[gsum]; b[zi] = dv[bsum]; a[zi] = dv[asum]; if (y == 0) { vmin[x] = MIN(x+radius+1, wm); vmax[x] = MAX(x-radius, 0); } p1 = yw + (vmin[x] * bpp); p2 = yw + (vmax[x] * bpp); if (aoffset >= 0) { alpha = pix[p1 + aoffset]; alpha2 = pix[p2 + aoffset]; } if ((alpha == 255 && alpha2 == 255) || premultiply) { rsum += pix[p1 + roffset] - pix[p2 + roffset]; gsum += pix[p1 + goffset] - pix[p2 + goffset]; bsum += pix[p1 + boffset] - pix[p2 + boffset]; } else { rsum += (pix[p1 + roffset] * alpha) / 255 - (pix[p2 + roffset] * alpha2) / 255; gsum += (pix[p1 + goffset] * alpha) / 255 - (pix[p2 + goffset] * alpha2) / 255; bsum += (pix[p1 + boffset] * alpha) / 255 - (pix[p2 + boffset] * alpha2) / 255; } asum += alpha - alpha2; zi++; } yw += pitch; } /* Horizontal pass */ for (x = 0; x < w; x++) { rsum = 0; gsum = 0; bsum = 0; asum = 0; for (i = -radius; i <= radius; i++) { yi = MIN(MAX(0,i),hm) * w + x; rsum += r[yi]; gsum += g[yi]; bsum += b[yi]; asum += a[yi]; } yi = x * bpp; for (y = 0; y < h; y++) { pix[yi + roffset] = dv[rsum]; pix[yi + goffset] = dv[gsum]; pix[yi + boffset] = dv[bsum]; if (aoffset >= 0) { pix[yi + aoffset] = dv[asum]; } if (x == 0) { vmin[y] = MIN(y+radius+1, hm)*w; vmax[y] = MAX(y-radius, 0)*w; } p1 = x + vmin[y]; p2 = x + vmax[y]; if (aoffset >= 0) { alpha = a[p1]; alpha2 = a[p2]; } rsum += r[p1] - r[p2]; gsum += g[p1] - g[p2]; bsum += b[p1] - b[p2]; if (alpha != alpha2) { asum += alpha - alpha2; } yi += pitch; } } } rc = YMAGINE_OK; cleanup: if (rgba != NULL) { Ymem_free(rgba); rgba = NULL; } if (vbuf != NULL) { Ymem_free(vbuf); vbuf = NULL; } if (dv != NULL) { Ymem_free(dv); dv = NULL; } return rc; }