int main(int argc, char *const argv[]) { char *map_output_file = NULL; if (argc < 3) { usage(argv[0]); return 1; } opterr = 0; int c; while((c = getopt(argc, argv, "ho:")) != -1) { switch (c) { case 'h': usage(argv[0]); return 0; case 'o': map_output_file = optarg; break; default: fprintf(stderr, "Unknown option\n"); return 1; } } if (optind+1 >= argc) { fprintf(stderr, "You must specify at least 2 files to compare\n"); return 1; } const char *file1 = argv[optind]; png24_image image1 = {}; int retval = read_image(file1, &image1); if (retval) { fprintf(stderr, "Can't read %s (%d)\n", file1, retval); return retval; } dssim_attr *attr = dssim_create_attr(); dssim_image *original = dssim_create_image(attr, image1.row_pointers, DSSIM_RGBA, image1.width, image1.height, get_gamma(&image1)); free(image1.row_pointers); free(image1.rgba_data); for (int arg = optind+1; arg < argc; arg++) { const char *file2 = argv[arg]; png24_image image2 = {}; retval = read_image(file2, &image2); if (retval) { fprintf(stderr, "Can't read %s (%d)\n", file2, retval); break; } if (image1.width != image2.width || image1.height != image2.height) { fprintf(stderr, "Image %s has different size than %s\n", file2, file1); retval = 4; break; } dssim_image *modified = dssim_create_image(attr, image2.row_pointers, DSSIM_RGBA, image2.width, image2.height, get_gamma(&image2)); free(image2.row_pointers); free(image2.rgba_data); if (!modified) { fprintf(stderr, "Unable to process image %s\n", file2); retval = 4; break; } if (map_output_file) { dssim_set_save_ssim_maps(attr, 1, 1); } double dssim = dssim_compare(attr, original, modified); dssim_dealloc_image(modified); printf("%.8f\t%s\n", dssim, file2); if (map_output_file) { dssim_ssim_map map_meta = dssim_pop_ssim_map(attr, 0, 0); dssim_px_t *map = map_meta.data; dssim_rgba *out = (dssim_rgba*)map; for(int i=0; i < map_meta.width*map_meta.height; i++) { const dssim_px_t max = 1.0 - map[i]; const dssim_px_t maxsq = max * max; out[i] = (dssim_rgba) { .r = to_byte(max * 3.0), .g = to_byte(maxsq * 6.0), .b = to_byte(max / ((1.0 - map_meta.dssim) * 4.0)), .a = 255, }; } if (write_image(map_output_file, out, map_meta.width, map_meta.height)) { fprintf(stderr, "Can't write %s\n", map_output_file); free(map); return 1; } free(map); } } dssim_dealloc_image(original); dssim_dealloc_attr(attr); return retval; }
void nemo_main() { stream instr, outstr; int nx, ny, nz; /* size of scratch map */ int nx1, ny1, nz1, nz2; int ni, i, ix, iy, iz, iz1; real dmin, dmax; imageptr iptr[MAXIM], optr; /* pointer to image */ string flipmode; instr = stropen(getparam("in"), "r"); outstr = stropen(getparam("out"), "w"); for (i=0; i<MAXIM; i++) { /* loop over all to gather data */ iptr[i] = 0; if (read_image( instr, &iptr[i]) == 0) break; nx1 = Nx(iptr[i]); ny1 = Ny(iptr[i]); nz1 = Nz(iptr[i]); dprintf(1,"Image %d: %d x %d x %d\n",i,nx1,ny1,nz1); if (i==0) { nx = nx1; ny = ny1; nz = nz1; dmin = MapMin(iptr[i]); dmax = MapMax(iptr[i]); } else { if (nx != nx1) error("size nx: %d != %d",nx,nx1); if (ny != ny1) error("size ny: %d != %d",ny,ny1); nz += nz1; dmin = MIN(dmin,MapMin(iptr[i])); dmax = MAX(dmax,MapMax(iptr[i])); } } ni = i; dprintf(0,"Final cube: %d x %d x %d\n",nx,ny,nz); dprintf(0,"Data min/max: %g %g\n",dmin,dmax); create_cube(&optr,nx,ny,nz); MapMin(optr) = dmin; MapMax(optr) = dmax; Xmin(optr) = Xmin(iptr[0]); Ymin(optr) = Ymin(iptr[0]); Zmin(optr) = Zmin(iptr[0]); Xref(optr) = Xref(iptr[0]); Yref(optr) = Yref(iptr[0]); Zref(optr) = Zref(iptr[0]); Dx(optr) = Dx(iptr[0]); Dy(optr) = Dy(iptr[0]); Dz(optr) = Dz(iptr[0]); for (i=0, iz=0; i<ni; i++) { /* grab all data in output cube */ nz1 = Nz(iptr[i]); for (iz1=0; iz1< nz1; iz1++, iz++) { for (iy=0; iy<ny; iy++) { for (ix=0; ix<nx; ix++) { CubeValue(optr,ix,iy,iz) = CubeValue(iptr[i],ix,iy,iz1); } } } } write_image(outstr, optr); }
dt_imageio_retval_t dt_imageio_open_png(dt_image_t *img, const char *filename, dt_mipmap_buffer_t *mbuf) { const char *ext = filename + strlen(filename); while(*ext != '.' && ext > filename) ext--; if(strncmp(ext, ".png", 4) && strncmp(ext, ".PNG", 4)) return DT_IMAGEIO_FILE_CORRUPTED; if(!img->exif_inited) (void)dt_exif_read(img, filename); dt_imageio_png_t image; uint8_t *buf = NULL; uint32_t width, height; uint16_t bpp; if(read_header(filename, &image) != 0) return DT_IMAGEIO_FILE_CORRUPTED; width = img->width = image.width; height = img->height = image.height; bpp = image.bit_depth; img->bpp = 4 * sizeof(float); float *mipbuf = (float *)dt_mipmap_cache_alloc(mbuf, img); if(!mipbuf) { fclose(image.f); png_destroy_read_struct(&image.png_ptr, NULL, NULL); fprintf(stderr, "[png_open] could not alloc full buffer for image `%s'\n", img->filename); return DT_IMAGEIO_CACHE_FULL; } buf = dt_alloc_align(16, (size_t)width * height * 3 * (bpp < 16 ? 1 : 2)); if(!buf) { fclose(image.f); png_destroy_read_struct(&image.png_ptr, NULL, NULL); fprintf(stderr, "[png_open] could not alloc intermediate buffer for image `%s'\n", img->filename); return DT_IMAGEIO_CACHE_FULL; } if(read_image(&image, (void *)buf) != 0) { dt_free_align(buf); fprintf(stderr, "[png_open] could not read image `%s'\n", img->filename); return DT_IMAGEIO_FILE_CORRUPTED; } for(size_t j = 0; j < height; j++) { if(bpp < 16) for(size_t i = 0; i < width; i++) for(int k = 0; k < 3; k++) mipbuf[4 * (j * width + i) + k] = buf[3 * (j * width + i) + k] * (1.0f / 255.0f); else for(size_t i = 0; i < width; i++) for(int k = 0; k < 3; k++) mipbuf[4 * (j * width + i) + k] = (256.0f * buf[2 * (3 * (j * width + i) + k)] + buf[2 * (3 * (j * width + i) + k) + 1]) * (1.0f / 65535.0f); } dt_free_align(buf); return DT_IMAGEIO_OK; }
int convert_to_j2k(opendcp_t *opendcp, char *in_file, char *out_file, char *tmp_path) { odcp_image_t *odcp_image; int result = 0; if (tmp_path == NULL) { tmp_path = "./"; } dcp_log(LOG_DEBUG,"%-15.15s: reading input file %s","convert_to_j2k",in_file); #ifdef OPENMP #pragma omp critical #endif { result = read_image(&odcp_image, in_file); } if (result != OPENDCP_NO_ERROR) { dcp_log(LOG_ERROR,"Unable to read file %s",in_file); return OPENDCP_ERROR; } if (!odcp_image) { dcp_log(LOG_ERROR,"Unable to load file %s",in_file); return OPENDCP_ERROR; } /* verify image is dci compliant */ if (check_image_compliance(opendcp->cinema_profile, odcp_image, NULL) != OPENDCP_NO_ERROR) { dcp_log(LOG_WARN,"The image resolution of %s is not DCI Compliant",in_file); /* resize image */ if (opendcp->j2k.resize) { if (resize(&odcp_image, opendcp->cinema_profile, opendcp->j2k.resize) != OPENDCP_NO_ERROR) { odcp_image_free(odcp_image); return OPENDCP_ERROR; } } else { odcp_image_free(odcp_image); return OPENDCP_ERROR; } } if (opendcp->j2k.xyz) { dcp_log(LOG_INFO,"RGB->XYZ color conversion %s",in_file); if (rgb_to_xyz(odcp_image, opendcp->j2k.lut, opendcp->j2k.xyz_method)) { dcp_log(LOG_ERROR,"Color conversion failed %s",in_file); odcp_image_free(odcp_image); return OPENDCP_ERROR; } } if ( opendcp->j2k.encoder == J2K_KAKADU ) { char tempfile[255]; sprintf(tempfile, "%s/tmp_%s.tif", tmp_path, basename(in_file)); dcp_log(LOG_DEBUG, "%-15.15s: Writing temporary tif %s", "convert_to_j2k", tempfile); result = opendcp_encode_tif(odcp_image, tempfile); odcp_image_free(odcp_image); if (result != OPENDCP_NO_ERROR) { dcp_log(LOG_ERROR,"Writing temporary tif failed"); return OPENDCP_ERROR; } result = encode_kakadu(opendcp, tempfile, out_file); if ( result != OPENDCP_NO_ERROR) { dcp_log(LOG_ERROR,"Kakadu JPEG2000 conversion failed %s",in_file); remove(tempfile); return OPENDCP_ERROR; } remove(tempfile); } else { opj_image_t *opj_image; odcp_to_opj(odcp_image, &opj_image); odcp_image_free(odcp_image); if (encode_openjpeg(opendcp,opj_image,out_file) != OPENDCP_NO_ERROR) { dcp_log(LOG_ERROR,"OpenJPEG JPEG2000 conversion failed %s",in_file); opj_image_destroy(opj_image); return OPENDCP_ERROR; } opj_image_destroy(opj_image); } return OPENDCP_NO_ERROR; }
int cmdline_main (int argc, char *argv[]) { guchar *output; int num_frames = 1; #ifdef MOVIES int generate_movie = 0; quicktime_t *output_movie; guchar **rows; #endif int antialiasing = 0, supersampling = 0; int img_width, img_height; char *generator = 0; userval_info_t *userval_info; int num_input_drawables = 0; gboolean size_is_set = FALSE; char *script = NULL; char *output_filename; gboolean htmldoc = FALSE; define_t *defines = NULL; int bench_render_count = 1; int render_num; gboolean bench_no_output = FALSE; gboolean bench_no_backend = FALSE; int compile_time_limit = DEFAULT_OPTIMIZATION_TIMEOUT; for (;;) { static struct option long_options[] = { { "version", no_argument, 0, OPTION_VERSION }, { "help", no_argument, 0, OPTION_HELP }, { "intersampling", no_argument, 0, 'i' }, { "oversampling", no_argument, 0, 'o' }, { "cache", required_argument, 0, 'c' }, { "generator", required_argument, 0, 'g' }, { "size", required_argument, 0, 's' }, { "script-file", required_argument, 0, 'f' }, { "htmldoc", no_argument, 0, OPTION_HTMLDOC }, { "bench-no-output", no_argument, 0, OPTION_BENCH_NO_OUTPUT }, { "bench-only-compile", no_argument, 0, OPTION_BENCH_ONLY_COMPILE }, { "bench-no-compile-time-limit", no_argument, 0, OPTION_BENCH_NO_COMPILE_TIME_LIMIT }, { "bench-no-backend", no_argument, 0, OPTION_BENCH_NO_BACKEND }, { "bench-render-count", required_argument, 0, OPTION_BENCH_RENDER_COUNT }, #ifdef MOVIES { "frames", required_argument, 0, 'F' }, { "movie", required_argument, 0, 'M' }, #endif { 0, 0, 0, 0 } }; int option, option_index; option = getopt_long(argc, argv, #ifdef MOVIES "f:ioF:D:M:c:g:s:", #else "f:ioD:c:g:s:", #endif long_options, &option_index); if (option == -1) break; switch (option) { case OPTION_VERSION : printf("MathMap " MATHMAP_VERSION "\n" "\n" "Copyright (C) 1997-2009 Mark Probst\n" "\n" "This program is free software; you can redistribute it and/or modify\n" "it under the terms of the GNU General Public License as published by\n" "the Free Software Foundation; either version 2 of the License, or\n" "(at your option) any later version.\n" "\n" "This program is distributed in the hope that it will be useful,\n" "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" "GNU General Public License for more details.\n" "\n" "You should have received a copy of the GNU General Public License\n" "along with this program; if not, write to the Free Software\n" "Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n"); return 0; case OPTION_HELP : usage(); return 0; case OPTION_HTMLDOC : htmldoc = TRUE; break; case 'f' : if (!g_file_get_contents(optarg, &script, NULL, NULL)) { fprintf(stderr, _("Error: The script file `%s' could not be read.\n"), optarg); return 1; } break; case 'i' : antialiasing = 1; break; case 'o' : supersampling = 1; break; case 'c' : cache_size = atoi(optarg); assert(cache_size > 0); break; case 'D' : append_define(optarg, &defines); break; case 'I' : alloc_cmdline_image_input_drawable(optarg); break; case 'g' : generator = optarg; break; case 's' : if (!parse_image_size(optarg, &img_width, &img_height)) { fprintf(stderr, _("Error: Invalid image size. Syntax is <width>x<height>. Example: 1024x768.\n")); exit(1); } size_is_set = 1; break; case OPTION_BENCH_RENDER_COUNT : bench_render_count = atoi(optarg); break; case OPTION_BENCH_ONLY_COMPILE : bench_render_count = 0; break; case OPTION_BENCH_NO_OUTPUT : bench_no_output = TRUE; break; case OPTION_BENCH_NO_COMPILE_TIME_LIMIT : compile_time_limit = -1; break; case OPTION_BENCH_NO_BACKEND : bench_no_backend = TRUE; break; #ifdef MOVIES case 'F' : generate_movie = 1; num_frames = atoi(optarg); assert(num_frames > 0); break; case 'M' : alloc_cmdline_movie_input_drawable(optarg); break; #endif } } if (script != NULL) { if (argc - optind != 1) { usage(); return 1; } output_filename = argv[optind]; } else { if (argc - optind != 2) { usage(); return 1; } script = argv[optind]; output_filename = argv[optind + 1]; } init_tags(); init_builtins(); init_macros(); init_compiler(); if (htmldoc) { mathmap_t *mathmap = parse_mathmap(script); filter_t *filter; FILE *out; if (mathmap == NULL) { fprintf(stderr, _("Error: Could not read MathMap script: %s\n"), error_string); return 1; } out = fopen(output_filename, "w"); if (out == NULL) { fprintf(stderr, _("Error: Cannot open file `%s' for writing: %s\n"), output_filename, strerror(errno)); return 1; } for (filter = mathmap->filters; filter != NULL; filter = filter->next) { if (filter->kind != FILTER_MATHMAP) continue; if (!write_filter_html_doc(out, filter->v.mathmap.decl)) return 1; } fclose(out); } else if (generator == 0) { char *support_paths[4]; mathmap_t *mathmap; mathmap_invocation_t *invocation; int current_frame; support_paths[0] = g_strdup_printf("%s/mathmap", GIMPDATADIR); support_paths[1] = g_strdup_printf("%s/.gimp-2.6/mathmap", getenv("HOME")); support_paths[2] = g_strdup_printf("%s/.gimp-2.4/mathmap", getenv("HOME")); support_paths[3] = NULL; mathmap = compile_mathmap(script, support_paths, compile_time_limit, bench_no_backend); if (bench_no_backend) return 0; if (mathmap == 0) { fprintf(stderr, _("Error: %s\n"), error_string); exit(1); } if (bench_render_count == 0) return 0; if (!size_is_set) for (userval_info = mathmap->main_filter->userval_infos; userval_info != NULL; userval_info = userval_info->next) { define_t *define; unsigned char *image; if (userval_info->type != USERVAL_IMAGE) continue; define = lookup_define(defines, userval_info->name); if (define == NULL) { fprintf(stderr, _("Error: No value defined for input image `%s'.\n"), userval_info->name); return 1; } image = read_image(define->value, &img_width, &img_height); if (image == NULL) { fprintf(stderr, _("Error: Could not read input image `%s'.\n"), define->value); return 1; } free(image); size_is_set = TRUE; break; } if (!size_is_set) { fprintf(stderr, _("Error: Image size not set and no input images given.\n")); exit(1); } invocation = invoke_mathmap(mathmap, NULL, img_width, img_height, TRUE); for (userval_info = mathmap->main_filter->userval_infos; userval_info != NULL; userval_info = userval_info->next) { userval_t *userval = &invocation->uservals[userval_info->index]; define_t *define = lookup_define(defines, userval_info->name); if (define == NULL) { if (userval_info->type == USERVAL_IMAGE) { fprintf(stderr, _("Error: No value defined for input image `%s'.\n"), userval_info->name); return 1; } } else switch (userval_info->type) { case USERVAL_INT_CONST : userval->v.int_const = atoi(define->value); break; case USERVAL_FLOAT_CONST : userval->v.float_const = g_ascii_strtod(define->value, NULL); break; case USERVAL_BOOL_CONST : userval->v.bool_const = (float)atoi(define->value); break; case USERVAL_IMAGE : assign_image_userval_drawable(userval_info, userval, alloc_cmdline_image_input_drawable(define->value)); ++num_input_drawables; break; default : fprintf(stderr, _("Error: Can only define user values for types int, float, bool and image.\n")); return 1; } } for (render_num = 0; render_num < bench_render_count; ++render_num) { #ifdef MOVIES for (i = 0; i < num_input_drawables; ++i) if (input_drawables[i].type == DRAWABLE_MOVIE) { assert(quicktime_video_width(input_drawables[i].v.movie, 0) == img_width); assert(quicktime_video_height(input_drawables[i].v.movie, 0) == img_height); } #endif invocation_set_antialiasing(invocation, antialiasing); invocation->supersampling = supersampling; invocation->output_bpp = 4; output = (guchar*)malloc((long)invocation->output_bpp * (long)img_width * (long)img_height); assert(output != 0); #ifdef MOVIES if (generate_movie) { output_movie = quicktime_open(output_filename, 0, 1); assert(output_movie != 0); quicktime_set_video(output_movie, 1, img_width, img_height, 25, QUICKTIME_JPEG); assert(quicktime_supported_video(output_movie, 0)); quicktime_seek_start(output_movie); rows = (guchar**)malloc(sizeof(guchar*) * img_height); for (i = 0; i < img_height; ++i) rows[i] = output + img_width * invocation->output_bpp * i; } #endif for (current_frame = 0; current_frame < num_frames; ++current_frame) { float current_t = (float)current_frame / (float)num_frames; image_t *closure = closure_image_alloc(&invocation->mathfuncs, NULL, invocation->mathmap->main_filter->num_uservals, invocation->uservals, img_width, img_height); mathmap_frame_t *frame = invocation_new_frame(invocation, closure, current_frame, current_t); call_invocation_parallel_and_join(frame, closure, 0, 0, img_width, img_height, output, 1); invocation_free_frame(frame); #ifdef MOVIES if (generate_movie && !bench_no_output) { fprintf(stderr, _("writing frame %d\n"), current_frame); assert(quicktime_encode_video(output_movie, rows, 0) == 0); } #endif closure_image_free(closure); } if (!bench_no_output) { #ifdef MOVIES if (generate_movie) quicktime_close(output_movie); else #endif write_image(output_filename, img_width, img_height, output, invocation->output_bpp, img_width * invocation->output_bpp, IMAGE_FORMAT_PNG); } free(output); } } else { if (strcmp(generator, "blender") == 0) { if (!blender_generate_plug_in(script, output_filename)) return 1; } /* else if (strcmp(generator, "pixeltree") == 0) { if (!pixeltree_generate_plug_in(argv[optind], argv[optind + 1])) return 1; } */ else { fprintf(stderr, _("Unknown generator `%s'\n"), generator); return 1; } } return 0; }
void inpaint_image_wrapper(const char *fileIn,const char *fileOccIn, const char *fileOut, int patchSizeX, int patchSizeY, int nLevels, bool useFeatures, bool verboseMode) { // *************************** // // ***** READ INPUTS ********* // // ************************** // //read input image size_t nx,ny,nc; size_t nOccX,nOccY,nOccC; //read input image printf("Reading input image\n"); float *inputImage = read_image(fileIn,&nx,&ny,&nc); //read input occlusion printf("Reading input occlusion\n"); float *inputOcc = read_image(fileOccIn,&nOccX,&nOccY,&nOccC); // ****************************************** // // **** INITIALISE PATCHMATCH PARAMETERS **** // // ****************************************** // patchMatchParameterStruct *patchMatchParams = initialise_patch_match_parameters(patchSizeX, patchSizeY, nx, ny, verboseMode); if (check_patch_match_parameters(patchMatchParams) == -1) return; // ****************************************** // // **** INITIALISE INPAINTING PARAMETERS **** // // ****************************************** // float residualThreshold = 0.1; int maxIterations = 10; inpaintingParameterStruct *inpaintingParams = initialise_inpainting_parameters(nLevels, useFeatures, residualThreshold, maxIterations); // ******************************** // // ***** CREATE IMAGE STRUCTURES*** // // ******************************** // nTupleVolume *imgVolIn = new nTupleVolume(nc,nx,ny,patchSizeX,patchSizeY,IMAGE_INDEXING,inputImage); nTupleVolume *occVolIn; if (nOccC == 3) //if we need to convert the input occlusion { nTupleVolume *occVolTemp = new nTupleVolume(3,nx,ny,patchSizeX,patchSizeY,IMAGE_INDEXING,inputOcc); occVolIn = rgb_to_grey(occVolTemp); delete(occVolTemp); } else occVolIn = new nTupleVolume(1,nOccX,nOccY,patchSizeX,patchSizeY,IMAGE_INDEXING,inputOcc); occVolIn->binarise(); // ***** CALL MAIN ROUTINE **** // nTupleVolume * imgOut = inpaint_image(imgVolIn, occVolIn, patchMatchParams, inpaintingParams); //write output //write_image(imgOut,fileOut,255); write_image(imgOut,fileOut); delete(imgOut); }
Image::Image( string filepath ) // konstruktor obiektu obrazka z pliku { image = NULL; header = NULL; read_image(filepath); // wczytujê obrazek z pliku }
void nemo_main() { stream instr, outstr; int nx, ny, nz; int nstep,nstep1; int i,j,k, n, n1, i1, j1, m; int ix[2], iy[2]; imageptr iptr=NULL, optr; /* pointer to images */ real *vals, fraction; string mode = getparam("mode"); bool Qmedian = (*mode == 'm'); bool Qmean = (*mode == 'a'); nstep = getiparam("nstep"); if (nstep%2 != 1) error("step size %d needs to be odd",nstep); nstep1 = (nstep-1)/2; n = getiparam("n"); if (Qmedian) dprintf(1,"Median filter size %d\n",n); else if (Qmean) dprintf(1,"Mean filter size %d\n",n); else dprintf(1,"Subtraction filter size %d\n",n); if (n%2 != 1) error("filter size %d needs to be odd",n); n1 = (n-1)/2; vals = (real *) allocate (sizeof(real) * (n*n + 1)); instr = stropen(getparam("in"), "r"); read_image( instr, &iptr); nx = Nx(iptr); ny = Ny(iptr); nz = Nz(iptr); if (nz > 1) error("Cannot do 3D cubes properly; use 2D"); if (hasvalue("x") && hasvalue("y")) { get_range("x",ix); get_range("y",iy); } else { ix[0] = 0; ix[1] = nx-1; iy[0] = 0; iy[1] = ny-1; } dprintf(1,"Xrange: %d - %d Yrange: %d - %d\n",ix[0],ix[1],iy[0],iy[1]); outstr = stropen(getparam("out"), "w"); create_cube(&optr,nx,ny,nz); Dx(optr) = Dx(iptr); Dy(optr) = Dy(iptr); Dz(optr) = Dz(iptr); Xmin(optr) = Xmin(iptr); Ymin(optr) = Ymin(iptr); Zmin(optr) = Zmin(iptr); if (nstep > 1) { warning("Cheat mode nstep=%d",nstep); for (j=nstep1; j<ny-nstep1; j+=nstep) { for (i=nstep1; i<nx-nstep1; i+=nstep) { if (j<n1 || j >= ny-n1 || j < iy[0] || j > iy[1]) { CVO(i,j) = CVI(i,j); continue; } if (i<n1 || i >= nx-n1 || i < ix[0] || i > ix[1]) { CVO(i,j) = CVI(i,j); continue; } m = 0; for (j1=j-n1; j1<=j+n1; j1++) for (i1=i-n1; i1<=i+n1; i1++) vals[m++] = CVI(i1,j1); CVO(i,j) = median(m,vals,fraction); for (j1=j-nstep1; j1<=j+nstep1; j1++) for (i1=i-nstep1; i1<=i+nstep1; i1++) CVO(i1,j1) = CVO(i,j); } } } else { for (j=0; j<ny; j++) { for (i=0; i<nx; i++) { if (j<n1 || j >= ny-n1 || j < iy[0] || j > iy[1]) { CVO(i,j) = CVI(i,j); continue; } if (i<n1 || i >= nx-n1 || i < ix[0] || i > ix[1]) { CVO(i,j) = CVI(i,j); continue; } m = 0; for (j1=j-n1; j1<=j+n1; j1++) for (i1=i-n1; i1<=i+n1; i1++) vals[m++] = CVI(i1,j1); if (Qmedian) CVO(i,j) = median(m,vals,fraction); else if (Qmean) CVO(i,j) = mean(m,vals,fraction); else CVO(i,j) = subtract(m,vals,fraction); } } } write_image(outstr, optr); }
int main(int argc, char *argv[]) { struct pngquant_options options = { .floyd = 1.f, // floyd-steinberg dithering }; options.liq = liq_attr_create(); if (!options.liq) { fputs("SSE-capable CPU is required for this build.\n", stderr); return WRONG_ARCHITECTURE; } unsigned int error_count=0, skipped_count=0, file_count=0; pngquant_error latest_error=SUCCESS; const char *newext = NULL, *output_file_path = NULL; fix_obsolete_options(argc, argv); int opt; do { opt = getopt_long(argc, argv, "Vvqfhs:Q:o:", long_options, NULL); switch (opt) { case 'v': options.verbose = true; break; case 'q': options.verbose = false; break; case arg_floyd: options.floyd = optarg ? atof(optarg) : 1.0; if (options.floyd < 0 || options.floyd > 1.f) { fputs("--floyd argument must be in 0..1 range\n", stderr); return INVALID_ARGUMENT; } break; case arg_ordered: options.floyd = 0; break; case 'f': options.force = true; break; case arg_no_force: options.force = false; break; case arg_ext: newext = optarg; break; case 'o': if (output_file_path) { fputs("--output option can be used only once\n", stderr); return INVALID_ARGUMENT; } output_file_path = optarg; break; case arg_iebug: // opacities above 238 will be rounded up to 255, because IE6 truncates <255 to 0. liq_set_min_opacity(options.liq, 238); fputs(" warning: the workaround for IE6 is deprecated\n", stderr); break; case arg_transbug: liq_set_last_index_transparent(options.liq, true); break; case arg_skip_larger: options.skip_if_larger = true; break; case 's': { int speed = atoi(optarg); if (speed >= 10) { options.fast_compression = true; } if (speed == 11) { options.floyd = 0; speed = 10; } if (LIQ_OK != liq_set_speed(options.liq, speed)) { fputs("Speed should be between 1 (slow) and 11 (fast).\n", stderr); return INVALID_ARGUMENT; } } break; case 'Q': if (!parse_quality(optarg, options.liq, &options.min_quality_limit)) { fputs("Quality should be in format min-max where min and max are numbers in range 0-100.\n", stderr); return INVALID_ARGUMENT; } break; case arg_posterize: if (LIQ_OK != liq_set_min_posterization(options.liq, atoi(optarg))) { fputs("Posterization should be number of bits in range 0-4.\n", stderr); return INVALID_ARGUMENT; } break; case arg_map: { png24_image tmp = {}; if (SUCCESS != read_image(options.liq, optarg, false, &tmp, &options.fixed_palette_image, false, false)) { fprintf(stderr, " error: unable to load %s", optarg); return INVALID_ARGUMENT; } } break; case 'h': print_full_version(stdout); print_usage(stdout); return SUCCESS; case 'V': puts(PNGQUANT_VERSION); return SUCCESS; case -1: break; default: return INVALID_ARGUMENT; } } while (opt != -1); int argn = optind; if (argn >= argc) { if (argn > 1) { fputs("No input files specified.\n", stderr); } else { print_full_version(stderr); } print_usage(stderr); return MISSING_ARGUMENT; } if (options.verbose) { liq_set_log_callback(options.liq, log_callback, NULL); options.log_callback = log_callback; } char *colors_end; unsigned long colors = strtoul(argv[argn], &colors_end, 10); if (colors_end != argv[argn] && '\0' == colors_end[0]) { if (LIQ_OK != liq_set_max_colors(options.liq, colors)) { fputs("Number of colors must be between 2 and 256.\n", stderr); return INVALID_ARGUMENT; } argn++; } if (newext && output_file_path) { fputs("--ext and --output options can't be used at the same time\n", stderr); return INVALID_ARGUMENT; } // new filename extension depends on options used. Typically basename-fs8.png if (newext == NULL) { newext = options.floyd > 0 ? "-ie-fs8.png" : "-ie-or8.png"; if (!options.ie_mode) { newext += 3; /* skip "-ie" */ } } if (argn == argc || (argn == argc-1 && 0==strcmp(argv[argn],"-"))) { options.using_stdin = true; options.using_stdout = !output_file_path; argn = argc-1; } const int num_files = argc-argn; if (output_file_path && num_files != 1) { fputs("Only one input file is allowed when --output is used\n", stderr); return INVALID_ARGUMENT; } #ifdef _OPENMP // if there's a lot of files, coarse parallelism can be used if (num_files > 2*omp_get_max_threads()) { omp_set_nested(0); omp_set_dynamic(1); } else { omp_set_nested(1); } #endif #pragma omp parallel for \ schedule(static, 1) reduction(+:skipped_count) reduction(+:error_count) reduction(+:file_count) shared(latest_error) for(int i=0; i < num_files; i++) { struct pngquant_options opts = options; opts.liq = liq_attr_copy(options.liq); const char *filename = opts.using_stdin ? "stdin" : argv[argn+i]; #ifdef _OPENMP struct buffered_log buf = {}; if (opts.log_callback && omp_get_num_threads() > 1 && num_files > 1) { liq_set_log_callback(opts.liq, log_callback_buferred, &buf); liq_set_log_flush_callback(opts.liq, log_callback_buferred_flush, &buf); options.log_callback = log_callback_buferred; options.log_callback_user_info = &buf; } #endif pngquant_error retval = SUCCESS; const char *outname = output_file_path; char *outname_free = NULL; if (!options.using_stdout) { if (!outname) { outname = outname_free = add_filename_extension(filename, newext); } if (!options.force && file_exists(outname)) { fprintf(stderr, " error: '%s' exists; not overwriting\n", outname); retval = NOT_OVERWRITING_ERROR; } } if (SUCCESS == retval) { retval = pngquant_file(filename, outname, &opts); } free(outname_free); liq_attr_destroy(opts.liq); if (retval) { #pragma omp critical { latest_error = retval; } if (retval == TOO_LOW_QUALITY || retval == TOO_LARGE_FILE) { skipped_count++; } else { error_count++; } } ++file_count; } if (error_count) { verbose_printf(&options, "There were errors quantizing %d file%s out of a total of %d file%s.", error_count, (error_count == 1)? "" : "s", file_count, (file_count == 1)? "" : "s"); } if (skipped_count) { verbose_printf(&options, "Skipped %d file%s out of a total of %d file%s.", skipped_count, (skipped_count == 1)? "" : "s", file_count, (file_count == 1)? "" : "s"); } if (!skipped_count && !error_count) { verbose_printf(&options, "No errors detected while quantizing %d image%s.", file_count, (file_count == 1)? "" : "s"); } liq_image_destroy(options.fixed_palette_image); liq_attr_destroy(options.liq); return latest_error; } pngquant_error pngquant_file(const char *filename, const char *outname, struct pngquant_options *options) { pngquant_error retval = SUCCESS; verbose_printf(options, "%s:", filename); liq_image *input_image = NULL; png24_image input_image_rwpng = {}; bool keep_input_pixels = options->skip_if_larger || (options->using_stdout && options->min_quality_limit); // original may need to be output to stdout if (SUCCESS == retval) { retval = read_image(options->liq, filename, options->using_stdin, &input_image_rwpng, &input_image, keep_input_pixels, options->verbose); } int quality_percent = 90; // quality on 0-100 scale, updated upon successful remap png8_image output_image = {}; if (SUCCESS == retval) { verbose_printf(options, " read %luKB file", (input_image_rwpng.file_size+1023UL)/1024UL); #if USE_LCMS if (input_image_rwpng.lcms_status == ICCP) { verbose_printf(options, " used embedded ICC profile to transform image to sRGB colorspace"); } else if (input_image_rwpng.lcms_status == GAMA_CHRM) { verbose_printf(options, " used gAMA and cHRM chunks to transform image to sRGB colorspace"); } else if (input_image_rwpng.lcms_status == ICCP_WARN_GRAY) { verbose_printf(options, " warning: ignored ICC profile in GRAY colorspace"); } #endif if (input_image_rwpng.gamma != 0.45455) { verbose_printf(options, " corrected image from gamma %2.1f to sRGB gamma", 1.0/input_image_rwpng.gamma); } // when using image as source of a fixed palette the palette is extracted using regular quantization liq_result *remap = liq_quantize_image(options->liq, options->fixed_palette_image ? options->fixed_palette_image : input_image); if (remap) { liq_set_output_gamma(remap, 0.45455); // fixed gamma ~2.2 for the web. PNG can't store exact 1/2.2 liq_set_dithering_level(remap, options->floyd); retval = prepare_output_image(remap, input_image, &output_image); if (SUCCESS == retval) { if (LIQ_OK != liq_write_remapped_image_rows(remap, input_image, output_image.row_pointers)) { retval = OUT_OF_MEMORY_ERROR; } set_palette(remap, &output_image); double palette_error = liq_get_quantization_error(remap); if (palette_error >= 0) { quality_percent = liq_get_quantization_quality(remap); verbose_printf(options, " mapped image to new colors...MSE=%.3f (Q=%d)", palette_error, quality_percent); } } liq_result_destroy(remap); } else { retval = TOO_LOW_QUALITY; } } if (SUCCESS == retval) { if (options->skip_if_larger) { // this is very rough approximation, but generally avoid losing more quality than is gained in file size. // Quality is squared, because even greater savings are needed to justify big quality loss. double quality = quality_percent/100.0; output_image.maximum_file_size = (input_image_rwpng.file_size-1) * quality*quality; } output_image.fast_compression = options->fast_compression; output_image.chunks = input_image_rwpng.chunks; input_image_rwpng.chunks = NULL; retval = write_image(&output_image, NULL, outname, options); if (TOO_LARGE_FILE == retval) { verbose_printf(options, " file exceeded expected size of %luKB", (unsigned long)output_image.maximum_file_size/1024UL); } } if (options->using_stdout && keep_input_pixels && (TOO_LARGE_FILE == retval || TOO_LOW_QUALITY == retval)) { // when outputting to stdout it'd be nasty to create 0-byte file // so if quality is too low, output 24-bit original pngquant_error write_retval = write_image(NULL, &input_image_rwpng, outname, options); if (write_retval) { retval = write_retval; } } liq_image_destroy(input_image); rwpng_free_image24(&input_image_rwpng); rwpng_free_image8(&output_image); return retval; }
int main( int argc, char **argv) { std::string inpf, trif, outf, backf; adobe::dictionary_t params; bool use_lab = false; try { po::options_description desc("Allowed options"); po::variables_map vm; po::positional_options_description p; p.add( "input" , 1); p.add( "trimap", 1); desc.add_options() ("help", "produce help message") // files ("input", po::value<std::string>(), "input file") ("trimap",po::value<std::string>(), "trimap file") ("output,o", po::value<std::string>(), "output file") ("background,bg", po::value<std::string>(), "clean background") ("save_bg", "save estimated background") // colors ("rgb", "use rgb colorspace") // sampling ("kwin", po::value<int>()->default_value( 8), "known window radius") ("uwin", po::value<int>()->default_value( 8), "unknown window radius") ("mins", po::value<int>()->default_value( 16), "min samples") // clusters ("clusters", po::value<int>()->default_value( 5), "max number of clusters") ("ctheresh", po::value<double>()->default_value( 0.001), "cluster thereshold") // optimize ("cvar", po::value<double>()->default_value( 0.04), "camera variance") // gui ("window,w", "show results in a window") ; // end po::store( po::command_line_parser( argc, argv).options( desc).positional( p).run(), vm); po::notify( vm); if( vm.count( "help") || !vm.count("input") || !vm.count("trimap")) usage(); if( (!vm.count("output")) && (!vm.count("window"))) usage(); inpf = vm["input"].as<std::string>(); trif = vm["trimap"].as<std::string>(); if( vm.count("output")) outf = vm["output"].as<std::string>(); use_lab = !vm.count("rgb"); params[adobe::name_t("use_lab")] = adobe::any_regular_t( use_lab); // load images image.reference( read_image( inpf.c_str())); trimap.reference( read_trimap( trif.c_str())); if( (trimap.rows() != image.rows()) || (trimap.cols() != image.cols())) { std::cout << "Image & trimap dimensions don't match\n"; exit( boost::exit_failure); } if( use_lab) convert2lab( image); if( vm.count( "background")) { backf = vm["background"].as<std::string>(); params[adobe::name_t("use_back")] = adobe::any_regular_t( true); bg.reference( read_image( backf.c_str())); if( use_lab) convert2lab( bg); } else { bg.resize( image.rows(), image.cols()); params[adobe::name_t("use_back")] = adobe::any_regular_t( false); } // sampling params[ adobe::name_t( "kwin_size")] = adobe::any_regular_t( vm["kwin"].as<int>()); params[ adobe::name_t( "uwin_size")] = adobe::any_regular_t( vm["uwin"].as<int>()); params[ adobe::name_t( "min_samples")] = adobe::any_regular_t( vm["mins"].as<int>()); // cluster params[ adobe::name_t( "maxk")] = adobe::any_regular_t( vm["clusters"].as<int>()); params[ adobe::name_t( "ctheresh")] = adobe::any_regular_t( vm["ctheresh"].as<double>()); // optimize params[ adobe::name_t( "cvar")] = adobe::any_regular_t( vm["cvar"].as<double>()); fg.resize( image.rows(), image.cols()); alpha.resize( image.rows(), image.cols()); bmatte bm( image, trimap, fg, bg, alpha, params); bm(); if( use_lab) { convert2rgb( image); convert2rgb( fg); convert2rgb( bg); } if( vm.count( "output")) { save_image( outf.c_str(), fg, &alpha); if( vm.count( "save_bg")) { std::string bgf = "bg_" + outf; save_image( bgf.c_str(), bg); } } if( vm.count( "window")) { comp.resize( image.rows(), image.cols()); for( int j=0;j<image.rows();++j) { for( int i=0;i<image.cols();++i) { float t = alpha( j, i); comp( j, i) = (fg( j, i) * t) + ( Imath::Color3f( .5f, .5f, .5f) * (1.0f - t)); } } glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); glutInitWindowPosition( 50, 50); glutInitWindowSize( image.cols(), image.rows()); glutCreateWindow( "BMatte"); glutKeyboardFunc( key); glutMouseFunc( mouse); glutDisplayFunc( display); gl_init(); glutMainLoop(); } } catch( std::exception& e) { std::cerr << "error: " << e.what() << "\n"; return boost::exit_failure; } catch( ...) { std::cerr << "Exception of unknown type!\n";} return boost::exit_success; }