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; }
static int VbitmapComputeIntersection(Vbitmap *vbitmap, const Vrect *region, Vrect *output) { Vrect vrect; if (output == NULL) return YMAGINE_OK; if (vbitmap == NULL) return YMAGINE_ERROR; if (region == NULL) { output->x = 0; output->y = 0; output->width = VbitmapWidth(vbitmap); output->height = VbitmapHeight(vbitmap); } // Nothing is NULL vrect.x = 0; vrect.y = 0; vrect.width = VbitmapWidth(vbitmap); vrect.height = VbitmapHeight(vbitmap); VrectComputeIntersection(&vrect, region, output); return YMAGINE_OK; }
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; }
static int quantizeWithOptions(Vbitmap *vbitmap, int maxcolors, Vcolor *colors, int *scores, int processing) { int i; int x, y, c; unsigned char *pixels; unsigned char *line; ColorArea centroid[PALETTESIZE]; Vcolor current; int width, height, pitch; uint64_t dist; uint64_t refdist; int refid; int ncolors; int maxiters = 100; if (maxcolors <= 0 || colors == NULL) { return 0; } if (vbitmap == NULL) { return 0; } if (processing == YMAGINE_THEME_DEFAULT) { processing = YMAGINE_THEME_SATURATION; } if (processing != YMAGINE_THEME_NONE && processing != YMAGINE_THEME_SATURATION) { return 0; } if (VbitmapLock(vbitmap) < 0) { return 0; } pixels = VbitmapBuffer(vbitmap); if (pixels == NULL) { VbitmapUnlock(vbitmap); return 0; } width = VbitmapWidth(vbitmap); height = VbitmapHeight(vbitmap); pitch = VbitmapPitch(vbitmap); if (width <= 0 || height <= 0 || pitch <= 0) { VbitmapUnlock(vbitmap); return 0; } /* Verify that width*height < 1<<24. This quarantee that will be no overflow in accumulators */ if (hasMultiplyOverflow((((uint32_t) 1)<<24), width, height)) { VbitmapUnlock(vbitmap); return 0; } /* Initial result, using default palette */ if (maxcolors > PALETTESIZE) { maxcolors = PALETTESIZE; } for (c = 0; c < maxcolors; c++) { centroid[c].color = palette[c]; centroid[c].count = 0; } #if 0 for (c = 0; c < maxcolors; c++) { fprintf(stderr, "Init[%d] = #%02x%02x%02x%02x (%d)\n", c, centroid[c].color.red, centroid[c].color.green, centroid[c].color.blue, centroid[c].color.alpha, centroid[c].count); } #endif for (i = 0; i < maxiters; i++) { /* Reset accumulators */ for (c = 0; c < maxcolors; c++) { centroid[c].accum_red = 0; centroid[c].accum_green = 0; centroid[c].accum_blue = 0; centroid[c].accum_alpha = 0; centroid[c].count = 0; } /* Assign each pixel to its nearest centroid */ current.alpha = 0xff; for (y = 0; y < height; y++){ line = pixels + y * pitch; for (x = 0; x < width; x++) { /* Current pixel as a Color record */ current.red=line[RED_OFFSET]; current.green=line[GREEN_OFFSET]; current.blue=line[BLUE_OFFSET]; current.alpha=line[ALPHA_OFFSET]; line+=4; /* Assign to first centroid by default */ refdist = norm2(¤t, &(centroid[0].color)); refid = 0; /* Then try to find a closer one */ for (c = 1; c < maxcolors; c++) { dist = norm2(¤t, &(centroid[c].color)); if (dist < refdist) { refdist = dist; refid = c; } } /* Assign this pixel to closest centroid */ centroid[refid].accum_red += current.red; centroid[refid].accum_green += current.green; centroid[refid].accum_blue += current.blue; centroid[refid].accum_alpha += current.alpha; centroid[refid].count++; } } refdist = 0; for (c = 0; c < maxcolors; c++) { if (centroid[c].count == 0) { current.red = 0xff; current.green = 0xff; current.blue = 0xff; current.alpha = 0xff; } else { current.red = centroid[c].accum_red/centroid[c].count; current.green = centroid[c].accum_green/centroid[c].count; current.blue = centroid[c].accum_blue/centroid[c].count; current.alpha = 0xff; } dist = norm2(¤t, &(centroid[c].color)); if (dist > refdist) { refdist = dist; } centroid[c].color = current; } if (refdist < 1) { break; } } VbitmapUnlock(vbitmap); /* Saturation */ if (processing == YMAGINE_THEME_SATURATION) { int i; uint32_t dwhite; uint32_t dblack; uint32_t dcrit, dmin; Vcolor col; col.red = 0x20; col.green = 0x20; col.blue = 0x20; col.alpha = 0xff; dcrit = norm2(&col, &black); /* Update scores to prefer saturated colors */ for (i = 0; i < maxcolors; i++) { uint32_t coeff; col.red = centroid[i].color.red; col.green = centroid[i].color.green; col.blue = centroid[i].color.blue; col.alpha = centroid[i].color.alpha; dwhite = norm2(&white, &col); dblack = norm2(&black, &col); dmin = (dwhite < dblack) ? dwhite : dblack; coeff = 256; if (dmin < dcrit) { coeff = (256 * (dcrit + (dcrit - dmin))) / dcrit; } centroid[i].count = (centroid[i].count * 256) / coeff; } } /* Sort colors, most dominant one first */ qsort(centroid, maxcolors, sizeof(centroid[0]), ColorAreaCompare); /* Put colors into ARGB format */ ncolors = 0; for (c = 0; c < maxcolors; c++) { if (centroid[c].count <= 0) { continue; } colors[c] = centroid[c].color; if (scores != NULL) { scores[c] = (int) centroid[c].count; } #if 0 ALOGD("color[%d] = #%02x%02x%02x%02x (%d)", c, centroid[c].color.red, centroid[c].color.green, centroid[c].color.blue, centroid[c].color.alpha, centroid[c].count); #endif ncolors++; } return ncolors; }
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; }
double VbitmapComputePSNR(Vbitmap *vbitmap, Vbitmap *reference) { int width; int height; unsigned char* v1buffer; unsigned char* v2buffer; int bpp1; int bpp2; int v1pitch; int v2pitch; double error = 0.0; double psnr = -1.0; if (vbitmap == NULL || reference == NULL || VbitmapWidth(vbitmap) != VbitmapWidth(reference) || VbitmapHeight(vbitmap) != VbitmapHeight(reference)) { return psnr; } if (vbitmap == reference) { return VBITMAP_MAX_PSNR; } bpp1 = VbitmapBpp(vbitmap); bpp2 = VbitmapBpp(reference); if (VbitmapLock(vbitmap) == YMAGINE_OK) { if (VbitmapLock(reference) == YMAGINE_OK) { v1buffer = VbitmapBuffer(vbitmap); v2buffer = VbitmapBuffer(reference); if (v1buffer != NULL && v2buffer != NULL) { width = VbitmapWidth(vbitmap); height = VbitmapHeight(vbitmap); v1pitch = VbitmapPitch(vbitmap); v2pitch = VbitmapPitch(reference); if (bpp1 == 1 && bpp2 == 1) { error = calculateError(width, height, v1buffer, v2buffer, 1, 1, v1pitch, v2pitch, 1); } else if (bpp1 == 3 && bpp2 == 3) { error = calculateError(width, height, v1buffer, v2buffer, 3, 3, v1pitch, v2pitch, 3); } else if (bpp1 == 4 && bpp2 == 4) { error = calculateError(width, height, v1buffer, v2buffer, 4, 4, v1pitch, v2pitch, 4); } else { int bpp = MIN(bpp1, bpp2); error = calculateError(width, height, v1buffer, v2buffer, bpp1, bpp2, v1pitch, v2pitch, bpp); } } VbitmapUnlock(reference); } VbitmapUnlock(vbitmap); } if (error > 1.0e-10) { psnr = (10.0 / LOG10) * log((255.0 * 255.0) / error); if (psnr > VBITMAP_MAX_PSNR) { psnr = VBITMAP_MAX_PSNR; } } else { psnr = VBITMAP_MAX_PSNR; } return psnr; }
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; }
static int tileRender(Vbitmap *canvas, int ntiles, int tileid, Ychannel* channelin, Vbitmap *srcbitmap) { int rc; int maxWidth = -1; int maxHeight = -1; /* scaleMode can be YMAGINE_SCALE_CROP or YMAGINE_SCALE_LETTERBOX */ int scaleMode = YMAGINE_SCALE_CROP; /* Fit mode */ int adjustMode = YMAGINE_ADJUST_NONE; /* metaMode can be one of YMAGINE_METAMODE_ALL, YMAGINE_METAMODE_COMMENTS, YMAGINE_METAMODE_NONE or YMAGINE_METAMODE_DEFAULT */ int metaMode = YMAGINE_METAMODE_DEFAULT; int quality = -1; int accuracy = -1; int subsampling = -1; int progressive = -1; float sharpen = 0.0f; float blur = 0.0f; float rotate = 0.0f; #if YMAGINE_PROFILE int profile = 0; NSTYPE start = 0; NSTYPE end = 0; NSTYPE start_decode = 0; NSTYPE end_decode = 0; #endif YmagineFormatOptions *options = NULL; Vbitmap *vbitmap = NULL; int canvasw; int canvash; int tilex; int tiley; int tilew; int tileh; #if YMAGINE_PROFILE if (profile) { start = NSTIME(); } #endif canvasw = VbitmapWidth(canvas); canvash = VbitmapHeight(canvas); if (ntiles > 4) { ntiles = 4; } if (tileid < 0 || tileid >= ntiles) { return YMAGINE_OK; } if (ntiles == 1) { tilex = 0; tiley = 0; tilew = canvasw; tileh = canvash; } else if (ntiles == 2) { tilex = cell(canvasw, tileid % 2, 2); tiley = cell(canvash, tileid / 2, 1); tilew = cell(canvasw, (tileid % 2) + 1, 2) - tilex; tileh = cell(canvash, (tileid / 2) + 1, 1) - tiley; } else if (ntiles == 3) { tilex = cell(canvasw, tileid % 2, 2); tiley = cell(canvash, tileid / 2, 2); tilew = cell(canvasw, (tileid % 2) + 1, 2) - tilex; if (tileid == 0) { tilex = 0; tiley = 0; tilew = cell(canvasw, 1, 2) - tilex; tileh = canvash; } else { tilex = cell(canvasw, 1, 2); tiley = cell(canvash, (tileid - 1) % 2, 2); tilew = cell(canvasw, 2, 2) - tilex; tileh = cell(canvash, ((tileid - 1) % 2) + 1, 2) - tiley; } } else { tilex = cell(canvasw, tileid % 2, 2); tiley = cell(canvash, tileid / 2, 2); tilew = cell(canvasw, (tileid % 2) + 1, 2) - tilex; tileh = cell(canvash, (tileid / 2) + 1, 2) - tiley; } maxWidth = tilew; maxHeight = tileh; rc = YMAGINE_ERROR; options = YmagineFormatOptions_Create(); if (options != NULL) { YmagineFormatOptions_setResize(options, maxWidth, maxHeight, scaleMode); YmagineFormatOptions_setQuality(options, quality); YmagineFormatOptions_setAccuracy(options, accuracy); YmagineFormatOptions_setMetaMode(options, metaMode); if (subsampling >= 0) { YmagineFormatOptions_setSubsampling(options, subsampling); } if (progressive >= 0) { YmagineFormatOptions_setProgressive(options, progressive); } if (sharpen > 0.0f) { YmagineFormatOptions_setSharpen(options, sharpen); } if (blur > 0.0f) { YmagineFormatOptions_setBlur(options, blur); } if (rotate != 0.0f) { YmagineFormatOptions_setRotate(options, rotate); } YmagineFormatOptions_setAdjust(options, adjustMode); vbitmap = VbitmapInitMemory(VBITMAP_COLOR_RGBA); if (vbitmap != NULL) { #if YMAGINE_PROFILE start_decode = NSTIME(); #endif if (channelin != NULL) { rc = YmagineDecode(vbitmap, channelin, options); } else if (srcbitmap != NULL) { rc = YmagineDecodeCopy(vbitmap, srcbitmap, options); } else { rc = YMAGINE_ERROR; } #if YMAGINE_PROFILE end_decode = NSTIME(); if (profile) { ALOGI("Decoded image %dx%d in %.2f ms\n", VbitmapWidth(vbitmap), VbitmapHeight(vbitmap), ((double) (end_decode - start_decode)) / 1000000.0); } #endif if (rc == YMAGINE_OK) { VbitmapRegionSelect(canvas, tilex, tiley, tilew, tileh); Ymagine_composeImage(canvas, vbitmap, 0, 0, YMAGINE_COMPOSE_BUMP); VbitmapRegionReset(canvas); #if YMAGINE_PROFILE if (profile) { end = NSTIME(); ALOGI("Rendered orb tile %d/%d in %.2f ms\n", tileid, ntiles, ((double) (end - start)) / 1000000.0); } #endif } VbitmapRelease(vbitmap); } YmagineFormatOptions_Release(options); options = NULL; } return rc; }
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; }
int parseopts_shader(const char* argv[], int argc, int i, PixelShader *shader, int compose) { /* Number of arguments processed */ int nargs = 0; if (argv[i][1] == 's' && strcmp(argv[i], "-saturation") == 0) { double saturation = 0.0f; if (i+1 >= argc) { fprintf(stdout, "missing value after option \"%s\"\n", argv[i]); fflush(stdout); return -1; } i++; saturation = atof(argv[i]); Yshader_PixelShader_saturation(shader, saturation); nargs += 2; } else if (argv[i][1] == 'e' && strcmp(argv[i], "-exposure") == 0) { double exposure = 0.0f; if (i+1 >= argc) { fprintf(stdout, "missing value after option \"%s\"\n", argv[i]); fflush(stdout); return -1; } i++; exposure = atof(argv[i]); Yshader_PixelShader_exposure(shader, exposure); nargs += 2; } else if (argv[i][1] == 'c' && strcmp(argv[i], "-contrast") == 0) { double contrast = 0.0f; if (i+1 >= argc) { fprintf(stdout, "missing value after option \"%s\"\n", argv[i]); fflush(stdout); return -1; } i++; contrast = atof(argv[i]); Yshader_PixelShader_contrast(shader, contrast); nargs += 2; } else if (argv[i][1] == 'b' && strcmp(argv[i], "-brightness") == 0) { double brightness = 0.0f; if (i+1 >= argc) { fprintf(stdout, "missing value after option \"%s\"\n", argv[i]); fflush(stdout); return -1; } i++; brightness = atof(argv[i]); Yshader_PixelShader_brightness(shader, brightness); nargs += 2; } else if (argv[i][1] == 't' && strcmp(argv[i], "-temperature") == 0) { double temperature = 0.0f; if (i+1 >= argc) { fprintf(stdout, "missing value after option \"%s\"\n", argv[i]); fflush(stdout); return -1; } i++; temperature = atof(argv[i]); Yshader_PixelShader_temperature(shader, temperature); nargs += 2; } else if (argv[i][1] == 'w' && strcmp(argv[i], "-whitebalance") == 0) { double whitebalance = 0.0f; if (i+1 >= argc) { fprintf(stdout, "missing value after option \"%s\"\n", argv[i]); fflush(stdout); return -1; } i++; whitebalance = atof(argv[i]); Yshader_PixelShader_whitebalance(shader, whitebalance); nargs += 2; } else if (argv[i][1] == 'v' && strcmp(argv[i], "-vignette") == 0) { Vbitmap *vmap; const char* shaderfile; int fd; Ychannel* channel; if (i+1 >= argc) { fprintf(stdout, "missing value after option \"%s\"\n", argv[i]); fflush(stdout); return -1; } i++; /* load map for vignette */ shaderfile = argv[i]; fd = open(shaderfile, O_RDONLY); if (fd < 0) { fprintf(stderr, "error loading vignette map \"%s\"\n", shaderfile); return -1; } vmap = VbitmapInitMemory(VBITMAP_COLOR_RGBA); channel = YchannelInitFd(fd, 0); YmagineDecodeResize(vmap, channel, -1, -1, YMAGINE_SCALE_LETTERBOX); YchannelRelease(channel); /* Either set auto-release to true, or close the file descriptor Ychannel doesn't own */ close(fd); fprintf(stderr, "Loaded vignette map from '%s' %dx%d\n", shaderfile, VbitmapWidth(vmap), VbitmapHeight(vmap)); /* Append vignette shader to pipeline */ VbitmapRetain(vmap); Yshader_PixelShader_vignette(shader, vmap, compose); VbitmapRelease(vmap); nargs += 2; } return nargs; }