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)); }
/* * sendBMPToGIMP * * Take the captured data and send it across * to GIMP. */ static void sendBMPToGimp(HBITMAP hBMP, HDC hDC, RECT rect) { int width, height; int imageType, layerType; gint32 image_id; gint32 layer_id; GimpPixelRgn pixel_rgn; GimpDrawable *drawable; /* Our width and height */ width = (rect.right - rect.left); height = (rect.bottom - rect.top); /* Check that we got the memory */ if (!capBytes) { g_message (_("No data captured")); return; } /* Flip the red and blue bytes */ flipRedAndBlueBytes(width, height); /* Set up the image and layer types */ imageType = GIMP_RGB; layerType = GIMP_RGB_IMAGE; /* Create the GIMP image and layers */ image_id = gimp_image_new(width, height, imageType); layer_id = gimp_layer_new(image_id, _("Background"), ROUND4(width), height, layerType, 100, GIMP_NORMAL_MODE); gimp_image_insert_layer(image_id, layer_id, -1, 0); /* Get our drawable */ drawable = gimp_drawable_get(layer_id); gimp_tile_cache_size(ROUND4(width) * gimp_tile_height() * 3); /* Initialize a pixel region for writing to the image */ gimp_pixel_rgn_init(&pixel_rgn, drawable, 0, 0, ROUND4(width), height, TRUE, FALSE); gimp_pixel_rgn_set_rect(&pixel_rgn, (guchar *) capBytes, 0, 0, ROUND4(width), height); /* HB: update data BEFORE size change */ gimp_drawable_flush(drawable); /* Now resize the layer down to the correct size if necessary. */ if (width != ROUND4(width)) { gimp_layer_resize (layer_id, width, height, 0, 0); gimp_image_resize (image_id, width, height, 0, 0); } /* Finish up */ gimp_drawable_detach(drawable); gimp_display_new (image_id); return; }
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); }
// Combine wavelets with latest FFT result and show output in the preview widget void wavelet_preview(PluginData *pd) { int x, y, w, h; gimp_preview_get_position (GIMP_PREVIEW(pd->preview), &x, &y); gimp_preview_get_size (GIMP_PREVIEW(pd->preview), &w, &h); gimp_pixel_rgn_init (&pd->region, pd->drawable, 0, 0, pd->image_width, pd->image_height, FALSE, TRUE); wavelet_apply(pd, x, y, w, h); gimp_pixel_rgn_set_rect(&pd->region, pd->img_pixels, x, y, w, h); gimp_drawable_preview_draw_region(GIMP_DRAWABLE_PREVIEW(pd->preview), &pd->region); }
void focusblur_fft_buffer_draw (FblurFftBuffer *fft) { GimpDrawablePreview *preview; gboolean dirty; guint8 *data; GimpPixelRgn pr; if (! fft->source.preview) { preview = NULL; dirty = TRUE; data = fft->source.data; } else { preview = GIMP_DRAWABLE_PREVIEW (fft->source.preview); g_assert (preview != NULL); dirty = FALSE; data = fft->source.data_preview; } g_assert (data != NULL); gimp_pixel_rgn_init (&pr, fft->source.drawable, fft->source.x1, fft->source.y1, fft->source.width, fft->source.height, dirty, TRUE); gimp_pixel_rgn_set_rect (&pr, data, fft->source.x1, fft->source.y1, fft->source.width, fft->source.height); if (! preview) { gimp_drawable_flush (fft->source.drawable); gimp_drawable_merge_shadow (fft->source.drawable->drawable_id, TRUE); gimp_drawable_update (fft->source.drawable->drawable_id, fft->source.x1, fft->source.y1, fft->source.width, fft->source.height); /* this buffer has been dirty */ focusblur_fft_buffer_clear_source (fft); } else { gimp_drawable_preview_draw_region (preview, &pr); } }
/* Draw the hole at the specified position */ static void draw_hole_rgb (GimpDrawable *drw, gint x, gint y, gint width, gint height, guchar *hole) { GimpPixelRgn rgn; guchar *data; gint tile_height = gimp_tile_height (); gint i, j, scan_lines; gint d_width = gimp_drawable_width (drw->drawable_id); gint length; if ((width <= 0) || (height <= 0)) return; if ((x+width <= 0) || (x >= d_width)) return; length = width; /* Check that we dont draw past the image */ if ((x+length) >= d_width) length = d_width-x; data = g_new (guchar, length * tile_height * drw->bpp); gimp_pixel_rgn_init (&rgn, drw, x, y, length, height, TRUE, FALSE); i = 0; while (i < height) { scan_lines = (i+tile_height-1 < height) ? tile_height : (height-i); if (length == width) { memcpy (data, hole + 3*width*i, width*scan_lines*3); } else /* We have to do some clipping */ { for (j = 0; j < scan_lines; j++) memcpy (data + j*length*3, hole + (i+j)*width*3, length*3); } gimp_pixel_rgn_set_rect (&rgn, data, x, y+i, length, scan_lines); i += scan_lines; } g_free (data); }
static gboolean file_vtf_load_layer (Vtf::HiresImageResource *vres, gint32 image, gint16 frame) { uint8_t *rgba = vres->getImageRGBA(0, frame, 0, 0); g_return_val_if_fail (rgba != NULL, FALSE); gchar *name = g_strdup_printf ("Frame %d", frame); gint32 layer = gimp_layer_new (image, name, vres->width (), vres->height(), GIMP_RGBA_IMAGE, 100, GIMP_NORMAL_MODE); gimp_image_insert_layer (image, layer, -1, frame); g_free (name); GimpPixelRgn pixel_rgn; GimpDrawable *drawable = gimp_drawable_get (layer); gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, TRUE, FALSE); gimp_pixel_rgn_set_rect (&pixel_rgn, rgba, 0, 0, drawable->width, drawable->height); gimp_drawable_detach (drawable); return TRUE; }
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); }
gint32 xjpg_load_layer (const char *filename, gint32 image_id, int image_type, char *layer_name, gdouble layer_opacity, GimpLayerModeEffects layer_mode ) { GimpPixelRgn l_pixel_rgn; GimpDrawable *l_drawable; gint32 l_layer_id; GimpImageType l_layer_type; struct jpeg_decompress_struct cinfo; struct my_error_mgr jerr; FILE *infile; guchar *l_buf; guchar **l_rowbuf; int l_tile_height; int l_scanlines; int l_idx, l_start, l_end; /* We set up the normal JPEG error routines. */ cinfo.err = jpeg_std_error (&jerr.pub); jerr.pub.error_exit = my_error_exit; l_layer_type = GIMP_GRAY_IMAGE; if ((infile = g_fopen (filename, "rb")) == NULL) { g_warning ("can't open \"%s\"\n", filename); return -1; } /* 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 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 */ 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; } /* Check jpeg file for layer type */ switch (cinfo.output_components) { case 1: l_layer_type = GIMP_GRAY_IMAGE; break; case 3: l_layer_type = GIMP_RGB_IMAGE; break; default: g_printerr ("XJT: cant load layer %s (type is not GRAY and not RGB)\n", filename); fclose (infile); return -1; } l_layer_id = gimp_layer_new (image_id, layer_name, cinfo.output_width, cinfo.output_height, l_layer_type, layer_opacity, layer_mode); if(l_layer_id < 0) { g_printerr ("XJT: cant create new layer\n"); fclose (infile); return -1; } l_drawable = gimp_drawable_get (l_layer_id); gimp_pixel_rgn_init (&l_pixel_rgn, l_drawable, 0, 0, l_drawable->width, l_drawable->height, TRUE, FALSE); /* 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_set_rect (&l_pixel_rgn, l_buf, 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); /* 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 (l_layer_id); } /* end xjpg_load_layer */
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); }
gint32 load_djvu (const gchar * filename, GimpRunMode runmode, gboolean preview) { GimpPixelRgn rgn_in; GimpDrawable *drawable; gint32 volatile image_ID; gint32 layer_ID; int x1, y1, x2, y2, width, height; unsigned char *src = NULL; int file_length; ctx = ddjvu_context_create("gimp"); // doc = ddjvu_document_create_by_filename(ctx,filename, TRUE); while (! ddjvu_document_decoding_done(doc)) handle(TRUE); i = ddjvu_document_get_pagenum(doc); dialog( &pageno ,i); //processing the page page = ddjvu_page_create_by_pageno(doc, pageno-1); while (! ddjvu_page_decoding_done(page)) handle(TRUE); if (ddjvu_page_decoding_error(page)) { fprintf(stderr,"unexpected error "); exit(10); } // ddjvu variables ddjvu_rect_t prect; ddjvu_rect_t rrect; ddjvu_format_style_t style; ddjvu_render_mode_t mode; ddjvu_format_t *fmt; int iw = ddjvu_page_get_width(page); int ih = ddjvu_page_get_height(page); int dpi = ddjvu_page_get_resolution(page); ddjvu_page_type_t type = ddjvu_page_get_type(page); char *image = 0; int rowsize; //end of ddjvu variables style= DDJVU_FORMAT_RGB24; mode=DDJVU_RENDER_COLOR; fmt = ddjvu_format_create(style, 0, 0); ddjvu_format_set_row_order(fmt, 1); prect.w = iw; prect.h = ih; prect.x = 0; prect.y = 0; flag_scale=150; prect.w = (unsigned int) (iw * flag_scale) / dpi; prect.h = (unsigned int) (ih * flag_scale) / dpi; rrect = prect; rowsize = (rrect.w *3); image = (char*)malloc(rowsize * rrect.h); //generating page ddjvu_page_render(page, mode, &prect, &rrect, fmt, rowsize, image); ddjvu_page_release(page); char *s =image; /* create output image */ width = prect.w; height = prect.h; x1 = 0; y1 = 0; x2 = prect.w; y2 = prect.h; image_ID = gimp_image_new (width, height, GIMP_RGB); layer_ID = gimp_layer_new (image_ID, _("Background"), width, height, GIMP_RGB, 100, GIMP_NORMAL_MODE); gimp_image_add_layer (image_ID, layer_ID, 0); drawable = gimp_drawable_get (layer_ID); // initializes the drawable gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); gimp_pixel_rgn_init (&rgn_in, drawable, x1, y1, x2 - x1, y2 - y1, TRUE, TRUE); gimp_pixel_rgn_set_rect (&rgn_in, image, 0, 0, width, height); //g_free (buf); gimp_drawable_flush (drawable); gimp_drawable_merge_shadow (drawable->drawable_id, TRUE); gimp_drawable_update (drawable->drawable_id, x1, y1, x2 - x1, y2 - y1); gimp_image_set_filename (image_ID, filename); return image_ID; image =NULL; //not handling any error if (doc) ddjvu_document_release(doc); if (ctx) ddjvu_context_release(ctx); }
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); }
gint32 load_image (const gchar *filename, GimpRunMode runmode, gboolean preview, GError **error) { GimpPixelRgn pixel_rgn; GimpDrawable *drawable; gint32 volatile image_ID; gint32 layer_ID; struct jpeg_decompress_struct cinfo; struct my_error_mgr jerr; jpeg_saved_marker_ptr marker; FILE *infile; guchar *buf; guchar **rowbuf; gint image_type; gint layer_type; gint tile_height; gint scanlines; gint i, start, end; #ifdef HAVE_LIBEXIF gint orientation = 0; #endif #ifdef HAVE_LCMS cmsHTRANSFORM cmyk_transform = NULL; #else gpointer cmyk_transform = NULL; #endif /* We set up the normal JPEG error routines. */ cinfo.err = jpeg_std_error (&jerr.pub); jerr.pub.error_exit = my_error_exit; if (!preview) { jerr.pub.output_message = my_output_message; } if ((infile = g_fopen (filename, "rb")) == NULL) { g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno), _("Could not open '%s' for reading: %s"), gimp_filename_to_utf8 (filename), g_strerror (errno)); return -1; } if (!preview) gimp_progress_init_printf (_("Opening '%s'"), gimp_filename_to_utf8 (filename)); image_ID = -1; /* 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); if (image_ID != -1 && !preview) gimp_image_delete (image_ID); if (preview) destroy_preview (); 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); if (! preview) { /* - step 2.1: tell the lib to save the comments */ jpeg_save_markers (&cinfo, JPEG_COM, 0xffff); /* - step 2.2: tell the lib to save APP1 data (EXIF or XMP) */ jpeg_save_markers (&cinfo, JPEG_APP0 + 1, 0xffff); /* - step 2.3: tell the lib to save APP2 data (ICC profiles) */ jpeg_save_markers (&cinfo, JPEG_APP0 + 2, 0xffff); } /* Step 3: read file parameters with jpeg_read_header() */ 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. */ /* temporary buffer */ tile_height = gimp_tile_height (); buf = g_new (guchar, tile_height * cinfo.output_width * cinfo.output_components); rowbuf = g_new (guchar *, tile_height); for (i = 0; i < tile_height; i++) rowbuf[i] = buf + cinfo.output_width * cinfo.output_components * i; switch (cinfo.output_components) { case 1: image_type = GIMP_GRAY; layer_type = GIMP_GRAY_IMAGE; break; case 3: image_type = GIMP_RGB; layer_type = GIMP_RGB_IMAGE; break; case 4: if (cinfo.out_color_space == JCS_CMYK) { image_type = GIMP_RGB; layer_type = GIMP_RGB_IMAGE; break; } /*fallthrough*/ default: g_message ("Don't know how to load JPEG images " "with %d color channels, using colorspace %d (%d).", cinfo.output_components, cinfo.out_color_space, cinfo.jpeg_color_space); return -1; break; } if (preview) { image_ID = preview_image_ID; } else { image_ID = gimp_image_new (cinfo.output_width, cinfo.output_height, image_type); gimp_image_undo_disable (image_ID); gimp_image_set_filename (image_ID, filename); } if (preview) { preview_layer_ID = gimp_layer_new (preview_image_ID, _("JPEG preview"), cinfo.output_width, cinfo.output_height, layer_type, 100, GIMP_NORMAL_MODE); layer_ID = preview_layer_ID; } else { layer_ID = gimp_layer_new (image_ID, _("Background"), cinfo.output_width, cinfo.output_height, layer_type, 100, GIMP_NORMAL_MODE); } drawable_global = drawable = gimp_drawable_get (layer_ID); gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, TRUE, FALSE); if (! preview) { GString *comment_buffer = NULL; guint8 *profile = NULL; guint profile_size = 0; #ifdef HAVE_LIBEXIF ExifData *exif_data = NULL; #endif /* Step 5.0: save the original JPEG settings in a parasite */ jpeg_detect_original_settings (&cinfo, image_ID); /* Step 5.1: check for comments, or EXIF metadata in APP1 markers */ for (marker = cinfo.marker_list; marker; marker = marker->next) { const gchar *data = (const gchar *) marker->data; gsize len = marker->data_length; if (marker->marker == JPEG_COM) { #ifdef GIMP_UNSTABLE g_print ("jpeg-load: found image comment (%d bytes)\n", marker->data_length); #endif if (! comment_buffer) { comment_buffer = g_string_new_len (data, len); } else { /* concatenate multiple comments, separate them with LF */ g_string_append_c (comment_buffer, '\n'); g_string_append_len (comment_buffer, data, len); } } else if ((marker->marker == JPEG_APP0 + 1) && (len > sizeof (JPEG_APP_HEADER_EXIF) + 8) && ! strcmp (JPEG_APP_HEADER_EXIF, data)) { #ifdef GIMP_UNSTABLE g_print ("jpeg-load: found EXIF block (%d bytes)\n", (gint) (len - sizeof (JPEG_APP_HEADER_EXIF))); #endif #ifdef HAVE_LIBEXIF if (! exif_data) exif_data = exif_data_new (); /* if there are multiple blocks, their data will be merged */ exif_data_load_data (exif_data, (unsigned char *) data, len); #endif } } #ifdef HAVE_LIBEXIF if (!jpeg_load_exif_resolution (image_ID, exif_data)) #endif jpeg_load_resolution (image_ID, &cinfo); /* if we found any comments, then make a parasite for them */ if (comment_buffer && comment_buffer->len) { GimpParasite *parasite; jpeg_load_sanitize_comment (comment_buffer->str); parasite = gimp_parasite_new ("gimp-comment", GIMP_PARASITE_PERSISTENT, strlen (comment_buffer->str) + 1, comment_buffer->str); gimp_image_attach_parasite (image_ID, parasite); gimp_parasite_free (parasite); g_string_free (comment_buffer, TRUE); } #ifdef HAVE_LIBEXIF /* if we found any EXIF block, then attach the metadata to the image */ if (exif_data) { gimp_metadata_store_exif (image_ID, exif_data); orientation = jpeg_exif_get_orientation (exif_data); exif_data_unref (exif_data); exif_data = NULL; } #endif /* Step 5.2: check for XMP metadata in APP1 markers (after EXIF) */ for (marker = cinfo.marker_list; marker; marker = marker->next) { const gchar *data = (const gchar *) marker->data; gsize len = marker->data_length; if ((marker->marker == JPEG_APP0 + 1) && (len > sizeof (JPEG_APP_HEADER_XMP) + 20) && ! strcmp (JPEG_APP_HEADER_XMP, data)) { GimpParam *return_vals; gint nreturn_vals; gchar *xmp_packet; #ifdef GIMP_UNSTABLE g_print ("jpeg-load: found XMP packet (%d bytes)\n", (gint) (len - sizeof (JPEG_APP_HEADER_XMP))); #endif xmp_packet = g_strndup (data + sizeof (JPEG_APP_HEADER_XMP), len - sizeof (JPEG_APP_HEADER_XMP)); /* FIXME: running this through the PDB is not very efficient */ return_vals = gimp_run_procedure ("plug-in-metadata-decode-xmp", &nreturn_vals, GIMP_PDB_IMAGE, image_ID, GIMP_PDB_STRING, xmp_packet, GIMP_PDB_END); if (return_vals[0].data.d_status != GIMP_PDB_SUCCESS) { g_warning ("JPEG - unable to decode XMP metadata packet"); } gimp_destroy_params (return_vals, nreturn_vals); g_free (xmp_packet); } } /* Step 5.3: check for an embedded ICC profile in APP2 markers */ jpeg_icc_read_profile (&cinfo, &profile, &profile_size); if (cinfo.out_color_space == JCS_CMYK) { cmyk_transform = jpeg_load_cmyk_transform (profile, profile_size); } else if (profile) /* don't attach the profile if we are transforming */ { GimpParasite *parasite; parasite = gimp_parasite_new ("icc-profile", GIMP_PARASITE_PERSISTENT | GIMP_PARASITE_UNDOABLE, profile_size, profile); gimp_image_attach_parasite (image_ID, parasite); gimp_parasite_free (parasite); } g_free (profile); /* Do not attach the "jpeg-save-options" parasite to the image * because this conflicts with the global defaults (bug #75398). */ } /* 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) { start = cinfo.output_scanline; end = cinfo.output_scanline + tile_height; end = MIN (end, cinfo.output_height); scanlines = end - start; for (i = 0; i < scanlines; i++) jpeg_read_scanlines (&cinfo, (JSAMPARRAY) &rowbuf[i], 1); if (cinfo.out_color_space == JCS_CMYK) jpeg_load_cmyk_to_rgb (buf, drawable->width * scanlines, cmyk_transform); gimp_pixel_rgn_set_rect (&pixel_rgn, buf, 0, start, drawable->width, scanlines); if (! preview && (cinfo.output_scanline % 32) == 0) gimp_progress_update ((gdouble) cinfo.output_scanline / (gdouble) cinfo.output_height); } /* Step 7: Finish decompression */ jpeg_finish_decompress (&cinfo); /* We can ignore the return value since suspension is not possible * with the stdio data source. */ #ifdef HAVE_LCMS if (cmyk_transform) cmsDeleteTransform (cmyk_transform); #endif /* 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 (rowbuf); g_free (buf); /* 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). */ /* Detach from the drawable and add it to the image. */ if (! preview) { gimp_progress_update (1.0); gimp_drawable_detach (drawable); } gimp_image_insert_layer (image_ID, layer_ID, -1, 0); #ifdef HAVE_LIBEXIF jpeg_exif_rotate_query (image_ID, orientation); #endif return image_ID; }
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); }
// Run the plugin static void run (const gchar *name, gint nparams, const GimpParam *param, gint *nreturn_vals, GimpParam **return_vals) { // Return values static GimpParam values[1]; gint sel_x1, sel_y1, sel_x2, sel_y2, w, h, padding; PluginData pd; GimpRunMode run_mode; GimpPDBStatusType status = GIMP_PDB_SUCCESS; *nreturn_vals = 1; *return_vals = values; if (param[0].type!= GIMP_PDB_INT32) status=GIMP_PDB_CALLING_ERROR; if (param[2].type!=GIMP_PDB_DRAWABLE) status=GIMP_PDB_CALLING_ERROR; run_mode = (GimpRunMode) param[0].data.d_int32; pd.drawable = gimp_drawable_get(param[2].data.d_drawable); gimp_drawable_mask_bounds(pd.drawable->drawable_id, &sel_x1, &sel_y1, &sel_x2, &sel_y2); pd.selection_width = sel_x2 - sel_x1; pd.selection_height = sel_y2 - sel_y1; pd.selection_offset_x = sel_x1; pd.selection_offset_y = sel_y1; pd.image_width = gimp_drawable_width(pd.drawable->drawable_id); pd.image_height = gimp_drawable_height(pd.drawable->drawable_id); pd.channel_count = gimp_drawable_bpp(pd.drawable->drawable_id); pd.point_grabbed = -1; if (run_mode == GIMP_RUN_INTERACTIVE) { // Interactive call with dialog dialog(&pd); if (pd.curve_user.count > 0) { gimp_set_data (PLUG_IN_BINARY, pd.curve_user.user_points, sizeof (GdkPoint) * pd.curve_user.count); } } else if (run_mode == GIMP_RUN_WITH_LAST_VALS) { // Read a saved curve and apply it fft_prepare(&pd); gimp_get_data(PLUG_IN_BINARY, pd.curve_user.user_points); pd.curve_user.count = gimp_get_data_size(PLUG_IN_BINARY) / sizeof (GdkPoint); gimp_pixel_rgn_init(&pd.region, pd.drawable, 0, 0, pd.image_width, pd.image_height, TRUE, TRUE); fft_apply(&pd); gimp_pixel_rgn_set_rect(&pd.region, pd.img_pixels, 0, 0, pd.image_width, pd.image_height); gimp_drawable_flush(pd.drawable); gimp_drawable_merge_shadow(pd.drawable->drawable_id, TRUE); gimp_drawable_update(pd.drawable->drawable_id, pd.selection_offset_x, pd.selection_offset_y, pd.selection_width, pd.selection_height); fft_destroy(&pd); gimp_displays_flush(); } else { status = GIMP_PDB_CALLING_ERROR; } values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = status; gimp_drawable_detach(pd.drawable); }
// Create and handle the plugin's dialog gboolean dialog(PluginData *pd) { gimp_ui_init (PLUG_IN_BINARY, FALSE); GtkWidget *dialog, *main_hbox, *hbox_buttons, *preview, *graph, *vbox, *preview_button, *preview_hd_checkbox; dialog = gimp_dialog_new ("Frequency Curves", PLUG_IN_BINARY, NULL, (GtkDialogFlags)0, gimp_standard_help_func, PLUG_IN_NAME, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); main_hbox = gtk_hbox_new (FALSE, 12); gtk_container_set_border_width (GTK_CONTAINER (main_hbox), 12); gtk_container_add (GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), main_hbox); curve_init(&pd->curve_user); curve_copy(&pd->curve_user, &pd->curve_fft); pd->preview = gimp_drawable_preview_new (pd->drawable, 0); gtk_box_pack_start (GTK_BOX (main_hbox), pd->preview, TRUE, TRUE, 0); gtk_widget_show (pd->preview); g_signal_connect_swapped (pd->preview, "invalidated", G_CALLBACK (preview_invalidated), pd); vbox = gtk_vbox_new (FALSE, 12); gtk_container_set_border_width (GTK_CONTAINER (vbox), 12); gtk_container_add (GTK_CONTAINER(main_hbox), vbox); gtk_widget_show(vbox); graph = pd->graph = gtk_drawing_area_new(); pd->graph_pixmap = NULL; gtk_widget_set_size_request (graph, GRAPH_WIDTH, GRAPH_HEIGHT); gtk_widget_set_events (graph, GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_ENTER_NOTIFY_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON1_MOTION_MASK); gtk_container_add (GTK_CONTAINER (vbox), graph); gtk_widget_show (graph); g_signal_connect (graph, "event", G_CALLBACK (graph_events), pd); hbox_buttons = gtk_hbox_new (FALSE, 12); gtk_container_set_border_width (GTK_CONTAINER (hbox_buttons), 12); gtk_container_add (GTK_CONTAINER(vbox), hbox_buttons); gtk_widget_show(hbox_buttons); preview_button = gtk_button_new_with_mnemonic ("HD _Preview"); gtk_box_pack_start (GTK_BOX (hbox_buttons), preview_button, FALSE, FALSE, 0); gtk_widget_show (preview_button); g_signal_connect (preview_button, "clicked", G_CALLBACK (preview_hd), pd); preview_hd_checkbox = gtk_check_button_new_with_label("Always preview HD"); gtk_box_pack_start (GTK_BOX (hbox_buttons), preview_hd_checkbox, FALSE, FALSE, 0); gtk_widget_show (preview_hd_checkbox); pd->do_preview_hd = FALSE; gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(preview_hd_checkbox), FALSE); g_signal_connect (preview_hd_checkbox, "toggled", G_CALLBACK (preview_hd_toggled), pd); gtk_widget_show(main_hbox); gtk_widget_show(dialog); fft_prepare(pd); histogram_generate(pd); wavelet_prepare(pd); gboolean run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK); if (run) { // set the region mode to actual writing gimp_pixel_rgn_init(&pd->region, pd->drawable, 0, 0, pd->image_width, pd->image_height, TRUE, TRUE); fft_apply(pd); gimp_pixel_rgn_set_rect(&pd->region, pd->img_pixels, 0, 0, pd->image_width, pd->image_height); // show the result gimp_drawable_flush(pd->drawable); gimp_drawable_merge_shadow(pd->drawable->drawable_id, TRUE); gimp_drawable_update(pd->drawable->drawable_id, pd->selection_offset_x, pd->selection_offset_y, pd->selection_width, pd->selection_height); gimp_displays_flush(); } fft_destroy(pd); wavelet_destroy(pd); gtk_widget_destroy (dialog); return run; }
static gint32 load_image (char *filename) { FILE *fp; gint32 image_ID = -1; gint32 layer_ID; GPixelRgn pixel_rgn; GDrawable *drawable; guchar *data; GDrawableType dtype; GImageType itype; struct stat st; int width, height, bpp=0; int i, j, k; int pelbytes, tileheight, wbytes, bsize, npels, pels, ncols, npals; int badread; gushort tmpval; if (stat (filename,&st) == -1) return -1; fp = fopen (filename, "rb"); if (!fp) return -1; bs = (bs_header_t *) g_malloc (st.st_size); fread (bs,st.st_size,1,fp); fclose (fp); if (bs->magic != BS_MAGIC) { printf("not a .bs file\n"); return -1; } gimp_get_data ("bs_width",&width); gimp_get_data ("bs_height",&height); printf("%d x %d\n",width,height); itype = RGB; dtype = RGB_IMAGE; image_ID = gimp_image_new (width, height, itype); gimp_image_set_filename (image_ID, filename); layer_ID = gimp_layer_new (image_ID, "Background", width, height, dtype, 100, NORMAL_MODE); gimp_image_add_layer (image_ID, layer_ID, 0); drawable = gimp_drawable_get (layer_ID); gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, width, height, TRUE, FALSE); data = (guchar *) g_malloc (width * height * 3); bs_init(); bs_decode_rgb24 (data,bs,width,height,0); printf ("image decoded!\n"); gimp_pixel_rgn_set_rect (&pixel_rgn, data, 0, 0, width, height); g_free (data); gimp_drawable_flush (drawable); gimp_drawable_detach (drawable); return image_ID; }
/* * 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 int pr_ass_sub(PyGimpPixelRgn *self, PyObject *v, PyObject *w) { GimpPixelRgn *pr = &(self->pr); PyObject *x, *y; const guchar *buf; Py_ssize_t len, x1, x2, xs, y1, y2, ys; if (w == NULL) { PyErr_SetString(PyExc_TypeError, "can't delete subscripts"); return -1; } if (!PyString_Check(w)) { PyErr_SetString(PyExc_TypeError, "must assign string to subscript"); return -1; } if (!PyTuple_Check(v) || PyTuple_Size(v) != 2) { PyErr_SetString(PyExc_TypeError, "subscript must be a 2-tuple"); return -1; } if (!PyArg_ParseTuple(v, "OO", &x, &y)) return -1; buf = (const guchar *)PyString_AsString(w); len = PyString_Size(w); if (!buf || len > INT_MAX) { return -1; } 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 -1; } 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 -1; } if (len != pr->bpp) { PyErr_SetString(PyExc_TypeError, "string is wrong length"); return -1; } gimp_pixel_rgn_set_pixel(pr, buf, 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 -1; } if (y1 == 0) y1 = pr->y; if(y1 < pr->y || y2 < pr->y) { PyErr_SetString(PyExc_IndexError, "y subscript out of range"); return -1; } if (len != pr->bpp * (y2 - y1)) { PyErr_SetString(PyExc_TypeError, "string is wrong length"); return -1; } gimp_pixel_rgn_set_col(pr, buf, x1, y1, y2 - y1); } else { PyErr_SetString(PyExc_IndexError,"invalid y subscript"); return -1; } } 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 -1; } if(x1 == 0) x1 = pr->x; if(x1 < pr->x || x2 < pr->x) { PyErr_SetString(PyExc_IndexError, "x subscript out of range"); return -1; } 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 -1; } if (len != pr->bpp * (x2 - x1)) { PyErr_SetString(PyExc_TypeError, "string is wrong length"); return -1; } gimp_pixel_rgn_set_row(pr, buf, 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 -1; } if (y1 == 0) y1 = pr->y; if(y1 < pr->y || y2 < pr->y) { PyErr_SetString(PyExc_IndexError, "y subscript out of range"); return -1; } if (len != pr->bpp * (x2 - x1) * (y2 - y1)) { PyErr_SetString(PyExc_TypeError, "string is wrong length"); return -1; } gimp_pixel_rgn_set_rect(pr, buf, x1, y1, x2 - x1, y2 - y1); } else { PyErr_SetString(PyExc_IndexError,"invalid y subscript"); return -1; } } else { PyErr_SetString(PyExc_TypeError, "invalid x subscript"); return -1; } return 0; }
void ptRun(const gchar* Name, gint NrParameters, const GimpParam* Parameter, gint *nreturn_vals, GimpParam **return_vals) { printf("(%s,%d) '%s'\n",__FILE__,__LINE__,__PRETTY_FUNCTION__); printf("Name : '%s'\n",Name); printf("NrParameters : %d\n",NrParameters); if (!strcmp(Name,"photivoSendToGimp")) { printf("RunMode : %d\n",Parameter[0].data.d_int32); printf("FileName1 : '%s'\n",Parameter[1].data.d_string); printf("FileName2 : '%s'\n",Parameter[2].data.d_string); QFile GimpFile(Parameter[1].data.d_string); bool result = GimpFile.open(QIODevice::ReadOnly | QIODevice::Text); assert(result); QTextStream In(&GimpFile); QString ImageFileName = In.readLine(); QString ExifFileName = In.readLine(); QString ICCFileName = In.readLine(); // Read image FILE *InputFile = fopen(ImageFileName.toLocal8Bit().data(),"rb"); if (!InputFile) { ptLogError(1,ImageFileName.toLocal8Bit().data()); return; // ptError_FileOpen; } short Colors; unsigned short Width; unsigned short Height; unsigned short BitsPerColor; char Buffer[128]; // Extremely naive. Probably just enough for testcases. char *s = fgets(Buffer,127,InputFile); assert ( s ); int n = sscanf(Buffer,"P%hd",&Colors); assert ( 1 == n ); assert(Colors == 6 ); do { s = fgets(Buffer,127,InputFile); assert ( s ); } while (Buffer[0] == '#'); sscanf(Buffer,"%hd %hd",&Width,&Height); s = fgets(Buffer,127,InputFile); assert ( s ); sscanf(Buffer,"%hd",&BitsPerColor); assert(BitsPerColor == 0xffff); Colors = 3; unsigned short (* ImageForGimp)[3] = (unsigned short (*)[3]) CALLOC2(Width*Height,sizeof(*ImageForGimp)); ptMemoryError(ImageForGimp,__FILE__,__LINE__); unsigned short* PpmRow = (unsigned short *) CALLOC2(Width*Height,sizeof(*PpmRow)); ptMemoryError(PpmRow,__FILE__,__LINE__); for (unsigned short Row=0; Row<Height; Row++) { size_t RV = fread(PpmRow,Colors*2,Width,InputFile); if (RV != (size_t) Width) { printf("ReadPpm error. Expected %d bytes. Got %d\n",Width,(int)RV); exit(EXIT_FAILURE); } if (htons(0x55aa) != 0x55aa) { swab((char *)PpmRow,(char *)PpmRow,Width*Colors*2); } for (unsigned short Col=0; Col<Width; Col++) { for (short c=0;c<3;c++) { ImageForGimp[Row*Width+Col][c] = PpmRow[Col*Colors+c]; } } } FREE2(PpmRow); FCLOSE(InputFile); QFile ExifFile(ExifFileName); result = ExifFile.open(QIODevice::ReadOnly); assert(result); qint64 FileSize = ExifFile.size(); QDataStream ExifIn(&ExifFile); char* ExifBuffer = (char *) MALLOC2(FileSize); ptMemoryError(ExifBuffer,__FILE__,__LINE__); unsigned ExifBufferLength = ExifIn.readRawData(ExifBuffer,FileSize); ExifFile.close(); QFile ICCFile(ICCFileName); result = ICCFile.open(QIODevice::ReadOnly); assert(result); qint64 FileSize2 = ICCFile.size(); QDataStream ICCIn(&ICCFile); char* ICCBuffer = (char *) MALLOC2(FileSize2); ptMemoryError(ICCBuffer,__FILE__,__LINE__); unsigned ICCBufferLength = ICCIn.readRawData(ICCBuffer,FileSize2); ICCFile.close(); // And now copy to gimp. gint32 GimpImage = gimp_image_new(Width, Height, GIMP_RGB); assert (GimpImage != -1); gint32 GimpLayer = gimp_layer_new(GimpImage, "BG", Width, Height, GIMP_RGB_IMAGE, 100.0, GIMP_NORMAL_MODE); #if GIMP_MINOR_VERSION<=6 gimp_image_add_layer(GimpImage,GimpLayer,0); #else gimp_image_insert_layer(GimpImage,GimpLayer,0,0); #endif GimpDrawable* Drawable = gimp_drawable_get(GimpLayer); GimpPixelRgn PixelRegion; gimp_pixel_rgn_init(&PixelRegion, Drawable, 0, 0, Drawable->width, Drawable->height, true, false); unsigned short TileHeight = gimp_tile_height(); for (unsigned short Row=0; Row<Height; Row+=TileHeight) { unsigned short NrRows = MIN(Height-Row, (int)TileHeight); guint8* Buffer = g_new(guint8,TileHeight*Width*3); for (unsigned short i=0; i<NrRows; i++) { for (unsigned short j=0; j<Width; j++) { for (short c=0;c<3;c++) { Buffer[3*(i*Width+j)+c] = ImageForGimp[(Row+i)*Width+j][c]>>8; } } } gimp_pixel_rgn_set_rect(&PixelRegion, Buffer, 0, Row, Width, NrRows); g_free(Buffer); } gimp_drawable_flush(Drawable); gimp_drawable_detach(Drawable); FREE2(ImageForGimp); GimpParasite* GimpExifData = gimp_parasite_new("exif-data", GIMP_PARASITE_PERSISTENT, ExifBufferLength, ExifBuffer); gimp_image_parasite_attach(GimpImage,GimpExifData); gimp_parasite_free(GimpExifData); FREE2(ExifBuffer); GimpParasite* GimpICCData = gimp_parasite_new("icc-profile", GIMP_PARASITE_PERSISTENT, ICCBufferLength, ICCBuffer); gimp_image_parasite_attach(GimpImage,GimpICCData); gimp_parasite_free(GimpICCData); FREE2(ICCBuffer); static GimpParam Values[2]; *nreturn_vals = 2; *return_vals = Values; Values[0].type = GIMP_PDB_STATUS; Values[0].data.d_status = GIMP_PDB_SUCCESS; Values[1].type = GIMP_PDB_IMAGE; Values[1].data.d_image = GimpImage; QFile::remove(ImageFileName); QFile::remove(ExifFileName); QFile::remove(ICCFileName); QFile::remove(Parameter[1].data.d_string); }
static gint32 ReadImage (FILE *fd, const gchar *filename, gint len, gint height, CMap cmap, gint ncols, gint format, gint interlace, gint number, guint leftpos, guint toppos, guint screenwidth, guint screenheight) { static gint32 image_ID = -1; static gint frame_number = 1; gint32 layer_ID; GimpPixelRgn pixel_rgn; GimpDrawable *drawable; guchar *dest, *temp; guchar c; gint xpos = 0, ypos = 0, pass = 0; gint cur_progress, max_progress; gint v; gint i, j; gchar *framename; gchar *framename_ptr; gboolean alpha_frame = FALSE; static gint previous_disposal; /* Guard against bogus frame size */ if (len < 1 || height < 1) { g_message ("Bogus frame dimensions"); return -1; } /* ** Initialize the Compression routines */ if (! ReadOK (fd, &c, 1)) { g_message ("EOF / read error on image data"); return -1; } if (LZWReadByte (fd, TRUE, c) < 0) { g_message ("Error while reading"); return -1; } if (frame_number == 1) { /* Guard against bogus logical screen size values */ if (screenwidth == 0) screenwidth = len; if (screenheight == 0) screenheight = height; image_ID = gimp_image_new (screenwidth, screenheight, GIMP_INDEXED); gimp_image_set_filename (image_ID, filename); for (i = 0, j = 0; i < ncols; i++) { used_cmap[0][i] = gimp_cmap[j++] = cmap[0][i]; used_cmap[1][i] = gimp_cmap[j++] = cmap[1][i]; used_cmap[2][i] = gimp_cmap[j++] = cmap[2][i]; } gimp_image_set_colormap (image_ID, gimp_cmap, ncols); if (Gif89.delayTime < 0) framename = g_strdup (_("Background")); else framename = g_strdup_printf (_("Background (%d%s)"), 10 * Gif89.delayTime, "ms"); previous_disposal = Gif89.disposal; if (Gif89.transparent == -1) { layer_ID = gimp_layer_new (image_ID, framename, len, height, GIMP_INDEXED_IMAGE, 100, GIMP_NORMAL_MODE); } else { layer_ID = gimp_layer_new (image_ID, framename, len, height, GIMP_INDEXEDA_IMAGE, 100, GIMP_NORMAL_MODE); alpha_frame=TRUE; } g_free (framename); } else /* NOT FIRST FRAME */ { gimp_progress_set_text_printf (_("Opening '%s' (frame %d)"), gimp_filename_to_utf8 (filename), frame_number); gimp_progress_pulse (); /* If the colourmap is now different, we have to promote to RGB! */ if (! promote_to_rgb) { for (i = 0; i < ncols; i++) { if ((used_cmap[0][i] != cmap[0][i]) || (used_cmap[1][i] != cmap[1][i]) || (used_cmap[2][i] != cmap[2][i])) { /* Everything is RGB(A) from now on... sigh. */ promote_to_rgb = TRUE; /* Promote everything we have so far into RGB(A) */ #ifdef GIFDEBUG g_print ("GIF: Promoting image to RGB...\n"); #endif gimp_image_convert_rgb (image_ID); break; } } } if (Gif89.delayTime < 0) framename = g_strdup_printf (_("Frame %d"), frame_number); else framename = g_strdup_printf (_("Frame %d (%d%s)"), frame_number, 10 * Gif89.delayTime, "ms"); switch (previous_disposal) { case 0x00: break; /* 'don't care' */ case 0x01: framename_ptr = framename; framename = g_strconcat (framename, " (combine)", NULL); g_free (framename_ptr); break; case 0x02: framename_ptr = framename; framename = g_strconcat (framename, " (replace)", NULL); g_free (framename_ptr); break; case 0x03: /* Rarely-used, and unhandled by many loaders/players (including GIMP: we treat as 'combine' mode). */ framename_ptr = framename; framename = g_strconcat (framename, " (combine) (!)", NULL); g_free (framename_ptr); break; case 0x04: /* I've seen a composite of this type. stvo_online_banner2.gif */ case 0x05: case 0x06: /* I've seen a composite of this type. bn31.Gif */ case 0x07: framename_ptr = framename; framename = g_strconcat (framename, " (unknown disposal)", NULL); g_free (framename_ptr); g_message (_("GIF: Undocumented GIF composite type %d is " "not handled. Animation might not play or " "re-save perfectly."), previous_disposal); break; default: g_message ("Disposal word got corrupted. Bug."); break; } previous_disposal = Gif89.disposal; layer_ID = gimp_layer_new (image_ID, framename, len, height, promote_to_rgb ? GIMP_RGBA_IMAGE : GIMP_INDEXEDA_IMAGE, 100, GIMP_NORMAL_MODE); alpha_frame = TRUE; g_free (framename); } frame_number++; gimp_image_insert_layer (image_ID, layer_ID, -1, 0); gimp_layer_translate (layer_ID, (gint) leftpos, (gint) toppos); drawable = gimp_drawable_get (layer_ID); cur_progress = 0; max_progress = height; if (alpha_frame) dest = (guchar *) g_malloc (len * height * (promote_to_rgb ? 4 : 2)); else dest = (guchar *) g_malloc (len * height); #ifdef GIFDEBUG g_print ("GIF: reading %d by %d%s GIF image, ncols=%d\n", len, height, interlace ? " interlaced" : "", ncols); #endif if (! alpha_frame && promote_to_rgb) { /* I don't see how one would easily construct a GIF in which this could happen, but it's a mad mad world. */ g_message ("Ouch! Can't handle non-alpha RGB frames.\n" "Please file a bug report in GIMP's bugzilla."); gimp_quit (); } while ((v = LZWReadByte (fd, FALSE, c)) >= 0) { if (alpha_frame) { if (((guchar) v > highest_used_index) && !(v == Gif89.transparent)) highest_used_index = (guchar) v; if (promote_to_rgb) { temp = dest + ( (ypos * len) + xpos ) * 4; *(temp ) = (guchar) cmap[0][v]; *(temp+1) = (guchar) cmap[1][v]; *(temp+2) = (guchar) cmap[2][v]; *(temp+3) = (guchar) ((v == Gif89.transparent) ? 0 : 255); } else { temp = dest + ( (ypos * len) + xpos ) * 2; *temp = (guchar) v; *(temp+1) = (guchar) ((v == Gif89.transparent) ? 0 : 255); } } else { if ((guchar) v > highest_used_index) highest_used_index = (guchar) v; temp = dest + (ypos * len) + xpos; *temp = (guchar) v; } xpos++; if (xpos == len) { xpos = 0; if (interlace) { switch (pass) { case 0: case 1: ypos += 8; break; case 2: ypos += 4; break; case 3: ypos += 2; break; } if (ypos >= height) { pass++; switch (pass) { case 1: ypos = 4; break; case 2: ypos = 2; break; case 3: ypos = 1; break; default: goto fini; } } } else { ypos++; } if (frame_number == 1) { cur_progress++; if ((cur_progress % 16) == 0) gimp_progress_update ((gdouble) cur_progress / (gdouble) max_progress); } } if (ypos >= height) break; } fini: if (LZWReadByte (fd, FALSE, c) >= 0) g_print ("GIF: too much input data, ignoring extra...\n"); gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, TRUE, FALSE); gimp_pixel_rgn_set_rect (&pixel_rgn, dest, 0, 0, drawable->width, drawable->height); g_free (dest); gimp_drawable_flush (drawable); gimp_drawable_detach (drawable); return image_ID; }
gint32 load_thumbnail_image (const gchar *filename, gint *width, gint *height, GError **error) { gint32 volatile image_ID; ExifData *exif_data; GimpPixelRgn pixel_rgn; GimpDrawable *drawable; gint32 layer_ID; struct jpeg_decompress_struct cinfo; struct my_error_mgr jerr; guchar *buf; guchar **rowbuf; gint image_type; gint layer_type; gint tile_height; gint scanlines; gint i, start, end; gint orientation; my_src_ptr src; FILE *infile; image_ID = -1; exif_data = jpeg_exif_data_new_from_file (filename, NULL); if (! ((exif_data) && (exif_data->data) && (exif_data->size > 0))) return -1; orientation = jpeg_exif_get_orientation (exif_data); cinfo.err = jpeg_std_error (&jerr.pub); jerr.pub.error_exit = my_error_exit; jerr.pub.output_message = my_output_message; gimp_progress_init_printf (_("Opening thumbnail for '%s'"), gimp_filename_to_utf8 (filename)); /* 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 (image_ID != -1) gimp_image_delete (image_ID); if (exif_data) { exif_data_unref (exif_data); exif_data = NULL; } return -1; } /* Now we can initialize the JPEG decompression object. */ jpeg_create_decompress (&cinfo); /* Step 2: specify data source (eg, a file) */ if (cinfo.src == NULL) cinfo.src = (struct jpeg_source_mgr *)(*cinfo.mem->alloc_small) ((j_common_ptr) &cinfo, JPOOL_PERMANENT, sizeof (my_source_mgr)); src = (my_src_ptr) cinfo.src; src->pub.init_source = init_source; src->pub.fill_input_buffer = fill_input_buffer; src->pub.skip_input_data = skip_input_data; src->pub.resync_to_restart = jpeg_resync_to_restart; src->pub.term_source = term_source; src->pub.bytes_in_buffer = exif_data->size; src->pub.next_input_byte = exif_data->data; src->buffer = exif_data->data; src->size = exif_data->size; /* Step 3: read file parameters with jpeg_read_header() */ jpeg_read_header (&cinfo, TRUE); /* 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 */ tile_height = gimp_tile_height (); buf = g_new (guchar, tile_height * cinfo.output_width * cinfo.output_components); rowbuf = g_new (guchar *, tile_height); for (i = 0; i < tile_height; i++) rowbuf[i] = buf + cinfo.output_width * cinfo.output_components * i; /* Create a new image of the proper size and associate the * filename with it. */ switch (cinfo.output_components) { case 1: image_type = GIMP_GRAY; layer_type = GIMP_GRAY_IMAGE; break; case 3: image_type = GIMP_RGB; layer_type = GIMP_RGB_IMAGE; break; case 4: if (cinfo.out_color_space == JCS_CMYK) { image_type = GIMP_RGB; layer_type = GIMP_RGB_IMAGE; break; } /*fallthrough*/ default: g_message ("Don't know how to load JPEG images " "with %d color channels, using colorspace %d (%d).", cinfo.output_components, cinfo.out_color_space, cinfo.jpeg_color_space); if (exif_data) { exif_data_unref (exif_data); exif_data = NULL; } return -1; break; } image_ID = gimp_image_new (cinfo.output_width, cinfo.output_height, image_type); gimp_image_undo_disable (image_ID); gimp_image_set_filename (image_ID, filename); jpeg_load_resolution (image_ID, &cinfo); layer_ID = gimp_layer_new (image_ID, _("Background"), cinfo.output_width, cinfo.output_height, layer_type, 100, GIMP_NORMAL_MODE); drawable_global = drawable = gimp_drawable_get (layer_ID); gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, drawable->width, drawable->height, TRUE, FALSE); /* 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) { start = cinfo.output_scanline; end = cinfo.output_scanline + tile_height; end = MIN (end, cinfo.output_height); scanlines = end - start; for (i = 0; i < scanlines; i++) jpeg_read_scanlines (&cinfo, (JSAMPARRAY) &rowbuf[i], 1); if (cinfo.out_color_space == JCS_CMYK) jpeg_load_cmyk_to_rgb (buf, drawable->width * scanlines, NULL); gimp_pixel_rgn_set_rect (&pixel_rgn, buf, 0, start, drawable->width, scanlines); gimp_progress_update ((gdouble) cinfo.output_scanline / (gdouble) cinfo.output_height); } /* 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 (rowbuf); g_free (buf); /* At this point you may want to check to see whether any * corrupt-data warnings occurred (test whether * jerr.num_warnings is nonzero). */ gimp_image_insert_layer (image_ID, layer_ID, -1, 0); /* NOW to get the dimensions of the actual image to return the * calling app */ cinfo.err = jpeg_std_error (&jerr.pub); jerr.pub.error_exit = my_error_exit; jerr.pub.output_message = my_output_message; if ((infile = g_fopen (filename, "rb")) == NULL) { g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno), _("Could not open '%s' for reading: %s"), gimp_filename_to_utf8 (filename), g_strerror (errno)); if (exif_data) { exif_data_unref (exif_data); exif_data = NULL; } return -1; } /* 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 (image_ID != -1) gimp_image_delete (image_ID); if (exif_data) { exif_data_unref (exif_data); exif_data = NULL; } 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() */ jpeg_read_header (&cinfo, TRUE); jpeg_start_decompress (&cinfo); *width = cinfo.output_width; *height = cinfo.output_height; /* Step 4: Release JPEG decompression object */ /* This is an important step since it will release a good deal * of memory. */ jpeg_destroy_decompress (&cinfo); fclose (infile); if (exif_data) { exif_data_unref (exif_data); exif_data = NULL; } jpeg_exif_rotate (image_ID, orientation); return image_ID; }
static void run ( const gchar *name, gint nparams, const GimpParam *param, gint *nreturn_vals, GimpParam **return_vals) { static GimpParam values[3]; GimpRunMode run_mode; GimpPDBStatusType status = GIMP_PDB_SUCCESS; SeparateContext mysc; //enum separate_function func = SEP_NONE; run_mode = param[0].data.d_int32; /* setup for localization */ INIT_I18N (); cmsErrorAction( LCMS_ERROR_IGNORE ); mysc.filename = NULL; if( nparams != ( run_mode == GIMP_RUN_NONINTERACTIVE ? 2 : 1 ) ) status = GIMP_PDB_CALLING_ERROR; else if( run_mode == GIMP_RUN_NONINTERACTIVE ) { if( param[1].type != GIMP_PDB_STRING || strlen( param[1].data.d_string ) == 0 ) status = GIMP_PDB_CALLING_ERROR; else mysc.filename = g_strdup( param[1].data.d_string ); } else { gint size = gimp_get_data_size( "plug-in-separate-import/lastpath" ); if( size ) { mysc.filename = g_malloc( size ); gimp_get_data( "plug-in-separate-import/lastpath", mysc.filename ); } } if( status == GIMP_PDB_SUCCESS && ( run_mode == GIMP_RUN_NONINTERACTIVE || separate_import_dialog( &mysc ) ) ) { gint i, j, x, y; TIFF *in; guint32 width, height, stripSize, stripCount, stripHeight; gint16 bps, spp, step, planerConfig, photometric, inkset, resolutionUnit; float xres, yres; const gchar *layerNames[] = { "C", "M", "Y", "K" }; guchar *buf, *maskbuf[4], *srcbuf, *destbuf[4], *iccProfile; gint32 layers[5], masks[4]; GimpDrawable *drw[4]; GimpPixelRgn rgn[4]; GimpRGB primaries[4] = { { .180, .541, .870, 1.0 }, { .925, .149, .388, 1.0 }, { .929, .862, .129, 1.0 }, { 0, 0, 0, 1.0 } }; gchar *str = NULL; gchar *baseName = g_path_get_basename( gimp_filename_to_utf8( mysc.filename ) ); #ifdef G_OS_WIN32 { gchar *_filename = NULL; // win32 filename encoding(not UTF-8) _filename = g_win32_locale_filename_from_utf8( mysc.filename ); in = TIFFOpen( _filename ? _filename : mysc.filename, "r" ); g_free( _filename ); } #else in = TIFFOpen( mysc.filename, "r" ); #endif if( !in ) { str = g_strdup_printf( _( "Cannot open : \"%s\"" ), baseName ); gimp_message( str ); g_free( str ); status = GIMP_PDB_EXECUTION_ERROR; } else { if( ( TIFFGetField( in, TIFFTAG_BITSPERSAMPLE, &bps ) == FALSE || ( bps != 8 && bps != 16 ) ) || ( TIFFGetField( in, TIFFTAG_SAMPLESPERPIXEL, &spp ) == FALSE || spp != 4 ) || ( TIFFGetField( in, TIFFTAG_PHOTOMETRIC, &photometric ) == FALSE || photometric != PHOTOMETRIC_SEPARATED ) || ( TIFFGetField( in, TIFFTAG_PLANARCONFIG, &planerConfig ) == FALSE || planerConfig != PLANARCONFIG_CONTIG ) || ( TIFFGetField( in, TIFFTAG_INKSET, &inkset ) == TRUE && inkset != INKSET_CMYK ) ) { str = g_strdup_printf( _( "\"%s\" is unsupported." ), baseName ); gimp_message( str ); g_free( str ); status = GIMP_PDB_EXECUTION_ERROR; } else { stripCount = TIFFNumberOfStrips( in ); stripSize = TIFFStripSize( in ); TIFFGetField( in, TIFFTAG_IMAGEWIDTH, &width ); TIFFGetField( in, TIFFTAG_IMAGELENGTH, &height ); TIFFGetField( in, TIFFTAG_ROWSPERSTRIP, &stripHeight ); TIFFGetField( in, TIFFTAG_RESOLUTIONUNIT, &resolutionUnit ); TIFFGetField( in, TIFFTAG_XRESOLUTION, &xres ); TIFFGetField( in, TIFFTAG_YRESOLUTION, &yres ); #if 0 str = g_strdup_printf( "Photometric : %d BPS : %d SPP : %d\nInkset : %d StripCount : %d", photometric, bps, spp, inkset, stripCount ); gimp_message( str ); g_free( str ); #endif step = ( bps == 16 ) ? 2 : 1; buf = g_malloc( stripSize ); values[1].data.d_image = gimp_image_new( width, height, GIMP_RGB ); gimp_image_set_resolution( values[1].data.d_image, xres, yres ); gimp_context_push(); for( i = 0; i < 4; i++ ) { layers[i] = gimp_layer_new( values[1].data.d_image, layerNames[i], width, height, GIMP_RGBA_IMAGE, 100.0, GIMP_DARKEN_ONLY_MODE ); gimp_context_set_foreground( &primaries[i] ); gimp_drawable_fill( layers[i], GIMP_FOREGROUND_FILL ); gimp_image_add_layer( values[1].data.d_image, layers[i], i ); masks[i] = gimp_layer_create_mask( layers[i], GIMP_ADD_BLACK_MASK ); gimp_layer_add_mask( layers[i], masks[i] ); drw[i] = gimp_drawable_get( masks[i] ); maskbuf[i] = g_malloc( width * stripHeight ); } gimp_context_pop(); layers[4] = gimp_layer_new( values[1].data.d_image, _( "Background" ), width, height, GIMP_RGB_IMAGE, 100.0, GIMP_NORMAL_MODE ); gimp_drawable_fill( layers[4], GIMP_WHITE_FILL ); gimp_image_add_layer( values[1].data.d_image, layers[4], 4 ); str = g_strdup_printf( _( "Reading \"%s\"..." ), baseName ); gimp_progress_init( str ); g_free( str ); for( i = 0; i < stripCount; i++ ) { guint32 size = TIFFReadEncodedStrip( in, i, buf, stripSize ); guint32 rowCount = ( size < stripSize ? height % stripHeight : stripHeight ); srcbuf = buf; if( bps == 16 ) srcbuf++; for( j = 0; j < 4; j++ ) { gimp_pixel_rgn_init( &( rgn[j] ), drw[j], 0, stripHeight * i, width, rowCount, FALSE, FALSE ); destbuf[j] = maskbuf[j]; } for( y = 0; y < rowCount; y++ ) { for( x = 0; x < width; x++ ) { *destbuf[0]++ = *srcbuf; srcbuf += step; *destbuf[1]++ = *srcbuf; srcbuf += step; *destbuf[2]++ = *srcbuf; srcbuf += step; *destbuf[3]++ = *srcbuf; srcbuf += step; //srcbuf += spp > 4 ? spp - 4 : 0; } } gimp_pixel_rgn_set_rect( &( rgn[0] ), maskbuf[0], 0, stripHeight * i, width, rowCount ); gimp_pixel_rgn_set_rect( &( rgn[1] ), maskbuf[1], 0, stripHeight * i, width, rowCount ); gimp_pixel_rgn_set_rect( &( rgn[2] ), maskbuf[2], 0, stripHeight * i, width, rowCount ); gimp_pixel_rgn_set_rect( &( rgn[3] ), maskbuf[3], 0, stripHeight * i, width, rowCount ); gimp_progress_update( (gdouble)i / stripCount ); } g_free( buf ); for( i = 0; i < 4; i++ ) { g_free( maskbuf[i] ); gimp_drawable_detach( drw[i] ); } #ifdef ENABLE_COLOR_MANAGEMENT if ( TIFFGetField( in, TIFFTAG_ICCPROFILE, &width, &iccProfile ) ) { GimpParasite *parasite; parasite = gimp_parasite_new( CMYKPROFILE, 0, width, iccProfile ); gimp_image_parasite_attach( values[1].data.d_image, parasite ); gimp_parasite_free( parasite ); //g_free( iccProfile ); // This causes clash on TIFFClose( in ). } #endif } TIFFClose( in ); } g_free( baseName ); } else status = GIMP_PDB_CANCEL; *return_vals = values; values[0].type = GIMP_PDB_STATUS; values[0].data.d_status = status; if( status == GIMP_PDB_SUCCESS ) { *nreturn_vals = 2; values[1].type = GIMP_PDB_IMAGE; if( run_mode != GIMP_RUN_NONINTERACTIVE ) { gimp_image_undo_enable( values[1].data.d_image ); gimp_display_new( values[1].data.d_image ); gimp_displays_flush(); } gimp_set_data( "plug-in-separate-import/lastpath", mysc.filename, strlen( mysc.filename ) + 1 ); } else *nreturn_vals = 1; g_free( mysc.filename ); }
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); }
/* Create a layer with the provided image data and add it to the image */ gboolean create_layer(gint32 image_ID, uint8_t *layer_data, gint32 position, gchar *name, gint width, gint height, gint32 offsetx, gint32 offsety) { gint32 layer_ID; #ifdef GIMP_2_9 GeglBuffer *geglbuffer; GeglRectangle extent; #else GimpDrawable *drawable; GimpPixelRgn region; #endif layer_ID = gimp_layer_new(image_ID, name, width, height, GIMP_RGBA_IMAGE, 100, GIMP_NORMAL_MODE); #ifdef GIMP_2_9 /* Retrieve the buffer for the layer */ geglbuffer = gimp_drawable_get_buffer(layer_ID); /* Copy the image data to the region */ gegl_rectangle_set(&extent, 0, 0, width, height); gegl_buffer_set(geglbuffer, &extent, 0, NULL, layer_data, GEGL_AUTO_ROWSTRIDE); /* Flush the drawable and detach */ gegl_buffer_flush(geglbuffer); g_object_unref(geglbuffer); #else /* Retrieve the drawable for the layer */ drawable = gimp_drawable_get(layer_ID); /* Get a pixel region from the layer */ gimp_pixel_rgn_init(®ion, drawable, 0, 0, width, height, FALSE, FALSE); /* Copy the image data to the region */ gimp_pixel_rgn_set_rect(®ion, layer_data, 0, 0, width, height); /* Flush the drawable and detach */ gimp_drawable_flush(drawable); gimp_drawable_detach(drawable); #endif /* Add the new layer to the image */ gimp_image_insert_layer(image_ID, layer_ID, -1, position); /* If layer offsets were provided, use them to position the image */ if (offsetx || offsety) { gimp_layer_set_offsets(layer_ID, offsetx, offsety); } /* TODO: fix this */ return TRUE; }