gint32 execute_plugin(GimpDrawable* d, const char *nome, param_type *p) { // gint i; guchar *img, *org; gint x,y,x2,y2,w,h; // guchar *work; GimpPixelRgn region, rgn_org; gint bpp = d->bpp; gimp_drawable_mask_bounds(d->drawable_id, &x, &y, &x2, &y2); w = x2 - x; h = y2 - y; img = malloc(w * h * bpp); org = malloc(w * h * bpp); // work = malloc(d.width * d.height * bpp); gimp_pixel_rgn_init(®ion, d, x, y, w, h, TRUE, TRUE); //este é buffer para gravar a imagem modificada. gimp_pixel_rgn_init(&rgn_org, d, x, y, w, h, FALSE, FALSE); // Esta é a imagem em si gimp_pixel_rgn_get_rect(®ion, img, x, y, w, h); gimp_pixel_rgn_get_rect(&rgn_org, org, x, y, w, h); switch (*nome) { case 'S': super_grow(p, org, img, w, h, bpp); break; case 'G': memcpy(img, org, w * h * bpp); grow(p, org, img, w, h, bpp); break; case 'A': find_iso(p, org, img, w, h, bpp); break; default: make_height_field(p, org, img, w, h, bpp); break; } gimp_pixel_rgn_set_rect(®ion, img, x, y, w, h); /* finish the process */ gimp_drawable_flush (d); gimp_drawable_merge_shadow (d->drawable_id, TRUE); gimp_drawable_update (d->drawable_id, x, y, w, h); gimp_displays_flush(); gimp_drawable_detach(d); free(img); free(org); return GIMP_PDB_SUCCESS; }
static void preview_update_preview (GimpPreview *preview, GimpDrawable *drawable) { gint x1, y1; gint width, height; gint bpp; guchar *buffer; GimpPixelRgn src_rgn; GimpPixelRgn preview_rgn; gint32 image_id, src_image_id; gint32 preview_id; GimpDrawable *preview_drawable; bpp = gimp_drawable_bpp (drawable->drawable_id); gimp_preview_get_position (preview, &x1, &y1); gimp_preview_get_size (preview, &width, &height); buffer = g_new (guchar, width * height * bpp); gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, width, height, FALSE, FALSE); gimp_pixel_rgn_get_rect (&src_rgn, buffer, x1, y1, width, height); /* set up gimp drawable for rendering preview into */ src_image_id = gimp_drawable_get_image (drawable->drawable_id); image_id = gimp_image_new (width, height, gimp_image_base_type (src_image_id)); preview_id = gimp_layer_new (image_id, "preview", width, height, gimp_drawable_type (drawable->drawable_id), 100, GIMP_NORMAL_MODE); preview_drawable = gimp_drawable_get (preview_id); gimp_image_add_layer (image_id, preview_id, 0); gimp_layer_set_offsets (preview_id, 0, 0); gimp_pixel_rgn_init (&preview_rgn, preview_drawable, 0, 0, width, height, TRUE, TRUE); gimp_pixel_rgn_set_rect (&preview_rgn, buffer, 0, 0, width, height); gimp_drawable_flush (preview_drawable); gimp_drawable_merge_shadow (preview_id, TRUE); gimp_drawable_update (preview_id, 0, 0, width, height); dog (image_id, preview_drawable, dogvals.inner, dogvals.outer, FALSE); gimp_pixel_rgn_get_rect (&preview_rgn, buffer, 0, 0, width, height); gimp_preview_draw_buffer (preview, buffer, width * bpp); gimp_image_delete (image_id); g_free (buffer); }
static void preview_update (GtkWidget *widget) { GimpPixelRgn src_rgn; /* Source image region */ guchar *dst; /* Output image */ GimpPreview *preview; /* The preview widget */ guchar *src; /* Source pixel rows */ gint img_bpp; gint x1,y1; gint width, height; preview = GIMP_PREVIEW (widget); img_bpp = gimp_drawable_bpp (drawable->drawable_id); width = preview->width; height = preview->height; gimp_preview_get_position (preview, &x1, &y1); gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, width, height, FALSE, FALSE); dst = g_new (guchar, width * height * img_bpp); src = g_new (guchar, width * height * img_bpp); gimp_pixel_rgn_get_rect (&src_rgn, src, x1, y1, width, height); despeckle_median (src, dst, width, height, img_bpp, despeckle_radius, TRUE); gimp_preview_draw_buffer (preview, dst, width * img_bpp); g_free (src); g_free (dst); }
static void waves (GimpDrawable *drawable) { GimpPixelRgn srcPr, dstPr; guchar *src, *dst; guint width, height, bpp, has_alpha; width = drawable->width; height = drawable->height; bpp = drawable->bpp; has_alpha = gimp_drawable_has_alpha (drawable->drawable_id); src = g_new (guchar, width * height * bpp); dst = g_new (guchar, width * height * bpp); gimp_pixel_rgn_init (&srcPr, drawable, 0, 0, width, height, FALSE, FALSE); gimp_pixel_rgn_init (&dstPr, drawable, 0, 0, width, height, TRUE, TRUE); gimp_pixel_rgn_get_rect (&srcPr, src, 0, 0, width, height); wave (src, dst, width, height, bpp, has_alpha, width / 2.0, height / 2.0, wvals.amplitude, wvals.wavelength, wvals.phase, wvals.type == MODE_SMEAR, wvals.reflective, TRUE); gimp_pixel_rgn_set_rect (&dstPr, dst, 0, 0, width, height); g_free (src); g_free (dst); gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); gimp_drawable_update (drawable->drawable_id, 0, 0, width, height); gimp_displays_flush (); }
/* This function operates on PixelArea, whose width and height are multiply of pixel width, and less than the tile size (to enhance its speed). If any coordinates of mask boundary is not multiply of pixel width (e.g. x1 % pixelwidth != 0), operates on the region whose width or height is the remainder. */ static void pixelize_small (GimpDrawable *drawable, gint pixelwidth, gint pixelheight, gint tile_width, gint tile_height) { GimpPixelRgn src_rgn, dest_rgn; gint bpp, has_alpha; gint x1, y1, x2, y2; gint progress, max_progress; gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, x2-x1, y2-y1, FALSE, FALSE); gimp_pixel_rgn_init (&dest_rgn, drawable, x1, y1, x2-x1, y2-y1, TRUE, TRUE); /* Initialize progress */ progress = 0; max_progress = (x2 - x1) * (y2 - y1); bpp = drawable->bpp; has_alpha = gimp_drawable_has_alpha (drawable->drawable_id); area.width = (tile_width / pixelwidth) * pixelwidth; area.height = (tile_height / pixelheight) * pixelheight; area.data= g_new (guchar, (glong) bpp * area.width * area.height); for (area.y = y1; area.y < y2; area.y += area.height - (area.y % area.height)) { area.h = area.height - (area.y % area.height); area.h = MIN (area.h, y2 - area.y); for (area.x = x1; area.x < x2; area.x += area.width - (area.x % area.width)) { area.w = area.width - (area.x % area.width); area.w = MIN(area.w, x2 - area.x); gimp_pixel_rgn_get_rect (&src_rgn, area.data, area.x, area.y, area.w, area.h); pixelize_sub (pixelwidth, pixelheight, bpp, has_alpha); gimp_pixel_rgn_set_rect (&dest_rgn, area.data, area.x, area.y, area.w, area.h); /* Update progress */ progress += area.w * area.h; gimp_progress_update ((double) progress / (double) max_progress); } } g_free(area.data); /* update the pixelized region */ gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); gimp_drawable_update (drawable->drawable_id, x1, y1, (x2 - x1), (y2 - y1)); }
/* Private functions */ static void draw_preview_area_update(GtkWidget *preview, GimpDrawable *drawable) { if(is_3D_preview_active()) { /** Adding all references to preview for second release. */ if ((local_vals.image_ID != 0) && (drawable != NULL)) { update_preview = 0; if (drawable->bpp == 3) { GimpPixelRgn amap_rgn; gint rowbytes = PREVIEW_SIZE * 3; gint nbytes = drawable->width * drawable->height * 3; guchar *tmp = g_new(guchar, nbytes); guchar dst[PREVIEW_RGB_SIZE]; gimp_pixel_rgn_init(&amap_rgn, drawable, 0, 0, drawable->width, drawable->height, 0, 0); gimp_pixel_rgn_get_rect(&amap_rgn, tmp, 0, 0, drawable->width, drawable->height); scale_pixels(dst, PREVIEW_SIZE, PREVIEW_SIZE, tmp, drawable->width, drawable->height, drawable->bpp); gimp_preview_area_draw(GIMP_PREVIEW_AREA(preview), 0, 0, PREVIEW_SIZE, PREVIEW_SIZE, GIMP_RGB_IMAGE, dst, rowbytes); gtk_widget_queue_draw (preview); g_free (tmp); _active = 'w'; } else if (drawable->bpp == 4) { GimpPixelRgn amap_rgn; gint rowbytes = PREVIEW_SIZE * 4; gint nbytes = drawable->width * drawable->height * 4; guchar *tmp = g_new(guchar, nbytes); guchar dst[PREVIEW_RGBA_SIZE]; gimp_pixel_rgn_init(&amap_rgn, drawable, 0, 0, drawable->width, drawable->height, 0, 0); gimp_pixel_rgn_get_rect(&amap_rgn, tmp, 0, 0, drawable->width, drawable->height); scale_pixels(dst, PREVIEW_SIZE, PREVIEW_SIZE, tmp, drawable->width, drawable->height, drawable->bpp); gimp_preview_area_draw(GIMP_PREVIEW_AREA(preview), 0, 0, PREVIEW_SIZE, PREVIEW_SIZE, GIMP_RGBA_IMAGE, dst, rowbytes); gtk_widget_queue_draw (preview); g_free (tmp); _active = 'w'; } } } }
void fft_prepare(PluginData *pd) { gint w = pd->image_width, h = pd->image_height; gint channel_count = pd->channel_count; int x, y; float **image; guchar *img_pixels; float norm; image = pd->image = (float**) malloc(sizeof(float*) * channel_count); pd->image_freq = (fftwf_complex**) malloc(sizeof(fftwf_complex*) * channel_count); img_pixels = pd->img_pixels = g_new (guchar, w * h * channel_count); //allocate an array for each channel for (int channel = 0; channel < channel_count; channel ++){ image[channel] = (float*) fftwf_malloc(sizeof(float) * w * h); pd->image_freq[channel] = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * (w/2+1) * h); } // printf("Image data occupies %lu MB.\n", (sizeof(float) * w * h * channel_count) >> 20); // printf("Frequency data occupies %lu MB.\n", (sizeof(fftwf_complex) * (w/2+1) * h * channel_count) >> 20); // forward plan fftwf_plan plan = fftwf_plan_dft_r2c_2d(pd->image_height, pd->image_width, *image, *pd->image_freq, FFTW_ESTIMATE); // inverse plan (to be reused) pd->plan = fftwf_plan_dft_c2r_2d(pd->image_height, pd->image_width, *pd->image_freq, *image, FFTW_ESTIMATE); // set image region to reading mode gimp_pixel_rgn_init (&pd->region, pd->drawable, 0, 0, w, h, FALSE, FALSE); gimp_pixel_rgn_get_rect(&pd->region, img_pixels, 0, 0, w, h); // execute forward FFT once int pw = w/2+1; // physical width float diagonal = sqrt(h*h + w*w)/2.0; norm = 1.0/(w*h); for(int channel=0; channel<channel_count; channel++) { // convert one color channel to float[] for(int i=0; i < w*h; i ++) { image[channel][i] = (float) img_pixels[(i)*channel_count + channel] * norm; } // transform the channel fftwf_execute_dft_r2c(plan, image[channel], pd->image_freq[channel]); for(int i=0; i < w*h; i ++) { image[channel][i] = (float) img_pixels[(i)*channel_count + channel] * norm; } // copy the channel again, for preview for(int i=0; i < w*h; i ++) { image[channel][i] = (float) img_pixels[(i)*channel_count + channel]; } } fftwf_destroy_plan(plan); }
static void color_to_alpha_preview (GimpPreview *preview, GimpDrawable *drawable) { GimpPixelRgn src_rgn; gint x, y; gint width, height; gint bpp; gint i; guchar *src, *dest; bpp = drawable->bpp; gimp_preview_get_position (preview, &x, &y); gimp_preview_get_size (preview, &width, &height); dest = g_new (guchar, width * height * 4); src = g_new (guchar, width * height * bpp); gimp_pixel_rgn_init (&src_rgn, drawable, x, y, width, height, FALSE, FALSE); gimp_pixel_rgn_get_rect (&src_rgn, src, x, y, width, height); for (i = 0; i < width * height; i++) to_alpha_func (src + i * bpp, dest + i * 4, bpp, NULL); g_free (src); /* Our code assumes that the drawable has an alpha channel (and adds * one later if the effect is actually performed). For that reason * we have to take care when drawing the preview. */ if (bpp == 4) { gimp_preview_draw_buffer (preview, dest, width * 4); } else { /* This is not correct because we ignore the selection, but it * is the best we can easily do. */ gimp_preview_area_draw (GIMP_PREVIEW_AREA (preview->area), 0, 0, width, height, GIMP_RGBA_IMAGE, dest, width * 4); } g_free (dest); }
static void despeckle (void) { GimpPixelRgn src_rgn; /* Source image region */ GimpPixelRgn dst_rgn; guchar *src; guchar *dst; gint img_bpp; gint x, y; gint width, height; img_bpp = gimp_drawable_bpp (drawable->drawable_id); if (! gimp_drawable_mask_intersect (drawable->drawable_id, &x, &y, &width, &height)) return; gimp_pixel_rgn_init (&src_rgn, drawable, x, y, width, height, FALSE, FALSE); gimp_pixel_rgn_init (&dst_rgn, drawable, x, y, width, height, TRUE, TRUE); src = g_new (guchar, width * height * img_bpp); dst = g_new (guchar, width * height * img_bpp); gimp_pixel_rgn_get_rect (&src_rgn, src, x, y, width, height); despeckle_median (src, dst, width, height, img_bpp, despeckle_radius, FALSE); gimp_pixel_rgn_set_rect (&dst_rgn, dst, x, y, width, height); gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); gimp_drawable_update (drawable->drawable_id, x, y, width, height); g_free (dst); g_free (src); }
gint xjpg_save_drawable (const char *filename, gint32 image_ID, gint32 drawable_ID, gint save_mode, t_JpegSaveVals *jsvals) { GimpPixelRgn pixel_rgn; GimpDrawable *drawable; GimpImageType drawable_type; struct jpeg_compress_struct cinfo; struct my_error_mgr jerr; FILE * volatile outfile; guchar *temp, *t; guchar *data; guchar *src, *s; int has_alpha; int rowstride, yend; int i, j; int alpha_offset; guchar alpha_byte; guchar volatile l_alpha_sum; alpha_offset = 0; has_alpha = 0; src = NULL; temp = NULL; data = NULL; l_alpha_sum = 0xff; drawable = gimp_drawable_get (drawable_ID); drawable_type = gimp_drawable_type (drawable_ID); switch (drawable_type) { case GIMP_RGB_IMAGE: case GIMP_GRAY_IMAGE: if(save_mode == JSVM_ALPHA) return FALSE; /* there is no alpha to save */ break; case GIMP_RGBA_IMAGE: case GIMP_GRAYA_IMAGE: break; case GIMP_INDEXED_IMAGE: /*g_message ("jpeg: cannot operate on indexed color images");*/ return FALSE; break; default: /*g_message ("jpeg: cannot operate on unknown image types");*/ return FALSE; break; } gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, FALSE, FALSE); /* Step 1: allocate and initialize JPEG compression object */ /* We have to set up the error handler first, in case the initialization * step fails. (Unlikely, but it could happen if you are out of memory.) * This routine fills in the contents of struct jerr, and returns jerr's * address which we place into the link field in cinfo. */ cinfo.err = jpeg_std_error (&jerr.pub); jerr.pub.error_exit = my_error_exit; outfile = NULL; /* Establish the setjmp return context for my_error_exit to use. */ if (setjmp (jerr.setjmp_buffer)) { /* If we get here, the JPEG code has signaled an error. * We need to clean up the JPEG object, close the input file, and return. */ jpeg_destroy_compress (&cinfo); if (outfile) fclose (outfile); if (drawable) gimp_drawable_detach (drawable); return FALSE; } /* Now we can initialize the JPEG compression object. */ jpeg_create_compress (&cinfo); /* Step 2: specify data destination (eg, a file) */ /* Note: steps 2 and 3 can be done in either order. */ /* Here we use the library-supplied code to send compressed data to a * stdio stream. You can also write your own code to do something else. * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that * requires it in order to write binary files. */ if ((outfile = g_fopen (filename, "wb")) == NULL) { g_message ("can't open %s\n", filename); return FALSE; } jpeg_stdio_dest (&cinfo, outfile); /* Get the input image and a pointer to its data. */ switch (drawable_type) { case GIMP_RGB_IMAGE: case GIMP_GRAY_IMAGE: /* # of color components per pixel */ cinfo.input_components = drawable->bpp; has_alpha = 0; alpha_offset = 0; break; case GIMP_RGBA_IMAGE: case GIMP_GRAYA_IMAGE: if(save_mode == JSVM_ALPHA) { cinfo.input_components = 1; } else { /* # of color components per pixel (minus the GIMP alpha channel) */ cinfo.input_components = drawable->bpp - 1; } alpha_offset = drawable->bpp -1; has_alpha = 1; break; default: return FALSE; break; } /* Step 3: set parameters for compression */ /* First we supply a description of the input image. * Four fields of the cinfo struct must be filled in: */ /* image width and height, in pixels */ cinfo.image_width = drawable->width; cinfo.image_height = drawable->height; /* colorspace of input image */ cinfo.in_color_space = ( (save_mode != JSVM_ALPHA) && (drawable_type == GIMP_RGB_IMAGE || drawable_type == GIMP_RGBA_IMAGE)) ? JCS_RGB : JCS_GRAYSCALE; /* Now use the library's routine to set default compression parameters. * (You must set at least cinfo.in_color_space before calling this, * since the defaults depend on the source color space.) */ jpeg_set_defaults (&cinfo); /* Now you can set any non-default parameters you wish to. * Here we just illustrate the use of quality (quantization table) scaling: */ jpeg_set_quality (&cinfo, (int) (jsvals->quality * 100), TRUE /* limit to baseline-JPEG values */); cinfo.smoothing_factor = (int) (jsvals->smoothing * 100); cinfo.optimize_coding = jsvals->optimize; /* Step 4: Start compressor */ /* TRUE ensures that we will write a complete interchange-JPEG file. * Pass TRUE unless you are very sure of what you're doing. */ jpeg_start_compress (&cinfo, TRUE); /* Step 5: while (scan lines remain to be written) */ /* jpeg_write_scanlines(...); */ /* Here we use the library's state variable cinfo.next_scanline as the * loop counter, so that we don't have to keep track ourselves. * To keep things simple, we pass one scanline per call; you can pass * more if you wish, though. */ /* JSAMPLEs per row in image_buffer */ rowstride = drawable->bpp * drawable->width; temp = (guchar *) g_malloc (cinfo.image_width * cinfo.input_components); data = (guchar *) g_malloc (rowstride * gimp_tile_height ()); src = data; while (cinfo.next_scanline < cinfo.image_height) { if ((cinfo.next_scanline % gimp_tile_height ()) == 0) { yend = cinfo.next_scanline + gimp_tile_height (); yend = MIN (yend, cinfo.image_height); gimp_pixel_rgn_get_rect (&pixel_rgn, data, 0, cinfo.next_scanline, cinfo.image_width, (yend - cinfo.next_scanline)); src = data; } t = temp; s = src; i = cinfo.image_width; switch(save_mode) { case JSVM_DRAWABLE: if(jsvals->clr_transparent) { /* save drawable (clear pixels where alpha is full transparent) */ while (i--) { alpha_byte = s[cinfo.input_components]; for (j = 0; j < cinfo.input_components; j++) { if(alpha_byte != 0) { *t++ = *s++; } else { *t++ = 0; s++; } } if (has_alpha) /* ignore alpha channel */ { s++; } } } else { /* save the drawable as it is (ignore alpha channel) */ while (i--) { for (j = 0; j < cinfo.input_components; j++) { *t++ = *s++; } if (has_alpha) /* ignore alpha channel */ { s++; } } } break; case JSVM_ALPHA: /* save the drawable's alpha cahnnel */ while (i--) { s += alpha_offset; l_alpha_sum &= (*s); /* check all alpha bytes for full opacity */ *t++ = *s++; } break; } src += rowstride; jpeg_write_scanlines (&cinfo, (JSAMPARRAY) &temp, 1); if ((cinfo.next_scanline % 5) == 0) gimp_progress_update ((double) cinfo.next_scanline / (double) cinfo.image_height); } gimp_progress_update (1.0); /* Step 6: Finish compression */ jpeg_finish_compress (&cinfo); /* After finish_compress, we can close the output file. */ fclose (outfile); if((save_mode == JSVM_ALPHA) && (l_alpha_sum == 0xff)) { /* all bytes in the alpha channel are set to 0xff * == full opaque image. We can remove the file * to save diskspace */ g_remove(filename); } /* Step 7: release JPEG compression object */ /* This is an important step since it will release a good deal of memory. */ jpeg_destroy_compress (&cinfo); /* free the temporary buffer */ g_free (temp); g_free (data); gimp_drawable_detach (drawable); return TRUE; } /* end xjpg_save_drawable */
gint xjpg_load_layer_alpha (const char *filename, gint32 image_id, gint32 layer_id) { GimpPixelRgn l_pixel_rgn; GimpDrawable *l_drawable; struct jpeg_decompress_struct cinfo; struct my_error_mgr jerr; FILE *infile; guchar *l_buf; guchar *l_dstbuf; guchar **l_rowbuf; int l_tile_height; int l_scanlines; int l_idx, l_start, l_end; int l_alpha_offset; guchar *l_buf_ptr; guchar *l_dstbuf_ptr; /* We set up the normal JPEG error routines. */ cinfo.err = jpeg_std_error (&jerr.pub); jerr.pub.error_exit = my_error_exit; /* add alpha channel */ gimp_layer_add_alpha (layer_id); if ((infile = g_fopen (filename, "rb")) == NULL) { /* No alpha found, thats OK, use full opaque alpha channel * (there is no need not store alpha channels on full opaque channels) * (fixme: if filename exists but is not readable * we should return -1 to indicate an error */ return 0; /* OK */ } /* Establish the setjmp return context for my_error_exit to use. */ if (setjmp (jerr.setjmp_buffer)) { /* If we get here, the JPEG code has signaled an error. * We need to clean up the JPEG object, close the input file, and return. */ jpeg_destroy_decompress (&cinfo); if (infile) fclose (infile); g_printerr ("XJT: JPEG alpha load error\n"); return -1; } /* Now we can initialize the JPEG decompression object. */ jpeg_create_decompress (&cinfo); /* Step 2: specify data source (eg, a file) */ jpeg_stdio_src (&cinfo, infile); /* Step 3: read file parameters with jpeg_read_header() */ (void) jpeg_read_header (&cinfo, TRUE); /* We can ignore the return value from jpeg_read_header since * (a) suspension is not possible with the stdio data source, and * (b) we passed TRUE to reject a tables-only JPEG file as an error. * See libjpeg.doc for more info. */ /* Step 4: set parameters for decompression */ /* In this example, we don't need to change any of the defaults set by * jpeg_read_header(), so we do nothing here. */ /* Step 5: Start decompressor */ jpeg_start_decompress (&cinfo); /* We may need to do some setup of our own at this point before reading * the data. After jpeg_start_decompress() we have the correct scaled * output image dimensions available, as well as the output colormap * if we asked for color quantization. * In this example, we need to make an output work buffer of the right size. */ /* temporary buffer (for read in jpeg lines) */ l_tile_height = gimp_tile_height (); l_buf = g_new (guchar, l_tile_height * cinfo.output_width * cinfo.output_components); l_rowbuf = g_new (guchar*, l_tile_height); for (l_idx = 0; l_idx < l_tile_height; l_idx++) { l_rowbuf[l_idx] = l_buf + cinfo.output_width * cinfo.output_components * l_idx; } l_drawable = gimp_drawable_get (layer_id); if(l_drawable == NULL) { g_printerr ("XJT: gimp_drawable_get failed on layer id %d\n", (int)layer_id); fclose(infile); return -1; } /* Check if jpeg file can be used as alpha channel */ if((cinfo.output_components != 1) || (cinfo.output_width != l_drawable->width) || (cinfo.output_height != l_drawable->height)) { g_printerr ("XJT: cant load %s as alpha channel\n", filename); fclose (infile); return -1; } /* buffer to read in the layer and merge with the alpha from jpeg file */ l_dstbuf = g_new (guchar, l_tile_height * l_drawable->width * l_drawable->bpp); gimp_pixel_rgn_init (&l_pixel_rgn, l_drawable, 0, 0, l_drawable->width, l_drawable->height, TRUE, FALSE); l_alpha_offset = l_drawable->bpp -1; /* Step 6: while (scan lines remain to be read) */ /* jpeg_read_scanlines(...); */ /* Here we use the library's state variable cinfo.output_scanline as the * loop counter, so that we don't have to keep track ourselves. */ while (cinfo.output_scanline < cinfo.output_height) { l_start = cinfo.output_scanline; l_end = cinfo.output_scanline + l_tile_height; l_end = MIN (l_end, cinfo.output_height); l_scanlines = l_end - l_start; for (l_idx = 0; l_idx < l_scanlines; l_idx++) { jpeg_read_scanlines (&cinfo, (JSAMPARRAY) &l_rowbuf[l_idx], 1); } gimp_pixel_rgn_get_rect (&l_pixel_rgn, l_dstbuf, 0, l_start, l_drawable->width, l_scanlines); /* copy the loaded jpeg data (from buf) to the layers alpha channel data */ l_idx = l_tile_height * l_drawable->width; l_buf_ptr = l_buf; l_dstbuf_ptr = l_dstbuf; while(l_idx--) { l_dstbuf_ptr += l_alpha_offset; *l_dstbuf_ptr++ = *l_buf_ptr++; } gimp_pixel_rgn_set_rect (&l_pixel_rgn, l_dstbuf, 0, l_start, l_drawable->width, l_scanlines); gimp_progress_update ((double) cinfo.output_scanline / (double) cinfo.output_height); } gimp_progress_update (1.0); /* Step 7: Finish decompression */ jpeg_finish_decompress (&cinfo); /* We can ignore the return value since suspension is not possible * with the stdio data source. */ /* Step 8: Release JPEG decompression object */ /* This is an important step since it will release a good deal of memory. */ jpeg_destroy_decompress (&cinfo); /* free up the temporary buffers */ g_free (l_rowbuf); g_free (l_buf); g_free (l_dstbuf); /* After finish_decompress, we can close the input file. * Here we postpone it until after no more JPEG errors are possible, * so as to simplify the setjmp error logic above. (Actually, I don't * think that jpeg_destroy can do an error exit, but why assume anything...) */ fclose (infile); /* At this point you may want to check to see whether any corrupt-data * warnings occurred (test whether jerr.num_warnings is nonzero). */ return (0); /* OK */ } /* xjpg_load_layer_alpha */
static void c2g_region (GimpPixelRgn *srcPR, GimpPixelRgn *destPR, gint bytes, /* Bytes per pixel */ gdouble radius, gdouble amount_p, gdouble gamma_p, gint x1, /* Corners of subregion */ gint x2, gint y1, gint y2, gboolean show_progress) { guchar *src; guchar *dest; guchar *bigsrc; guchar *bigdest; guchar *tmpdest; gint width = x2 - x1; gint height = y2 - y1; gdouble *cmatrix = NULL; gint cmatrix_length; gdouble *ctable; gint row, col, idx; gint w = c2g_params.radius+10; gdouble amount = c2g_params.amount; gdouble gamma = c2g_params.gamma; if (show_progress) gimp_progress_init (_("Blurring...")); iir_init(c2g_params.radius); /* allocate buffers */ src = g_new (guchar, MAX (width, height) * bytes); dest = g_new (guchar, MAX (width, height) * bytes); iir.p = g_new(gdouble, MAX (width, height)+2*w); bigsrc = g_new(guchar, width * height * bytes); bigdest = g_new(guchar, width * height * bytes); tmpdest = g_new(guchar, width * height * bytes); if (show_progress) gimp_progress_init (_("Colour converting...")); // 1. Calculate Nayatani Grey and Blur in LAB gimp_pixel_rgn_get_rect (srcPR, bigsrc, x1, y1, width, height); extract_lab(bigsrc, bytes, width * height, bigdest); nayatani(bigdest,bytes,width * height, bigdest); gimp_pixel_rgn_set_rect (destPR, bigdest, x1, y1, width, height); // 2. Make a blur of Grey LAB for (row = 0, idx=0; row < height; row++, idx+=width) { gimp_pixel_rgn_get_row (destPR, src, x1, y1 + row, width); blur_line (ctable, cmatrix, cmatrix_length, src, dest, width, bytes); gimp_pixel_rgn_set_row (destPR, dest, x1, y1 + row, width); } for (col = 0; col < width; col++) { gimp_pixel_rgn_get_col (destPR, src, x1 + col, y1, height); blur_line (ctable, cmatrix, cmatrix_length, src, dest, height, bytes); gimp_pixel_rgn_set_col (destPR, dest, x1 + col, y1, height); if (show_progress && col % 8 == 0) gimp_progress_update ((gdouble) col / (3 * width) + 0.33); } // 3. Convert grey and blur back to RGB. compose_lab(bigdest, width * height, bytes, bigdest); // bigdest=greyRGB gimp_pixel_rgn_get_rect (destPR, bigsrc, x1, y1, width, height); compose_lab(bigsrc, width * height, bytes, bigsrc); // bigsrc= blurgreyRGB // 4. Blur Colour RGB and write into destPR gimp_pixel_rgn_get_rect (srcPR, tmpdest, x1, y1, width, height); gimp_pixel_rgn_set_rect (destPR, tmpdest, x1, y1, width, height); for (row = 0, idx=0; row < height; row++, idx+=width) { gimp_pixel_rgn_get_row (destPR, src, x1, y1 + row, width); blur_line (ctable, cmatrix, cmatrix_length, src, dest, width, bytes); gimp_pixel_rgn_set_row (destPR, dest, x1, y1 + row, width); } for (col = 0; col < width; col++) { gimp_pixel_rgn_get_col (destPR, src, x1 + col, y1, height); blur_line (ctable, cmatrix, cmatrix_length, src, dest, height, bytes); gimp_pixel_rgn_set_col (destPR, dest, x1 + col, y1, height); if (show_progress && col % 8 == 0) gimp_progress_update ((gdouble) col / (3 * width) + 0.33); } // destPR = blur colour RGB chromaunsharp( srcPR, destPR, bigdest, bigsrc, bytes, x1, y1, width, height, amount, gamma, tmpdest ); compose_lab(tmpdest, width * height, bytes, tmpdest); // tmpdest has unsharp gimp_pixel_rgn_set_rect (destPR, tmpdest, x1, y1, width, height); if (show_progress) gimp_progress_update (0.0); g_free (bigsrc); g_free (bigdest); g_free (tmpdest); g_free (iir.p); g_free (dest); g_free (src); }
/* * For all x and y as requested, replace the pixel at (x,y) * with a weighted average of the most frequently occurring * values in a circle of mask_size diameter centered at (x,y). */ static void oilify (GimpDrawable *drawable, GimpPreview *preview) { gboolean use_inten; gboolean use_msmap = FALSE; gboolean use_emap = FALSE; GimpDrawable *mask_size_map_drawable = NULL; GimpDrawable *exponent_map_drawable = NULL; GimpPixelRgn mask_size_map_rgn; GimpPixelRgn exponent_map_rgn; gint msmap_bpp = 0; gint emap_bpp = 0; GimpPixelRgn dest_rgn; GimpPixelRgn *regions[3]; gint n_regions; gint bpp; gint *sqr_lut; gint x1, y1, x2, y2; gint width, height; gint Hist[HISTSIZE]; gint Hist_rgb[4][HISTSIZE]; gpointer pr; gint progress, max_progress; guchar *src_buf; guchar *src_inten_buf = NULL; gint i; use_inten = (ovals.mode == MODE_INTEN); /* Get the selection bounds */ if (preview) { gimp_preview_get_position (preview, &x1, &y1); gimp_preview_get_size (preview, &width, &height); x2 = x1 + width; y2 = y1 + height; } else { gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); width = x2 - x1; height = y2 - y1; } progress = 0; max_progress = width * height; bpp = drawable->bpp; /* * Look-up-table implementation of the square function, for use in the * VERY TIGHT inner loops */ { gint lut_size = (gint) ovals.mask_size / 2 + 1; sqr_lut = g_new (gint, lut_size); for (i = 0; i < lut_size; i++) sqr_lut[i] = SQR (i); } /* Get the map drawables, if applicable */ if (ovals.use_mask_size_map && ovals.mask_size_map >= 0) { use_msmap = TRUE; mask_size_map_drawable = gimp_drawable_get (ovals.mask_size_map); gimp_pixel_rgn_init (&mask_size_map_rgn, mask_size_map_drawable, x1, y1, width, height, FALSE, FALSE); msmap_bpp = mask_size_map_drawable->bpp; } if (ovals.use_exponent_map && ovals.exponent_map >= 0) { use_emap = TRUE; exponent_map_drawable = gimp_drawable_get (ovals.exponent_map); gimp_pixel_rgn_init (&exponent_map_rgn, exponent_map_drawable, x1, y1, width, height, FALSE, FALSE); emap_bpp = exponent_map_drawable->bpp; } gimp_pixel_rgn_init (&dest_rgn, drawable, x1, y1, width, height, (preview == NULL), TRUE); { GimpPixelRgn src_rgn; gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, width, height, FALSE, FALSE); src_buf = g_new (guchar, width * height * bpp); gimp_pixel_rgn_get_rect (&src_rgn, src_buf, x1, y1, width, height); } /* * If we're working in intensity mode, then generate a separate intensity * map of the source image. This way, we can avoid calculating the * intensity of any given source pixel more than once. */ if (use_inten) { guchar *src; guchar *dest; src_inten_buf = g_new (guchar, width * height); for (i = 0, src = src_buf, dest = src_inten_buf ; i < (width * height) ; i++, src += bpp, dest++) { *dest = (guchar) GIMP_RGB_LUMINANCE (src[0], src[1], src[2]); } } n_regions = 0; regions[n_regions++] = &dest_rgn; if (use_msmap) regions[n_regions++] = &mask_size_map_rgn; if (use_emap) regions[n_regions++] = &exponent_map_rgn; for (pr = gimp_pixel_rgns_register2 (n_regions, regions); pr != NULL; pr = gimp_pixel_rgns_process (pr)) { gint y; guchar *dest_row; guchar *src_msmap_row = NULL; guchar *src_emap_row = NULL; for (y = dest_rgn.y, dest_row = dest_rgn.data, src_msmap_row = mask_size_map_rgn.data, /* valid iff use_msmap */ src_emap_row = exponent_map_rgn.data /* valid iff use_emap */ ; y < (gint) (dest_rgn.y + dest_rgn.h) ; y++, dest_row += dest_rgn.rowstride, src_msmap_row += mask_size_map_rgn.rowstride, /* valid iff use_msmap */ src_emap_row += exponent_map_rgn.rowstride) /* valid iff use_emap */ { gint x; guchar *dest; guchar *src_msmap = NULL; guchar *src_emap = NULL; for (x = dest_rgn.x, dest = dest_row, src_msmap = src_msmap_row, /* valid iff use_msmap */ src_emap = src_emap_row /* valid iff use_emap */ ; x < (gint) (dest_rgn.x + dest_rgn.w) ; x++, dest += bpp, src_msmap += msmap_bpp, /* valid iff use_msmap */ src_emap += emap_bpp) /* valid iff use_emap */ { gint radius, radius_squared; gfloat exponent; gint mask_x1, mask_y1; gint mask_x2, mask_y2; gint mask_y; gint src_offset; guchar *src_row; guchar *src_inten_row = NULL; if (use_msmap) { gfloat factor = get_map_value (src_msmap, msmap_bpp); radius = ROUND (factor * (0.5 * ovals.mask_size)); } else { radius = (gint) ovals.mask_size / 2; } radius_squared = SQR (radius); exponent = ovals.exponent; if (use_emap) exponent *= get_map_value (src_emap, emap_bpp); if (use_inten) memset (Hist, 0, sizeof (Hist)); memset (Hist_rgb, 0, sizeof (Hist_rgb)); mask_x1 = CLAMP ((x - radius), x1, x2); mask_y1 = CLAMP ((y - radius), y1, y2); mask_x2 = CLAMP ((x + radius + 1), x1, x2); mask_y2 = CLAMP ((y + radius + 1), y1, y2); src_offset = (mask_y1 - y1) * width + (mask_x1 - x1); for (mask_y = mask_y1, src_row = src_buf + src_offset * bpp, src_inten_row = src_inten_buf + src_offset /* valid iff use_inten */ ; mask_y < mask_y2 ; mask_y++, src_row += width * bpp, src_inten_row += width) /* valid iff use_inten */ { guchar *src; guchar *src_inten = NULL; gint dy_squared = sqr_lut[ABS (mask_y - y)]; gint mask_x; for (mask_x = mask_x1, src = src_row, src_inten = src_inten_row /* valid iff use_inten */ ; mask_x < mask_x2 ; mask_x++, src += bpp, src_inten++) /* valid iff use_inten */ { gint dx_squared = sqr_lut[ABS (mask_x - x)]; gint b; /* Stay inside a circular mask area */ if ((dx_squared + dy_squared) > radius_squared) continue; if (use_inten) { gint inten = *src_inten; ++Hist[inten]; for (b = 0; b < bpp; b++) Hist_rgb[b][inten] += src[b]; } else { for (b = 0; b < bpp; b++) ++Hist_rgb[b][src[b]]; } } /* for mask_x */ } /* for mask_y */ if (use_inten) { weighted_average_color (Hist, Hist_rgb, exponent, dest, bpp); } else { gint b; for (b = 0; b < bpp; b++) dest[b] = weighted_average_value (Hist_rgb[b], exponent); } } /* for x */ } /* for y */ if (preview) { gimp_drawable_preview_draw_region (GIMP_DRAWABLE_PREVIEW (preview), &dest_rgn); } else { progress += dest_rgn.w * dest_rgn.h; gimp_progress_update ((gdouble) progress / (gdouble) max_progress); } } /* for pr */ /* Detach from the map drawables */ if (mask_size_map_drawable) gimp_drawable_detach (mask_size_map_drawable); if (exponent_map_drawable) gimp_drawable_detach (exponent_map_drawable); if (src_inten_buf) g_free (src_inten_buf); g_free (src_buf); g_free (sqr_lut); if (!preview) { /* Update the oil-painted region */ gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); gimp_drawable_update (drawable->drawable_id, x1, y1, width, height); } }
static inline void filter (void) { static void (* overlap)(guchar *, const guchar *); GimpPixelRgn src; GimpPixelRgn dst; GimpRGB color; guchar pixel[4]; gint division_x; gint division_y; gint offset_x; gint offset_y; Tile *tiles; gint numof_tiles; Tile *t; gint i; gint x; gint y; gint move_max_pixels; gint clear_x0; gint clear_y0; gint clear_x1; gint clear_y1; gint clear_width; gint clear_height; guchar *pixels; guchar *buffer; gint dindex; gint sindex; gint px, py; GRand *gr; gr = g_rand_new (); /* INITIALIZE */ gimp_pixel_rgn_init (&src, p.drawable, 0, 0, p.drawable->width, p.drawable->height, FALSE, FALSE); gimp_pixel_rgn_init (&dst, p.drawable, 0, 0, p.drawable->width, p.drawable->height, TRUE, TRUE); pixels = g_new (guchar, p.drawable->bpp * p.drawable->width * p.drawable->height); buffer = g_new (guchar, p.drawable->bpp * p.params.tile_width * p.params.tile_height); overlap = p.drawable_has_alpha ? overlap_RGBA : overlap_RGB; gimp_progress_init (_("Paper Tile")); gimp_drawable_mask_bounds (p.drawable->drawable_id, &p.selection.x0, &p.selection.y0, &p.selection.x1, &p.selection.y1); p.selection.width = p.selection.x1 - p.selection.x0; p.selection.height = p.selection.y1 - p.selection.y0; gimp_tile_cache_ntiles (2 * (p.selection.width / gimp_tile_width () + 1)); /* TILES */ division_x = p.params.division_x; division_y = p.params.division_y; if (p.params.fractional_type == FRACTIONAL_TYPE_FORCE) { if (0 < p.drawable->width % p.params.tile_width) division_x++; if (0 < p.drawable->height % p.params.tile_height) division_y++; if (p.params.centering) { if (1 < p.drawable->width % p.params.tile_width) { division_x++; offset_x = (p.drawable->width % p.params.tile_width) / 2 - p.params.tile_width; } else { offset_x = 0; } if (1 < p.drawable->height % p.params.tile_height) { division_y++; offset_y = (p.drawable->height % p.params.tile_height) / 2 - p.params.tile_height; } else { offset_y = 0; } } else { offset_x = 0; offset_y = 0; } } else { if (p.params.centering) { offset_x = (p.drawable->width % p.params.tile_width) / 2; offset_y = (p.drawable->height % p.params.tile_height) / 2; } else { offset_x = 0; offset_y = 0; } } move_max_pixels = p.params.move_max_rate * p.params.tile_width / 100.0; numof_tiles = division_x * division_y; t = tiles = g_new(Tile, numof_tiles); for (y = 0; y < division_y; y++) { gint srcy = offset_y + p.params.tile_height * y; for (x = 0; x < division_x; x++, t++) { gint srcx = offset_x + p.params.tile_width * x; if (srcx < 0) { t->x = 0; t->width = srcx + p.params.tile_width; } else if (srcx + p.params.tile_width < p.drawable->width) { t->x = srcx; t->width = p.params.tile_width; } else { t->x = srcx; t->width = p.drawable->width - srcx; } if (srcy < 0) { t->y = 0; t->height = srcy + p.params.tile_height; } else if (srcy + p.params.tile_height < p.drawable->height) { t->y = srcy; t->height = p.params.tile_height; } else { t->y = srcy; t->height = p.drawable->height - srcy; } t->z = g_rand_int (gr); random_move (&t->move_x, &t->move_y, move_max_pixels); } } qsort (tiles, numof_tiles, sizeof *tiles, tile_compare); gimp_pixel_rgn_get_rect (&src, pixels, 0, 0, p.drawable->width, p.drawable->height); if (p.params.fractional_type == FRACTIONAL_TYPE_IGNORE) { clear_x0 = offset_x; clear_y0 = offset_y; clear_width = p.params.tile_width * division_x; clear_height = p.params.tile_height * division_y; } else { clear_x0 = 0; clear_y0 = 0; clear_width = p.drawable->width; clear_height = p.drawable->height; } clear_x1 = clear_x0 + clear_width; clear_y1 = clear_y0 + clear_height; switch (p.params.background_type) { case BACKGROUND_TYPE_TRANSPARENT: for (y = clear_y0; y < clear_y1; y++) { for (x = clear_x0; x < clear_x1; x++) { dindex = p.drawable->bpp * (p.drawable->width * y + x); for (i = 0; i < p.drawable->bpp; i++) { pixels[dindex+i] = 0; } } } break; case BACKGROUND_TYPE_INVERTED: for (y = clear_y0; y < clear_y1; y++) { for (x = clear_x0; x < clear_x1; x++) { dindex = p.drawable->bpp * (p.drawable->width * y + x); pixels[dindex+0] = 255 - pixels[dindex+0]; pixels[dindex+1] = 255 - pixels[dindex+1]; pixels[dindex+2] = 255 - pixels[dindex+2]; } } break; case BACKGROUND_TYPE_IMAGE: break; case BACKGROUND_TYPE_FOREGROUND: gimp_context_get_foreground (&color); gimp_rgb_get_uchar (&color, &pixel[0], &pixel[1], &pixel[2]); pixel[3] = 255; for (y = clear_y0; y < clear_y1; y++) { for (x = clear_x0; x < clear_x1; x++) { dindex = p.drawable->bpp * (p.drawable->width * y + x); for (i = 0; i < p.drawable->bpp; i++) { pixels[dindex+i] = pixel[i]; } } } break; case BACKGROUND_TYPE_BACKGROUND: gimp_context_get_background (&color); gimp_rgb_get_uchar (&color, &pixel[0], &pixel[1], &pixel[2]); pixel[3] = 255; for (y = clear_y0; y < clear_y1; y++) { for (x = clear_x0; x < clear_x1; x++) { dindex = p.drawable->bpp * (p.drawable->width * y + x); for(i = 0; i < p.drawable->bpp; i++) { pixels[dindex+i] = pixel[i]; } } } break; case BACKGROUND_TYPE_COLOR: gimp_rgba_get_uchar (&p.params.background_color, pixel, pixel + 1, pixel + 2, pixel + 3); for (y = clear_y0; y < clear_y1; y++) { for (x = clear_x0; x < clear_x1; x++) { dindex = p.drawable->bpp * (p.drawable->width * y + x); for(i = 0; i < p.drawable->bpp; i++) { pixels[dindex+i] = pixel[i]; } } } break; } /* DRAW */ for (t = tiles, i = 0; i < numof_tiles; i++, t++) { gint x0 = t->x + t->move_x; gint y0 = t->y + t->move_y; gimp_pixel_rgn_get_rect (&src, buffer, t->x, t->y, t->width, t->height); for (y = 0; y < t->height; y++) { py = y0 + y; for (x = 0; x < t->width; x++) { px = x0 + x; sindex = p.drawable->bpp * (t->width * y + x); if (0 <= px && px < p.drawable->width && 0 <= py && py < p.drawable->height) { dindex = p.drawable->bpp * (p.drawable->width * py + px); overlap(&pixels[dindex], &buffer[sindex]); } else if (p.params.wrap_around) { px = (px + p.drawable->width) % p.drawable->width; py = (py + p.drawable->height) % p.drawable->height; dindex = p.drawable->bpp * (p.drawable->width * py + px); overlap(&pixels[dindex], &buffer[sindex]); } } } gimp_progress_update ((gdouble) i / (gdouble) numof_tiles); } gimp_pixel_rgn_set_rect (&dst, pixels, 0, 0, p.drawable->width, p.drawable->height); gimp_progress_update (1.0); gimp_drawable_flush (p.drawable); gimp_drawable_merge_shadow (p.drawable->drawable_id, TRUE); gimp_drawable_update (p.drawable->drawable_id, p.selection.x0, p.selection.y0, p.selection.width, p.selection.height); g_rand_free (gr); g_free (buffer); g_free (pixels); g_free (tiles); }
guchar *p_drawable_encode_jpeg(GDrawable *drawable, gint32 jpeg_interlaced, gint32 *JPEG_size, gint32 jpeg_quality, gint32 odd_even, gint32 use_YUV411, void *app0_buffer, gint32 app0_length) { GPixelRgn pixel_rgn; GDrawableType drawable_type; struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; guchar *temp, *t; guchar *data; guchar *src, *s; int has_alpha; int rowstride, yend; int i, j, y; guchar *JPEG_data; size_t *JPEG_buf_remain; size_t totalsize = 0; drawable_type = gimp_drawable_type (drawable->id); gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, FALSE, FALSE); /* Step 1: allocate and initialize JPEG compression object */ /* We have to set up the error handler first, in case the initialization * step fails. (Unlikely, but it could happen if you are out of memory.) * This routine fills in the contents of struct jerr, and returns jerr's * address which we place into the link field in cinfo. */ cinfo.err = jpeg_std_error(&jerr); /* Now we can initialize the JPEG compression object. */ jpeg_create_compress (&cinfo); /* Step 2: specify data destination (eg, a file) */ /* Note: steps 2 and 3 can be done in either order. */ /* We use our own jpeg destination mgr */ JPEG_data = (guchar *)g_malloc(OUTPUT_BUF_SIZE * sizeof(guchar)); /* Install my memory destination manager (instead of stdio_dest) */ jpeg_memio_dest (&cinfo, JPEG_data, &JPEG_buf_remain); if (gap_debug) fprintf(stderr, "GAP_AVI: encode_jpeg: Cleared the initilization !\n"); /* Get the input image and a pointer to its data. */ switch (drawable_type) { case RGB_IMAGE: case GRAY_IMAGE: /* # of color components per pixel */ cinfo.input_components = drawable->bpp; has_alpha = 0; break; case RGBA_IMAGE: case GRAYA_IMAGE: gimp_message ("jpeg: image contains a-channel info which will be lost"); /* # of color components per pixel (minus the GIMP alpha channel) */ cinfo.input_components = drawable->bpp - 1; has_alpha = 1; break; case INDEXED_IMAGE: gimp_message ("jpeg: cannot operate on indexed color images"); return FALSE; break; default: gimp_message ("jpeg: cannot operate on unknown image types"); return FALSE; break; } /* Step 3: set parameters for compression */ /* First we supply a description of the input image. * Four fields of the cinfo struct must be filled in: */ /* image width and height, in pixels */ cinfo.image_width = drawable->width; cinfo.image_height = drawable->height; /* colorspace of input image */ cinfo.in_color_space = (drawable_type == RGB_IMAGE || drawable_type == RGBA_IMAGE) ? JCS_RGB : JCS_GRAYSCALE; /* Now use the library's routine to set default compression parameters. * (You must set at least cinfo.in_color_space before calling this, * since the defaults depend on the source color space.) */ jpeg_set_defaults (&cinfo); jpeg_set_quality (&cinfo, (int) (jpeg_quality), TRUE); /* Smoothing is not possible for nonstandard sampling rates */ /* cinfo.smoothing_factor = (int) (50); */ /* I wonder if this is slower: */ /* cinfo.optimize_coding = 1; */ /* Are these the evil AVI destroyers ? */ cinfo.write_Adobe_marker = FALSE; cinfo.write_JFIF_header = FALSE; /* That's the only allowed encoding in a movtar */ if (!use_YUV411) { cinfo.comp_info[0].h_samp_factor = 2; cinfo.comp_info[0].v_samp_factor = 1; cinfo.comp_info[1].h_samp_factor = 1; cinfo.comp_info[1].v_samp_factor = 1; cinfo.comp_info[2].h_samp_factor = 1; cinfo.comp_info[2].v_samp_factor = 1; } else if (gap_debug) fprintf(stderr, "Using YUV 4:1:1 encoding !"); cinfo.restart_interval = 0; cinfo.restart_in_rows = FALSE; /* could be _ISLOW or _FLOAT, too, but this is fastest */ cinfo.dct_method = JDCT_ISLOW; if (gap_debug) fprintf(stderr, "GAP_AVI: encode_jpeg: Cleared parameter setting !\n"); if (jpeg_interlaced) { cinfo.image_height = drawable->height/2; rowstride = drawable->bpp * drawable->width; temp = (guchar *) g_malloc (cinfo.image_width * cinfo.input_components); data = (guchar *) g_malloc (rowstride * gimp_tile_height ()); for (y = (odd_even) ? 1 : 0; (odd_even) ? (y >= 0) : (y <= 1); (odd_even) ? (y--) : (y++)) { if (gap_debug) fprintf(stderr, "GAP_AVI: encode_jpeg: interlaced picture, now coding %s lines\n", y ? "odd" : "even"); jpeg_start_compress (&cinfo, TRUE); /* Step 4.1: Write the app0 marker out */ if(app0_buffer) jpeg_write_marker(&cinfo, JPEG_APP0, app0_buffer, app0_length); while (cinfo.next_scanline < cinfo.image_height) { if (gap_debug) fprintf(stderr, "GAP_AVI: encode_jpeg: Line %d !", cinfo.next_scanline); gimp_pixel_rgn_get_rect (&pixel_rgn, data, 0, 2 * cinfo.next_scanline + y, cinfo.image_width, 1); /* Get rid of all the bad stuff (tm) (= get the right pixel order for JPEG encoding) */ t = temp; s = data; i = cinfo.image_width; while (i--) { for (j = 0; j < cinfo.input_components; j++) *t++ = *s++; if (has_alpha) /* ignore alpha channel */ s++; } src += 2*rowstride; jpeg_write_scanlines (&cinfo, (JSAMPARRAY) &temp, 1); } jpeg_finish_compress(&cinfo); totalsize += (OUTPUT_BUF_SIZE - *JPEG_buf_remain); //JPEG_data = (guchar *)realloc(JPEG_data, sizeof(guchar)* *JPEG_size); } /* fprintf(stderr, "2 fields written.\n"); */ } else { /* Step 4: Start compressor */ /* TRUE ensures that we will write a complete interchange-JPEG file. * Pass TRUE unless you are very sure of what you're doing. */ if (gap_debug) fprintf(stderr, "GAP_AVI: encode_jpeg: non-interlaced picture.\n"); jpeg_start_compress (&cinfo, TRUE); /* Step 4.1: Write the app0 marker out */ if(app0_buffer) jpeg_write_marker(&cinfo, JPEG_APP0, app0_buffer, app0_length); /* Step 5: while (scan lines remain to be written) */ /* jpeg_write_scanlines(...); */ /* Here we use the library's state variable cinfo.next_scanline as the * loop counter, so that we don't have to keep track ourselves. * To keep things simple, we pass one scanline per call; you can pass * more if you wish, though. */ /* JSAMPLEs per row in image_buffer */ rowstride = drawable->bpp * drawable->width; temp = (guchar *) g_malloc (cinfo.image_width * cinfo.input_components); data = (guchar *) g_malloc (rowstride * gimp_tile_height ()); /* fault if cinfo.next_scanline isn't initially a multiple of * gimp_tile_height */ src = NULL; while (cinfo.next_scanline < cinfo.image_height) { if (gap_debug) fprintf(stderr, "GAP_AVI: encode_jpeg: Line %d !", cinfo.next_scanline); if ((cinfo.next_scanline % gimp_tile_height ()) == 0) { yend = cinfo.next_scanline + gimp_tile_height (); yend = MIN (yend, cinfo.image_height); gimp_pixel_rgn_get_rect (&pixel_rgn, data, 0, cinfo.next_scanline, cinfo.image_width, (yend - cinfo.next_scanline)); src = data; } t = temp; s = src; i = cinfo.image_width; while (i--) { for (j = 0; j < cinfo.input_components; j++) *t++ = *s++; if (has_alpha) /* ignore alpha channel */ s++; } src += rowstride; jpeg_write_scanlines (&cinfo, (JSAMPARRAY) &temp, 1); } /* Step 6: Finish compression */ jpeg_finish_compress (&cinfo); totalsize += (OUTPUT_BUF_SIZE - *JPEG_buf_remain); // JPEG_data = (guchar *)realloc(JPEG_data, sizeof(guchar)* *JPEG_size); } /* Step 7: release JPEG compression object */ /* This is an important step since it will release a good deal of memory. */ jpeg_destroy_compress (&cinfo); /* free the temporary buffer */ g_free (temp); g_free (data); *JPEG_size = totalsize; return JPEG_data; }
static void psd_write_image_data_packbits (int fd, gint32 imageID, gint32 width, gint32 height) { gint i, x, y, col; gint32 current, total; gint16 compression; GimpDrawable *drw[4]; GimpPixelRgn region; gchar *src_buf, *dst_buf; guint16 line_bytes[MAX_PIXELS]; gint buf_width, buf_height; off_t data_head, data_end; gchar channel_name[4][2] = { "C", "M", "Y", "K" }; drw[0] = separate_find_channel (imageID,sep_C); drw[1] = separate_find_channel (imageID,sep_M); drw[2] = separate_find_channel (imageID,sep_Y); drw[3] = separate_find_channel (imageID,sep_K); gimp_progress_init (""); current = 0; total = height * 4; buf_width = ceil (width * 1.334); buf_height = MIN (MAX_BUFFER_SIZE / buf_width, height); if (!(src_buf = g_try_malloc (buf_width * buf_height))) return; if (!(dst_buf = g_try_malloc (buf_width * buf_height))) { g_free (src_buf); return; } compression = GINT16_TO_BE (1); write (fd, &compression, sizeof (gint16)); data_head = lseek (fd, 0, SEEK_CUR); data_end = data_head + height * 4 * 2; for (i = 0; i < 4; i++) { gint n_lines; gint result; gimp_progress_set_text_printf (_("Exporting Photoshop PSD (%s channel)..."), channel_name[i]); if (drw[i]) { gimp_pixel_rgn_init (®ion, drw[i], 0, 0, width, height, FALSE, FALSE); for (y = 0; y < height; y += buf_height, current += buf_height) { gint read_bytes, write_bytes; gimp_progress_update ((gdouble)current / (gdouble)total); n_lines = MIN (height - y, buf_height); gimp_pixel_rgn_get_rect (®ion, src_buf, 0, y, width, n_lines); read_bytes = 0; write_bytes = 0; for (col = 0; col < n_lines; col++) { gint _write_bytes = write_bytes; gchar *count = dst_buf + write_bytes++; *count = 0; dst_buf[write_bytes++] = 0xff - src_buf[read_bytes++]; for (x = 1; x < width; x++) { gchar tmp = 0xff - src_buf[read_bytes++]; if (dst_buf[write_bytes - 1] == tmp) /* 連続 */ { if (*count == -127) { /* 128バイトを超えた場合 */ count = dst_buf + write_bytes++; *count = 0; dst_buf[write_bytes++] = tmp; } else if (*count <= 0) { /* 通常のカウント */ (*count)--; } else { /* 非連続からの切り替え */ (*count)--; /* 非連続としてカウントされた1バイト目の分を減らす */ count = dst_buf + write_bytes - 1; *count = -1; dst_buf[write_bytes++] = tmp; } } else /* 非連続 */ { if (*count >= 0 && *count != 127) { (*count)++; dst_buf[write_bytes++] = tmp; } else { count = dst_buf + write_bytes++; *count = 0; dst_buf[write_bytes++] = tmp; } } } line_bytes[y + col] = GINT16_TO_BE (write_bytes - _write_bytes); } /* seek to end of pixel data */ lseek (fd, data_end, SEEK_SET); result = write (fd, dst_buf, write_bytes); data_end += write_bytes; } /* seek to bytes per line data */ lseek (fd, data_head + height * i * 2, SEEK_SET); result = write (fd, line_bytes, height * 2); } else { gint n_repeat = width / 128; gint bytes = 0; for (x = 0; x < n_repeat; x++) { dst_buf[bytes++] = -127; dst_buf[bytes++] = 0xff; } if (width % 128) { dst_buf[bytes++] = ((width % 128) - 1) * -1; dst_buf[bytes++] = 0xff; } for (col = 1; col < buf_height; col++) memcpy (dst_buf + bytes * col, dst_buf, bytes); /* seek to end of pixel data */ lseek (fd, data_end, SEEK_SET); for (y = 0; y < height; y += buf_height, current += buf_height) { gimp_progress_update ((gdouble)current / (gdouble)total); n_lines = MIN (height - y, buf_height); result = write (fd, dst_buf, bytes * n_lines); for (col = 0; col < n_lines; col++) line_bytes[y + col] = GINT16_TO_BE (bytes); } data_end += bytes * height; /* seek to bytes per line data */ lseek (fd, data_head + height * i * 2, SEEK_SET); result = write (fd, line_bytes, height * 2); } } gimp_progress_update (1.0); g_free (src_buf); g_free (dst_buf); }
static void psd_write_image_data_raw (int fd, gint32 imageID, gint32 width, gint32 height) { gint i, x, y; gint32 current, total; gint16 compression; GimpDrawable *drw[4]; GimpPixelRgn region; gchar *buf; gint buf_height; gchar channel_name[4][2] = { "C", "M", "Y", "K" }; drw[0] = separate_find_channel (imageID,sep_C); drw[1] = separate_find_channel (imageID,sep_M); drw[2] = separate_find_channel (imageID,sep_Y); drw[3] = separate_find_channel (imageID,sep_K); gimp_progress_init (""); current = 0; total = height * 4; buf_height = MIN (MAX_BUFFER_SIZE / width, height); if (!(buf = g_try_malloc (width * buf_height))) return; compression = 0; write (fd, &compression, sizeof (gint16)); for (i = 0; i < 4; i++) { gint n_lines; gint result; gimp_progress_set_text_printf (_("Exporting Photoshop PSD (%s channel)..."), channel_name[i]); if (drw[i]) { gimp_pixel_rgn_init (®ion, drw[i], 0, 0, width, height, FALSE, FALSE); for (y = 0; y < height; y += buf_height, current += buf_height) { gimp_progress_update ((gdouble)current / (gdouble)total); n_lines = MIN (height - y, buf_height); gimp_pixel_rgn_get_rect (®ion, buf, 0, y, width, n_lines); for (x = 0; x < width * n_lines; x++) buf[x] = 0xff - buf[x]; result = write (fd, buf, width * n_lines); } } else { memset (buf, 0xff, width * buf_height); for (y = 0; y < height; y += buf_height, current += buf_height) { gimp_progress_update ((gdouble)current / (gdouble)total); n_lines = MIN (height - y, buf_height); result = write (fd, buf, width * n_lines); } } } gimp_progress_update (1.0); g_free (buf); }
static void edge_preview_update (GimpPreview *preview) { /* drawable */ GimpDrawable *drawable; glong bytes; gint alpha; gboolean has_alpha; /* preview */ guchar *src = NULL; /* Buffer to hold source image */ guchar *render_buffer = NULL; /* Buffer to hold rendered image */ guchar *dest; gint width; /* Width of preview widget */ gint height; /* Height of preview widget */ gint x1; /* Upper-left X of preview */ gint y1; /* Upper-left Y of preview */ GimpPixelRgn srcPR; /* Pixel regions */ /* algorithm */ gint x, y; /* Get drawable info */ drawable = gimp_drawable_preview_get_drawable (GIMP_DRAWABLE_PREVIEW (preview)); bytes = gimp_drawable_bpp (drawable->drawable_id); alpha = bytes; has_alpha = gimp_drawable_has_alpha (drawable->drawable_id); if (has_alpha) alpha--; /* * Setup for filter... */ gimp_preview_get_position (preview, &x1, &y1); gimp_preview_get_size (preview, &width, &height); /* initialize pixel regions */ gimp_pixel_rgn_init (&srcPR, drawable, x1, y1, width, height, FALSE, FALSE); src = g_new (guchar, width * height * bytes); render_buffer = g_new (guchar, width * height * bytes); /* render image */ gimp_pixel_rgn_get_rect(&srcPR, src, x1, y1, width, height); dest = render_buffer; /* render algorithm */ for (y = 0 ; y < height ; y++) for (x = 0 ; x < width ; x++) { gint chan; for (chan = 0; chan < alpha; chan++) { guchar kernel[9]; #define SRC(X,Y) src[bytes * (CLAMP((X), 0, width-1) + \ width * CLAMP((Y), 0, height-1)) + chan] kernel[0] = SRC (x - 1, y - 1); kernel[1] = SRC (x - 1, y ); kernel[2] = SRC (x - 1, y + 1); kernel[3] = SRC (x , y - 1); kernel[4] = SRC (x , y ); kernel[5] = SRC (x , y + 1); kernel[6] = SRC (x + 1, y - 1); kernel[7] = SRC (x + 1, y ); kernel[8] = SRC (x + 1, y + 1); #undef SRC dest[chan] = edge_detect (kernel); } if (has_alpha) dest[alpha] = src[bytes * (x + width * y) + alpha]; dest += bytes; } /* * Draw the preview image on the screen... */ gimp_preview_draw_buffer (preview, render_buffer, width * bytes); g_free (render_buffer); g_free (src); }
static void ico_dialog_update_icon_preview (GtkWidget *dialog, gint32 layer, gint bpp) { GtkWidget *preview = ico_dialog_get_layer_preview (dialog, layer); GdkPixbuf *pixbuf; gint w = gimp_drawable_width (layer); gint h = gimp_drawable_height (layer); if (! preview) return; if (bpp <= 8) { GimpDrawable *drawable; GimpDrawable *tmp; GimpPixelRgn src_pixel_rgn, dst_pixel_rgn; gint32 image; gint32 tmp_image; gint32 tmp_layer; guchar *buffer; guchar *cmap; gint num_colors; image = gimp_item_get_image (layer); tmp_image = gimp_image_new (w, h, gimp_image_base_type (image)); gimp_image_undo_disable (tmp_image); if (gimp_drawable_is_indexed (layer)) { cmap = gimp_image_get_colormap (image, &num_colors); gimp_image_set_colormap (tmp_image, cmap, num_colors); g_free (cmap); } tmp_layer = gimp_layer_new (tmp_image, "temporary", w, h, gimp_drawable_type (layer), 100, GIMP_NORMAL_MODE); gimp_image_insert_layer (tmp_image, tmp_layer, -1, 0); drawable = gimp_drawable_get (layer); tmp = gimp_drawable_get (tmp_layer); gimp_pixel_rgn_init (&src_pixel_rgn, drawable, 0, 0, w, h, FALSE, FALSE); gimp_pixel_rgn_init (&dst_pixel_rgn, tmp, 0, 0, w, h, TRUE, FALSE); buffer = g_malloc (w * h * 4); gimp_pixel_rgn_get_rect (&src_pixel_rgn, buffer, 0, 0, w, h); gimp_pixel_rgn_set_rect (&dst_pixel_rgn, buffer, 0, 0, w, h); gimp_drawable_detach (tmp); gimp_drawable_detach (drawable); if (gimp_drawable_is_indexed (layer)) gimp_image_convert_rgb (tmp_image); gimp_image_convert_indexed (tmp_image, GIMP_FS_DITHER, GIMP_MAKE_PALETTE, 1 <<bpp, TRUE, FALSE, "dummy"); cmap = gimp_image_get_colormap (tmp_image, &num_colors); if ( num_colors == (1 << bpp) && !ico_cmap_contains_black (cmap, num_colors)) { /* Windows icons with color maps need the color black. * We need to eliminate one more color to make room for black. */ if (gimp_drawable_is_indexed (layer)) { g_free (cmap); cmap = gimp_image_get_colormap (image, &num_colors); gimp_image_set_colormap (tmp_image, cmap, num_colors); } else if (gimp_drawable_is_gray (layer)) { gimp_image_convert_grayscale (tmp_image); } else { gimp_image_convert_rgb (tmp_image); } tmp = gimp_drawable_get (tmp_layer); gimp_pixel_rgn_init (&dst_pixel_rgn, tmp, 0, 0, w, h, TRUE, FALSE); gimp_pixel_rgn_set_rect (&dst_pixel_rgn, buffer, 0, 0, w, h); gimp_drawable_detach (tmp); if (!gimp_drawable_is_rgb (layer)) gimp_image_convert_rgb (tmp_image); gimp_image_convert_indexed (tmp_image, GIMP_FS_DITHER, GIMP_MAKE_PALETTE, (1<<bpp) - 1, TRUE, FALSE, "dummy"); } g_free (cmap); g_free (buffer); pixbuf = gimp_drawable_get_thumbnail (tmp_layer, MIN (w, 128), MIN (h, 128), GIMP_PIXBUF_SMALL_CHECKS); gimp_image_delete (tmp_image); } else if (bpp == 24) { GimpDrawable *drawable; GimpDrawable *tmp; GimpPixelRgn src_pixel_rgn, dst_pixel_rgn; gint32 image; gint32 tmp_image; gint32 tmp_layer; guchar *buffer; GimpParam *return_vals; gint n_return_vals; image = gimp_item_get_image (layer); tmp_image = gimp_image_new (w, h, gimp_image_base_type (image)); gimp_image_undo_disable (tmp_image); if (gimp_drawable_is_indexed (layer)) { guchar *cmap; gint num_colors; cmap = gimp_image_get_colormap (image, &num_colors); gimp_image_set_colormap (tmp_image, cmap, num_colors); g_free (cmap); } tmp_layer = gimp_layer_new (tmp_image, "temporary", w, h, gimp_drawable_type (layer), 100, GIMP_NORMAL_MODE); gimp_image_insert_layer (tmp_image, tmp_layer, -1, 0); drawable = gimp_drawable_get (layer); tmp = gimp_drawable_get (tmp_layer); gimp_pixel_rgn_init (&src_pixel_rgn, drawable, 0, 0, w, h, FALSE, FALSE); gimp_pixel_rgn_init (&dst_pixel_rgn, tmp, 0, 0, w, h, TRUE, FALSE); buffer = g_malloc (w * h * 4); gimp_pixel_rgn_get_rect (&src_pixel_rgn, buffer, 0, 0, w, h); gimp_pixel_rgn_set_rect (&dst_pixel_rgn, buffer, 0, 0, w, h); g_free (buffer); gimp_drawable_detach (tmp); gimp_drawable_detach (drawable); if (gimp_drawable_is_indexed (layer)) gimp_image_convert_rgb (tmp_image); return_vals = gimp_run_procedure ("plug-in-threshold-alpha", &n_return_vals, GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE, GIMP_PDB_IMAGE, tmp_image, GIMP_PDB_DRAWABLE, tmp_layer, GIMP_PDB_INT32, ICO_ALPHA_THRESHOLD, GIMP_PDB_END); gimp_destroy_params (return_vals, n_return_vals); pixbuf = gimp_drawable_get_thumbnail (tmp_layer, MIN (w, 128), MIN (h, 128), GIMP_PIXBUF_SMALL_CHECKS); gimp_image_delete (tmp_image); } else { pixbuf = gimp_drawable_get_thumbnail (layer, MIN (w, 128), MIN (h, 128), GIMP_PIXBUF_SMALL_CHECKS); } gtk_image_set_from_pixbuf (GTK_IMAGE (preview), pixbuf); g_object_unref (pixbuf); }
static void drawlens (GimpDrawable *drawable, GimpPreview *preview) { GimpImageType drawtype = gimp_drawable_type (drawable->drawable_id); GimpPixelRgn srcPR, destPR; gint width, height; gint bytes; gint row; gint x1, y1, x2, y2; guchar *src, *dest; gint i, col; gfloat regionwidth, regionheight, dx, dy, xsqr, ysqr; gfloat a, b, c, asqr, bsqr, csqr, x, y; glong pixelpos, pos; GimpRGB background; guchar bgr_red, bgr_blue, bgr_green; guchar alphaval; gimp_context_get_background (&background); gimp_rgb_get_uchar (&background, &bgr_red, &bgr_green, &bgr_blue); bytes = drawable->bpp; if (preview) { gimp_preview_get_position (preview, &x1, &y1); gimp_preview_get_size (preview, &width, &height); x2 = x1 + width; y2 = y1 + height; src = gimp_drawable_get_thumbnail_data (drawable->drawable_id, &width, &height, &bytes); regionwidth = width; regionheight = height; } else { gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); regionwidth = x2 - x1; regionheight = y2 - y1; width = drawable->width; height = drawable->height; gimp_pixel_rgn_init (&srcPR, drawable, 0, 0, width, height, FALSE, FALSE); gimp_pixel_rgn_init (&destPR, drawable, 0, 0, width, height, TRUE, TRUE); src = g_new (guchar, regionwidth * regionheight * bytes); gimp_pixel_rgn_get_rect (&srcPR, src, x1, y1, regionwidth, regionheight); } dest = g_new (guchar, regionwidth * regionheight * bytes); a = regionwidth / 2; b = regionheight / 2; c = MIN (a, b); asqr = a * a; bsqr = b * b; csqr = c * c; for (col = 0; col < regionwidth; col++) { dx = (gfloat) col - a + 0.5; xsqr = dx * dx; for (row = 0; row < regionheight; row++) { pixelpos = (col + row * regionwidth) * bytes; dy = -((gfloat) row - b) - 0.5; ysqr = dy * dy; if (ysqr < (bsqr - (bsqr * xsqr) / asqr)) { find_projected_pos (asqr, bsqr, csqr, dx, dy, &x, &y); y = -y; pos = ((gint) (y + b) * regionwidth + (gint) (x + a)) * bytes; for (i = 0; i < bytes; i++) { dest[pixelpos + i] = src[pos + i]; } } else { if (lvals.keep_surr) { for (i = 0; i < bytes; i++) { dest[pixelpos + i] = src[pixelpos + i]; } } else { if (lvals.set_transparent) alphaval = 0; else alphaval = 255; switch (drawtype) { case GIMP_INDEXEDA_IMAGE: dest[pixelpos + 1] = alphaval; case GIMP_INDEXED_IMAGE: dest[pixelpos + 0] = 0; break; case GIMP_RGBA_IMAGE: dest[pixelpos + 3] = alphaval; case GIMP_RGB_IMAGE: dest[pixelpos + 0] = bgr_red; dest[pixelpos + 1] = bgr_green; dest[pixelpos + 2] = bgr_blue; break; case GIMP_GRAYA_IMAGE: dest[pixelpos + 1] = alphaval; case GIMP_GRAY_IMAGE: dest[pixelpos+0] = bgr_red; break; } } } } if (!preview) { if (((gint) (regionwidth-col) % 5) == 0) gimp_progress_update ((gdouble) col / (gdouble) regionwidth); } } if (preview) { gimp_preview_draw_buffer (preview, dest, bytes * regionwidth); } else { gimp_progress_update (1.0); gimp_pixel_rgn_set_rect (&destPR, dest, x1, y1, regionwidth, regionheight); gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); gimp_drawable_update (drawable->drawable_id, x1, y1, x2 - x1, y2 - y1); } g_free (src); g_free (dest); }
/* * Applies the algorithm */ static void retinex (GimpDrawable *drawable, GimpPreview *preview) { gint x, y, width, height; gint size, bytes; guchar *src = NULL; guchar *psrc = NULL; GimpPixelRgn dst_rgn, src_rgn; bytes = drawable->bpp; /* * Get the size of the current image or its selection. */ if (preview) { src = gimp_zoom_preview_get_source (GIMP_ZOOM_PREVIEW (preview), &width, &height, &bytes); } else { if (! gimp_drawable_mask_intersect (drawable->drawable_id, &x, &y, &width, &height)) return; /* Allocate memory */ size = width * height * bytes; src = g_try_malloc (sizeof (guchar) * size); if (src == NULL) { g_warning ("Failed to allocate memory"); return; } memset (src, 0, sizeof (guchar) * size); /* Fill allocated memory with pixel data */ gimp_pixel_rgn_init (&src_rgn, drawable, x, y, width, height, FALSE, FALSE); gimp_pixel_rgn_get_rect (&src_rgn, src, x, y, width, height); } /* Algorithm for Multi-scale Retinex with color Restoration (MSRCR). */ psrc = src; MSRCR (psrc, width, height, bytes, preview != NULL); if (preview) { gimp_preview_draw_buffer (preview, psrc, width * bytes); } else { gimp_pixel_rgn_init (&dst_rgn, drawable, x, y, width, height, TRUE, TRUE); gimp_pixel_rgn_set_rect (&dst_rgn, psrc, x, y, width, height); gimp_progress_update (1.0); gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); gimp_drawable_update (drawable->drawable_id, x, y, width, height); } g_free (src); }
/* Decompose an image. It returns the number of new (gray) images. The image IDs for the new images are returned in image_ID_dst. On failure, -1 is returned. */ static gint32 decompose (gint32 image_ID, gint32 drawable_ID, const gchar *extract_type, gint32 *image_ID_dst, gint32 *nlayers, gint32 *layer_ID_dst) { const gchar *layername; gint i, j, extract_idx, scan_lines; gint height, width, tile_height, num_layers; gchar *filename; guchar *src; guchar *dst[MAX_EXTRACT_IMAGES]; GimpDrawable *drawable_src; GimpDrawable *drawable_dst[MAX_EXTRACT_IMAGES]; GimpPixelRgn pixel_rgn_src; GimpPixelRgn pixel_rgn_dst[MAX_EXTRACT_IMAGES]; extract_idx = -1; /* Search extract type */ for (j = 0; j < G_N_ELEMENTS (extract); j++) { if (g_ascii_strcasecmp (extract_type, extract[j].type) == 0) { extract_idx = j; break; } } if (extract_idx < 0) return -1; /* Check structure of source image */ drawable_src = gimp_drawable_get (drawable_ID); if (drawable_src->bpp < 3) { g_message ("Not an RGB image."); return -1; } if ((extract[extract_idx].extract_fun == extract_alpha || extract[extract_idx].extract_fun == extract_rgba) && (!gimp_drawable_has_alpha (drawable_ID))) { g_message ("No alpha channel available."); return -1; } width = drawable_src->width; height = drawable_src->height; tile_height = gimp_tile_height (); gimp_pixel_rgn_init (&pixel_rgn_src, drawable_src, 0, 0, width, height, FALSE, FALSE); /* allocate a buffer for retrieving information from the src pixel region */ src = g_new (guchar, tile_height * width * drawable_src->bpp); /* Create all new gray images */ num_layers = extract[extract_idx].num_images; if (num_layers > MAX_EXTRACT_IMAGES) num_layers = MAX_EXTRACT_IMAGES; for (j = 0; j < num_layers; j++) { /* Build a filename like <imagename>-<channel>.<extension> */ gchar *fname; gchar *extension; gdouble xres, yres; fname = gimp_image_get_filename (image_ID); if (fname) { extension = fname + strlen (fname) - 1; while (extension >= fname) { if (*extension == '.') break; extension--; } if (extension >= fname) { *(extension++) = '\0'; if (decovals.as_layers) filename = g_strdup_printf ("%s-%s.%s", fname, gettext (extract[extract_idx].type), extension); else filename = g_strdup_printf ("%s-%s.%s", fname, gettext (extract[extract_idx].channel_name[j]), extension); } else { if (decovals.as_layers) filename = g_strdup_printf ("%s-%s", fname, gettext (extract[extract_idx].type)); else filename = g_strdup_printf ("%s-%s", fname, gettext (extract[extract_idx].channel_name[j])); } } else { filename = g_strdup (gettext (extract[extract_idx].channel_name[j])); } gimp_image_get_resolution (image_ID, &xres, &yres); if (decovals.as_layers) { layername = gettext (extract[extract_idx].channel_name[j]); if (j == 0) image_ID_dst[j] = create_new_image (filename, layername, width, height, GIMP_GRAY, xres, yres, layer_ID_dst + j, drawable_dst + j, pixel_rgn_dst + j); else layer_ID_dst[j] = create_new_layer (image_ID_dst[0], j, layername, width, height, GIMP_GRAY, drawable_dst + j, pixel_rgn_dst + j); } else { image_ID_dst[j] = create_new_image (filename, NULL, width, height, GIMP_GRAY, xres, yres, layer_ID_dst + j, drawable_dst + j, pixel_rgn_dst + j); } g_free (filename); g_free (fname); dst[j] = g_new (guchar, tile_height * width); } i = 0; while (i < height) { /* Get source pixel region */ scan_lines = (i+tile_height-1 < height) ? tile_height : (height-i); gimp_pixel_rgn_get_rect (&pixel_rgn_src, src, 0, i, width, scan_lines); /* Extract the channel information */ extract[extract_idx].extract_fun (src, drawable_src->bpp, scan_lines*width, dst); /* Transfer the registration color */ if (decovals.use_registration) transfer_registration_color (src, drawable_src->bpp, scan_lines*width, dst, extract[extract_idx].num_images); /* Set destination pixel regions */ for (j = 0; j < num_layers; j++) gimp_pixel_rgn_set_rect (&(pixel_rgn_dst[j]), dst[j], 0, i, width, scan_lines); i += scan_lines; gimp_progress_update ((gdouble) i / (gdouble) height); } g_free (src); for (j = 0; j < num_layers; j++) { gimp_drawable_detach (drawable_dst[j]); gimp_drawable_update (layer_ID_dst[j], 0, 0, gimp_drawable_width (layer_ID_dst[j]), gimp_drawable_height (layer_ID_dst[j])); gimp_layer_add_alpha (layer_ID_dst[j]); g_free (dst[j]); } gimp_drawable_detach (drawable_src); *nlayers = num_layers; return (decovals.as_layers ? 1 : num_layers); }
static gboolean pluginCore (piArgs *argp) { GimpDrawable *drw, *ndrw = NULL; GimpPixelRgn srcPr, dstPr; gboolean success = TRUE; gint nl = 0; gint y, i; gint Y, I, Q; guint width, height, bpp; gint sel_x1, sel_x2, sel_y1, sel_y2; gint prog_interval; guchar *src, *s, *dst, *d; guchar r, prev_r=0, new_r=0; guchar g, prev_g=0, new_g=0; guchar b, prev_b=0, new_b=0; gdouble fy, fc, t, scale; gdouble pr, pg, pb; gdouble py; drw = gimp_drawable_get (argp->drawable); width = drw->width; height = drw->height; bpp = drw->bpp; if (argp->new_layerp) { gchar name[40]; const gchar *mode_names[] = { "ntsc", "pal", }; const gchar *action_names[] = { "lum redux", "sat redux", "flag", }; g_snprintf (name, sizeof (name), "hot mask (%s, %s)", mode_names[argp->mode], action_names[argp->action]); nl = gimp_layer_new (argp->image, name, width, height, GIMP_RGBA_IMAGE, (gdouble)100, GIMP_NORMAL_MODE); ndrw = gimp_drawable_get (nl); gimp_drawable_fill (nl, GIMP_TRANSPARENT_FILL); gimp_image_insert_layer (argp->image, nl, -1, 0); } gimp_drawable_mask_bounds (drw->drawable_id, &sel_x1, &sel_y1, &sel_x2, &sel_y2); width = sel_x2 - sel_x1; height = sel_y2 - sel_y1; src = g_new (guchar, width * height * bpp); dst = g_new (guchar, width * height * 4); gimp_pixel_rgn_init (&srcPr, drw, sel_x1, sel_y1, width, height, FALSE, FALSE); if (argp->new_layerp) { gimp_pixel_rgn_init (&dstPr, ndrw, sel_x1, sel_y1, width, height, FALSE, FALSE); } else { gimp_pixel_rgn_init (&dstPr, drw, sel_x1, sel_y1, width, height, TRUE, TRUE); } gimp_pixel_rgn_get_rect (&srcPr, src, sel_x1, sel_y1, width, height); s = src; d = dst; build_tab (argp->mode); gimp_progress_init (_("Hot")); prog_interval = height / 10; for (y = sel_y1; y < sel_y2; y++) { gint x; if (y % prog_interval == 0) gimp_progress_update ((double) y / (double) (sel_y2 - sel_y1)); for (x = sel_x1; x < sel_x2; x++) { if (hotp (r = *(s + 0), g = *(s + 1), b = *(s + 2))) { if (argp->action == ACT_FLAG) { for (i = 0; i < 3; i++) *d++ = 0; s += 3; if (bpp == 4) *d++ = *s++; else if (argp->new_layerp) *d++ = 255; } else { /* * Optimization: cache the last-computed hot pixel. */ if (r == prev_r && g == prev_g && b == prev_b) { *d++ = new_r; *d++ = new_g; *d++ = new_b; s += 3; if (bpp == 4) *d++ = *s++; else if (argp->new_layerp) *d++ = 255; } else { Y = tab[0][0][r] + tab[0][1][g] + tab[0][2][b]; I = tab[1][0][r] + tab[1][1][g] + tab[1][2][b]; Q = tab[2][0][r] + tab[2][1][g] + tab[2][2][b]; prev_r = r; prev_g = g; prev_b = b; /* * Get Y and chroma amplitudes in floating point. * * If your C library doesn't have hypot(), just use * hypot(a,b) = sqrt(a*a, b*b); * * Then extract linear (un-gamma-corrected) * floating-point pixel RGB values. */ fy = (double)Y / (double)SCALE; fc = hypot ((double) I / (double) SCALE, (double) Q / (double) SCALE); pr = (double) pix_decode (r); pg = (double) pix_decode (g); pb = (double) pix_decode (b); /* * Reducing overall pixel intensity by scaling R, * G, and B reduces Y, I, and Q by the same factor. * This changes luminance but not saturation, since * saturation is determined by the chroma/luminance * ratio. * * On the other hand, by linearly interpolating * between the original pixel value and a grey * pixel with the same luminance (R=G=B=Y), we * change saturation without affecting luminance. */ if (argp->action == ACT_LREDUX) { /* * Calculate a scale factor that will bring the pixel * within both chroma and composite limits, if we scale * luminance and chroma simultaneously. * * The calculated chrominance reduction applies * to the gamma-corrected RGB values that are * the input to the RGB-to-YIQ operation. * Multiplying the original un-gamma-corrected * pixel values by the scaling factor raised to * the "gamma" power is equivalent, and avoids * calling gc() and inv_gc() three times each. */ scale = chroma_lim / fc; t = compos_lim / (fy + fc); if (t < scale) scale = t; scale = pow (scale, mode[argp->mode].gamma); r = (guint8) pix_encode (scale * pr); g = (guint8) pix_encode (scale * pg); b = (guint8) pix_encode (scale * pb); } else { /* ACT_SREDUX hopefully */ /* * Calculate a scale factor that will bring the * pixel within both chroma and composite * limits, if we scale chroma while leaving * luminance unchanged. * * We have to interpolate gamma-corrected RGB * values, so we must convert from linear to * gamma-corrected before interpolation and then * back to linear afterwards. */ scale = chroma_lim / fc; t = (compos_lim - fy) / fc; if (t < scale) scale = t; pr = gc (pr, argp->mode); pg = gc (pg, argp->mode); pb = gc (pb, argp->mode); py = pr * mode[argp->mode].code[0][0] + pg * mode[argp->mode].code[0][1] + pb * mode[argp->mode].code[0][2]; r = pix_encode (inv_gc (py + scale * (pr - py), argp->mode)); g = pix_encode (inv_gc (py + scale * (pg - py), argp->mode)); b = pix_encode (inv_gc (py + scale * (pb - py), argp->mode)); } *d++ = new_r = r; *d++ = new_g = g; *d++ = new_b = b; s += 3; if (bpp == 4) *d++ = *s++; else if (argp->new_layerp) *d++ = 255; } } } else { if (!argp->new_layerp) { for (i = 0; i < bpp; i++) *d++ = *s++; } else { s += bpp; d += 4; } } } } gimp_pixel_rgn_set_rect (&dstPr, dst, sel_x1, sel_y1, width, height); g_free (src); g_free (dst); if (argp->new_layerp) { gimp_drawable_flush (ndrw); gimp_drawable_update (nl, sel_x1, sel_y1, width, height); } else { gimp_drawable_flush (drw); gimp_drawable_merge_shadow (drw->drawable_id, TRUE); gimp_drawable_update (drw->drawable_id, sel_x1, sel_y1, width, height); } gimp_displays_flush (); return success; }
static PyObject * pr_subscript(PyGimpPixelRgn *self, PyObject *key) { GimpPixelRgn *pr = &(self->pr); PyObject *x, *y; Py_ssize_t x1, y1, x2, y2, xs, ys; PyObject *ret; if (!PyTuple_Check(key) || PyTuple_Size(key) != 2) { PyErr_SetString(PyExc_TypeError, "subscript must be a 2-tuple"); return NULL; } if (!PyArg_ParseTuple(key, "OO", &x, &y)) return NULL; if (PyInt_Check(x)) { x1 = PyInt_AsSsize_t(x); if (x1 < pr->x || x1 >= pr->x + pr->w) { PyErr_SetString(PyExc_IndexError, "x subscript out of range"); return NULL; } if (PyInt_Check(y)) { y1 = PyInt_AsSsize_t(y); if (y1 < pr->y || y1 >= pr->y + pr->h) { PyErr_SetString(PyExc_IndexError, "y subscript out of range"); return NULL; } ret = PyString_FromStringAndSize(NULL, pr->bpp); gimp_pixel_rgn_get_pixel(pr, (guchar*)PyString_AS_STRING(ret), x1, y1); } else if (PySlice_Check(y)) { if (PySlice_GetIndices((PySliceObject*)y, pr->y + pr->h, &y1, &y2, &ys) || y1 >= y2 || ys != 1) { PyErr_SetString(PyExc_IndexError, "invalid y slice"); return NULL; } if(y1 == 0) y1 = pr->y; if(y1 < pr->y || y2 < pr->y) { PyErr_SetString(PyExc_IndexError, "y subscript out of range"); return NULL; } ret = PyString_FromStringAndSize(NULL, pr->bpp * (y2 - y1)); gimp_pixel_rgn_get_col(pr, (guchar*)PyString_AS_STRING(ret), x1, y1, y2-y1); } else { PyErr_SetString(PyExc_TypeError, "invalid y subscript"); return NULL; } } else if (PySlice_Check(x)) { if (PySlice_GetIndices((PySliceObject *)x, pr->x + pr->w, &x1, &x2, &xs) || x1 >= x2 || xs != 1) { PyErr_SetString(PyExc_IndexError, "invalid x slice"); return NULL; } if (x1 == 0) x1 = pr->x; if(x1 < pr->x || x2 < pr->x) { PyErr_SetString(PyExc_IndexError, "x subscript out of range"); return NULL; } if (PyInt_Check(y)) { y1 = PyInt_AsSsize_t(y); if (y1 < pr->y || y1 >= pr->y + pr->h) { PyErr_SetString(PyExc_IndexError, "y subscript out of range"); return NULL; } ret = PyString_FromStringAndSize(NULL, pr->bpp * (x2 - x1)); gimp_pixel_rgn_get_row(pr, (guchar*)PyString_AS_STRING(ret), x1, y1, x2 - x1); } else if (PySlice_Check(y)) { if (PySlice_GetIndices((PySliceObject*)y, pr->y + pr->h, &y1, &y2, &ys) || y1 >= y2 || ys != 1) { PyErr_SetString(PyExc_IndexError, "invalid y slice"); return NULL; } if(y1 == 0) y1 = pr->y; if(y1 < pr->y || y2 < pr->y) { PyErr_SetString(PyExc_IndexError, "y subscript out of range"); return NULL; } ret = PyString_FromStringAndSize(NULL, pr->bpp * (x2 - x1) * (y2 - y1)); gimp_pixel_rgn_get_rect(pr, (guchar*)PyString_AS_STRING(ret), x1, y1, x2 - x1, y2 - y1); } else { PyErr_SetString(PyExc_TypeError, "invalid y subscript"); return NULL; } } else { PyErr_SetString(PyExc_TypeError, "invalid x subscript"); return NULL; } return ret; }
GimpPDBStatusType SaveICNS (const gchar *file_name, gint32 image_ID) { // Horrible awful temporary hack ResourceHeader icnsHeader; ResourceHeader it32Header; ResourceHeader t8mkHeader; guchar *compData, *alphaData; FILE *outfile; guchar *pixels; gint dataSize; if (gimp_image_base_type (image_ID) != GIMP_RGB) { if (! gimp_image_convert_rgb (image_ID)) return GIMP_PDB_EXECUTION_ERROR; } gint *layers; gint nlayers; GimpPixelRgn region; layers = gimp_image_get_layers (image_ID, &nlayers); GimpDrawable *drawable = gimp_drawable_get (layers[0]); pixels = g_new (guchar, 128*128*4); gimp_pixel_rgn_init (®ion, drawable, 0, 0, 128, 128, TRUE, FALSE); gimp_pixel_rgn_get_rect (®ion, pixels, 0, 0, 128, 128); compData = icns_compress (128, 128, pixels, &dataSize); alphaData = icns_get_alpha (128, 128, pixels); it32Header.type = GUINT32_TO_BE ('it32'); it32Header.size = GUINT32_TO_BE (sizeof (ResourceHeader) + dataSize); t8mkHeader.type = GUINT32_TO_BE ('t8mk'); t8mkHeader.size = GUINT32_TO_BE (sizeof (ResourceHeader) + 128*128); icnsHeader.type = GUINT32_TO_BE ('icns'); icnsHeader.size = dataSize + 128*128 + 3 * sizeof (ResourceHeader); outfile = fopen (file_name, "wb"); if (outfile) { fwrite (&icnsHeader, 1, sizeof (ResourceHeader), outfile); fwrite (&it32Header, 1, sizeof (ResourceHeader), outfile); fwrite (compData, 1, dataSize, outfile); fwrite (&t8mkHeader, 1, sizeof (ResourceHeader), outfile); fwrite (alphaData, 1, 128*128, outfile); fclose (outfile); } else { g_warning ("SaveICNS: couldn't open output file"); } g_free (pixels); g_free (compData); g_free (alphaData); return GIMP_PDB_SUCCESS; }
static void compose_row (gint frame_num, DisposeType dispose, gint row_num, guchar *dest, gint dest_width, GimpDrawable *drawable, gboolean cleanup) { static guchar *line_buf = NULL; guchar *srcptr; GimpPixelRgn pixel_rgn; gint rawx, rawy, rawbpp, rawwidth, rawheight; gint i; gboolean has_alpha; if (cleanup) { if (line_buf) { g_free (line_buf); line_buf = NULL; } return; } if (dispose == DISPOSE_REPLACE) { total_alpha (dest, dest_width, pixelstep); } gimp_drawable_offsets (drawable->drawable_id, &rawx, &rawy); rawheight = gimp_drawable_height (drawable->drawable_id); /* this frame has nothing to give us for this row; return */ if (row_num >= rawheight + rawy || row_num < rawy) return; rawbpp = gimp_drawable_bpp (drawable->drawable_id); rawwidth = gimp_drawable_width (drawable->drawable_id); has_alpha = gimp_drawable_has_alpha (drawable->drawable_id); if (line_buf) { g_free (line_buf); line_buf = NULL; } line_buf = g_malloc (rawwidth * rawbpp); /* Initialise and fetch the raw new frame row */ gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, row_num - rawy, rawwidth, 1, FALSE, FALSE); gimp_pixel_rgn_get_rect (&pixel_rgn, line_buf, 0, row_num - rawy, rawwidth, 1); /* render... */ srcptr = line_buf; for (i=rawx; i<rawwidth+rawx; i++) { if (i>=0 && i<dest_width) { if ((!has_alpha) || ((*(srcptr+rawbpp-1))&128)) { gint pi; for (pi = 0; pi < pixelstep-1; pi++) { dest[i*pixelstep +pi] = *(srcptr + pi); } dest[i*pixelstep + pixelstep - 1] = 255; } } srcptr += rawbpp; } }
/* ------------------------------ * gap_pview_render_f_from_image * ------------------------------ * render preview widget from image. * IMPORTANT: the image is scaled to preview size * and the visible layers in the image are merged together ! * If the supplied image shall stay unchanged, * you may use gap_pview_render_f_from_image_duplicate * * hint: call gtk_widget_queue_draw(pv_ptr->da_widget); * after this procedure to make the changes appear on screen. */ void gap_pview_render_f_from_image (GapPView *pv_ptr , gint32 image_id , gint32 flip_request , gint32 flip_status ) { gint32 layer_id; guchar *frame_data; GimpPixelRgn pixel_rgn; GimpDrawable *drawable; if(image_id < 0) { if(gap_debug) { printf("gap_pview_render_f_from_image: have no image, cant render image_id:%d\n" ,(int)image_id ); } return; } p_free_desaturated_area_data(pv_ptr); if((gimp_image_width(image_id) != pv_ptr->pv_width) || ( gimp_image_height(image_id) != pv_ptr->pv_height)) { gimp_image_scale(image_id, pv_ptr->pv_width, pv_ptr->pv_height); } /* workaround: gimp_image_merge_visible_layers * needs at least 2 layers to work without complaining * therefore add 2 full transparent dummy layers */ { gint32 l_layer_id; GimpImageBaseType l_type; l_type = gimp_image_base_type(image_id); l_type = (l_type * 2); /* convert from GimpImageBaseType to GimpImageType */ l_layer_id = gimp_layer_new(image_id, "dummy_01" , 4, 4 , l_type , 0.0 /* Opacity full transparent */ , 0 /* NORMAL */ ); gimp_image_insert_layer(image_id, l_layer_id, 0, 0); l_layer_id = gimp_layer_new(image_id, "dummy_02" , 4, 4 , l_type , 0.0 /* Opacity full transparent */ , 0 /* NORMAL */ ); gimp_image_insert_layer(image_id, l_layer_id, 0, 0); gimp_layer_resize_to_image_size(l_layer_id); } layer_id = gimp_image_merge_visible_layers (image_id, GIMP_CLIP_TO_IMAGE); drawable = gimp_drawable_get (layer_id); frame_data = g_malloc(drawable->width * drawable->height * drawable->bpp); gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0 , drawable->width, drawable->height , FALSE /* dirty */ , FALSE /* shadow */ ); gimp_pixel_rgn_get_rect (&pixel_rgn, frame_data , 0 , 0 , drawable->width , drawable->height); { gboolean frame_data_was_grabbed; frame_data_was_grabbed = gap_pview_render_f_from_buf (pv_ptr , frame_data , drawable->width , drawable->height , drawable->bpp , TRUE /* allow_grab_src_data */ , flip_request , flip_status ); if(!frame_data_was_grabbed) g_free(frame_data); gimp_drawable_detach (drawable); } } /* end gap_pview_render_f_from_image */
static void chromaunsharp (GimpPixelRgn *cPR, GimpPixelRgn *bcPR, guchar *g, guchar *bg, gint bpp, gint x1, gint y1, gint width, gint height, gdouble amount, gdouble gamma, guchar *dest) { register guchar *lab_dest = dest; guchar *c = g_new(guchar, width*height*bpp); guchar *bc = g_new(guchar, width*height*bpp); gimp_pixel_rgn_get_rect (cPR, c, x1, y1, width, height); gimp_pixel_rgn_get_rect (bcPR, bc, x1, y1, width, height); guchar *ptr[4]; ptr[0] = c; ptr[1] = bc; ptr[2] = g; ptr[3] = bg; register gint count = width*height, offset = bpp; gint i; gdouble red, green, blue; gdouble x, y, z; gdouble tl, l[4], a[4], b[4]; gdouble tx, ty, tz; gdouble ftx, fty, ftz; gdouble lambda, de, hg, deg; gdouble sixteenth = 16.0 / 116.0; while (count-- > 0) { for ( i=0; i < 4; i++ ) { // C to RGB red = *(ptr[i]+0) / 255.0; green = *(ptr[i]+1) / 255.0; blue = *(ptr[i]+2) / 255.0; //apply gamma function to convert to sRGB if ( red <=0.03928 ) red = red/12.92; else red = pow((red+0.055)/1.055,2.4); if ( green <=0.03928 ) green = green/12.92; else green = pow((green+0.055)/1.055,2.4); if ( blue <=0.03928 ) blue = blue/12.92; else blue = pow((blue+0.055)/1.055,2.4); x = 0.431 * red + 0.342 * green + 0.178 * blue; y = 0.222 * red + 0.707 * green + 0.071 * blue; z = 0.020 * red + 0.130 * green + 0.939 * blue; if (( ty = y/Yn ) > 0.008856) { tl = 116.0 * cbrt( ty ) - 16.0; fty = cbrt( ty ); } else { tl = 903.3 * ty; fty = 7.78*ty + sixteenth; } ftx = ((tx = x/Xn) > 0.008856) ? cbrt (tx) : 7.78 * tx + sixteenth; ftz = ((tz = z/Zn) > 0.008856) ? cbrt (tz) : 7.78 * tz + sixteenth; l[i] = tl; a[i] = ftx - fty; b[i] = fty - ftz; ptr[i] += offset; } // end for // Calculate lambda hg = l[2]-l[3]; de = pow(pow(l[0]-l[1],2)+pow(a[0]-a[1],2)+pow(b[0]-b[1],2),0.5); deg = pow(pow(hg,2),0.5); if ( deg == 0 ) lambda = de/0.00001; else lambda = de/deg; lambda = pow(lambda,gamma); tl = l[2] + (amount*lambda*hg); // Keep the old chromatic greyimage's channels. lab_dest[0] = CLAMP( (gint)( tl*2.5599) , 0, 255); lab_dest[1] = (guchar) (128.0 + a[2] * 635 ); lab_dest[2] = (guchar) (128.0 + b[2] * 254 ); lab_dest += offset; } g_free (c); g_free (bc); }
static void util_fillReducedBuffer (guchar *dest, gint destWidth, gint destHeight, gint destBPP, gboolean destHasAlpha, GimpDrawable *sourceDrawable, gint x0, gint y0, gint sourceWidth, gint sourceHeight) { GimpPixelRgn rgn; guchar *sourceBuffer, *reducedRowBuffer; guchar *sourceBufferPos, *reducedRowBufferPos; guchar *sourceBufferRow; gint x, y, i, yPrime; gboolean sourceHasAlpha; gint sourceBpp; gint *sourceRowOffsetLookup; if ((sourceDrawable == NULL) || (sourceWidth == 0) || (sourceHeight == 0)) { for (x = 0; x < destWidth * destHeight * destBPP; x++) dest[x] = 0; return; } sourceBpp = sourceDrawable->bpp; sourceBuffer = g_new (guchar, sourceWidth * sourceHeight * sourceBpp); reducedRowBuffer = g_new (guchar, destWidth * sourceBpp); sourceRowOffsetLookup = g_new (int, destWidth); gimp_pixel_rgn_init (&rgn, sourceDrawable, x0, y0, sourceWidth, sourceHeight, FALSE, FALSE); sourceHasAlpha = gimp_drawable_has_alpha (sourceDrawable->drawable_id); for (x = 0; x < destWidth; x++) sourceRowOffsetLookup[x] = (x * (sourceWidth - 1) / (destWidth - 1)) * sourceBpp; gimp_pixel_rgn_get_rect (&rgn, sourceBuffer, x0, y0, sourceWidth, sourceHeight); for (y = 0; y < destHeight; y++) { yPrime = y * (sourceHeight - 1) / (destHeight - 1); sourceBufferRow = &(sourceBuffer[yPrime * sourceWidth * sourceBpp]); sourceBufferPos = sourceBufferRow; reducedRowBufferPos = reducedRowBuffer; for (x = 0; x < destWidth; x++) { sourceBufferPos = sourceBufferRow + sourceRowOffsetLookup[x]; for (i = 0; i < sourceBpp; i++) reducedRowBufferPos[i] = sourceBufferPos[i]; reducedRowBufferPos += sourceBpp; } util_convertColorspace(&(dest[y * destWidth * destBPP]), destBPP, destHasAlpha, reducedRowBuffer, sourceDrawable->bpp, sourceHasAlpha, destWidth); } g_free (sourceBuffer); g_free (reducedRowBuffer); g_free (sourceRowOffsetLookup); }
static void preview_update (GimpPreview *preview) { GimpDrawable *drawable; GimpPixelRgn src_rgn; /* Source image region */ guchar *src_ptr; /* Current source pixel */ guchar *dst_ptr; /* Current destination pixel */ intneg *neg_ptr; /* Current negative pixel */ gint i; /* Looping var */ gint y; /* Current location in image */ gint width; /* Byte width of the image */ gint x1, y1; gint preview_width, preview_height; guchar *preview_src, *preview_dst; intneg *preview_neg; gint img_bpp; /* Bytes-per-pixel in image */ void (*filter)(int, guchar *, guchar *, intneg *, intneg *, intneg *); filter = NULL; compute_luts(); gimp_preview_get_position (preview, &x1, &y1); gimp_preview_get_size (preview, &preview_width, &preview_height); drawable = gimp_drawable_preview_get_drawable (GIMP_DRAWABLE_PREVIEW (preview)); img_bpp = gimp_drawable_bpp (drawable->drawable_id); preview_src = g_new (guchar, preview_width * preview_height * img_bpp); preview_neg = g_new (intneg, preview_width * preview_height * img_bpp); preview_dst = g_new (guchar, preview_width * preview_height * img_bpp); gimp_pixel_rgn_init (&src_rgn, drawable, x1, y1, preview_width, preview_height, FALSE, FALSE); width = preview_width * img_bpp; /* * Load the preview area... */ gimp_pixel_rgn_get_rect (&src_rgn, preview_src, x1, y1, preview_width, preview_height); for (i = width * preview_height, src_ptr = preview_src, neg_ptr = preview_neg; i > 0; i --) *neg_ptr++ = neg_lut[*src_ptr++]; /* * Select the filter... */ switch (img_bpp) { case 1: filter = gray_filter; break; case 2: filter = graya_filter; break; case 3: filter = rgb_filter; break; case 4: filter = rgba_filter; break; default: g_error ("Programmer stupidity error: img_bpp is %d\n", img_bpp); } /* * Sharpen... */ memcpy (preview_dst, preview_src, width); memcpy (preview_dst + width * (preview_height - 1), preview_src + width * (preview_height - 1), width); for (y = preview_height - 2, src_ptr = preview_src + width, neg_ptr = preview_neg + width + img_bpp, dst_ptr = preview_dst + width; y > 0; y --, src_ptr += width, neg_ptr += width, dst_ptr += width) (*filter)(preview_width, src_ptr, dst_ptr, neg_ptr - width, neg_ptr, neg_ptr + width); gimp_preview_draw_buffer (preview, preview_dst, preview_width * img_bpp); g_free (preview_src); g_free (preview_neg); g_free (preview_dst); }