static void bilateral_filter (GeglBuffer *src, const GeglRectangle *src_rect, GeglBuffer *dst, const GeglRectangle *dst_rect, gint s_sigma, gfloat r_sigma) { gint c, x, y, z, k, i; const gint padding_xy = 2; const gint padding_z = 2; const gint width = src_rect->width; const gint height = src_rect->height; const gint channels = 4; const gint sw = (width -1) / s_sigma + 1 + (2 * padding_xy); const gint sh = (height-1) / s_sigma + 1 + (2 * padding_xy); const gint depth = (int)(1.0f / r_sigma) + 1 + (2 * padding_z); /* down-sampling */ gfloat *grid = g_new0 (gfloat, sw * sh * depth * channels * 2); gfloat *blurx = g_new0 (gfloat, sw * sh * depth * channels * 2); gfloat *blury = g_new0 (gfloat, sw * sh * depth * channels * 2); gfloat *blurz = g_new0 (gfloat, sw * sh * depth * channels * 2); gfloat *input = g_new0 (gfloat, width * height * channels); gfloat *smoothed = g_new0 (gfloat, width * height * channels); #define INPUT(x,y,c) input[c+channels*(x + width * y)] #define GRID(x,y,z,c,i) grid [i+2*(c+channels*(x+sw*(y+z*sh)))] #define BLURX(x,y,z,c,i) blurx[i+2*(c+channels*(x+sw*(y+z*sh)))] #define BLURY(x,y,z,c,i) blury[i+2*(c+channels*(x+sw*(y+z*sh)))] #define BLURZ(x,y,z,c,i) blurz[i+2*(c+channels*(x+sw*(y+z*sh)))] gegl_buffer_get (src, src_rect, 1.0, babl_format ("RGBA float"), input, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); for (k=0; k < (sw * sh * depth * channels * 2); k++) { grid [k] = 0.0f; blurx[k] = 0.0f; blury[k] = 0.0f; blurz[k] = 0.0f; } #if 0 /* in case we want to normalize the color space */ gfloat input_min[4] = { FLT_MAX, FLT_MAX, FLT_MAX}; gfloat input_max[4] = {-FLT_MAX, -FLT_MAX, -FLT_MAX}; for(y = 0; y < height; y++) for(x = 0; x < width; x++) for(c = 0; c < channels; c++) { input_min[c] = MIN(input_min[c], INPUT(x,y,c)); input_max[c] = MAX(input_max[c], INPUT(x,y,c)); } #endif /* downsampling */ for(y = 0; y < height; y++) for(x = 0; x < width; x++) for(c = 0; c < channels; c++) { const float z = INPUT(x,y,c); // - input_min[c]; const int small_x = (int)((float)(x) / s_sigma + 0.5f) + padding_xy; const int small_y = (int)((float)(y) / s_sigma + 0.5f) + padding_xy; const int small_z = (int)((float)(z) / r_sigma + 0.5f) + padding_z; g_assert(small_x >= 0 && small_x < sw); g_assert(small_y >= 0 && small_y < sh); g_assert(small_z >= 0 && small_z < depth); GRID(small_x, small_y, small_z, c, 0) += INPUT(x, y, c); GRID(small_x, small_y, small_z, c, 1) += 1.0f; } /* blur in x, y and z */ /* XXX: we could use less memory, but at expense of code readability */ for (z = 1; z < depth-1; z++) for (y = 1; y < sh-1; y++) for (x = 1; x < sw-1; x++) for(c = 0; c < channels; c++) for (i=0; i<2; i++) BLURX(x, y, z, c, i) = (GRID (x-1, y, z, c, i) + 2.0f * GRID (x, y, z, c, i) + GRID (x+1, y, z, c, i)) / 4.0f; for (z = 1; z < depth-1; z++) for (y = 1; y < sh-1; y++) for (x = 1; x < sw-1; x++) for(c = 0; c < channels; c++) for (i=0; i<2; i++) BLURY(x, y, z, c, i) = (BLURX (x, y-1, z, c, i) + 2.0f * BLURX (x, y, z, c, i) + BLURX (x, y+1, z, c, i)) / 4.0f; for (z = 1; z < depth-1; z++) for (y = 1; y < sh-1; y++) for (x = 1; x < sw-1; x++) for(c = 0; c < channels; c++) for (i=0; i<2; i++) BLURZ(x, y, z, c, i) = (BLURY (x, y-1, z, c, i) + 2.0f * BLURY (x, y, z, c, i) + BLURY (x, y+1, z, c, i)) / 4.0f; /* trilinear filtering */ for (y=0; y < height; y++) for (x=0; x < width; x++) for(c = 0; c < channels; c++) { float xf = (float)(x) / s_sigma + padding_xy; float yf = (float)(y) / s_sigma + padding_xy; float zf = INPUT(x,y,c) / r_sigma + padding_z; int x1 = CLAMP((int)xf, 0, sw-1); int y1 = CLAMP((int)yf, 0, sh-1); int z1 = CLAMP((int)zf, 0, depth-1); int x2 = CLAMP(x1+1, 0, sw-1); int y2 = CLAMP(y1+1, 0, sh-1); int z2 = CLAMP(z1+1, 0, depth-1); float x_alpha = xf - x1; float y_alpha = yf - y1; float z_alpha = zf - z1; float interpolated[2]; g_assert(xf >= 0 && xf < sw); g_assert(yf >= 0 && yf < sh); g_assert(zf >= 0 && zf < depth); for (i=0; i<2; i++) interpolated[i] = lerp(lerp(lerp(BLURZ(x1, y1, z1, c, i), BLURZ(x2, y1, z1, c, i), x_alpha), lerp(BLURZ(x1, y2, z1, c, i), BLURZ(x2, y2, z1, c, i), x_alpha), y_alpha), lerp(lerp(BLURZ(x1, y1, z2, c, i), BLURZ(x2, y1, z2, c, i), x_alpha), lerp(BLURZ(x1, y2, z2, c, i), BLURZ(x2, y2, z2, c, i), x_alpha), y_alpha), z_alpha); smoothed[channels*(y*width+x)+c] = interpolated[0] / interpolated[1]; } gegl_buffer_set (dst, dst_rect, 0, babl_format ("RGBA float"), smoothed, GEGL_AUTO_ROWSTRIDE); g_free (grid); g_free (blurx); g_free (blury); g_free (blurz); g_free (input); g_free (smoothed); }
static gboolean process (GeglOperation *operation, GeglBuffer *output, const GeglRectangle *result) { GeglChantO *o = GEGL_CHANT_PROPERTIES (operation); Priv *p = (Priv*)o->chant_data; guchar *capbuf; static gboolean inited = FALSE; if (!inited && o->fps != 0) { inited= TRUE; g_timeout_add (1000/o->fps, update, operation); } if (!p->active) return FALSE; v4lgrabf (p->vd); capbuf = v4lgetaddress (p->vd); v4lsyncf (p->vd); if (!capbuf) { g_warning ("no capbuf found"); return FALSE; } if (p->decode) { guchar foobuf[o->width*o->height*3]; /* XXX: foobuf is unneeded the conversions resets for every * scanline and could thus have been done in a line by line * manner an fed into the output buffer */ gint y; for (y = 0; y < p->h; y++) { gint x; guchar *dst = &foobuf[y*p->w*3]; guchar *ysrc = (guchar *) (capbuf + (y) * (p->w) * 1); guchar *usrc = (guchar *) (capbuf + (p->w) * (p->h) + (y) / 2 * (p->w) / 2); guchar *vsrc = (guchar *) (capbuf + (p->w) * (p->h) + ((p->w) * (p->h)) / 4 + (y) / 2 * (p->w) / 2); for (x = 0; x < p->w; x++) { gint R, G, B; #ifndef byteclamp #define byteclamp(j) do{if(j<0)j=0; else if(j>255)j=255;}while(0) #endif #define YUV82RGB8(Y,U,V,R,G,B)do{\ R= ((Y<<15) + 37355*(V-128))>>15;\ G= ((Y<<15) -12911* (U-128) - 19038*(V-128))>>15;\ B= ((Y<<15) +66454* (U-128) )>>15;\ byteclamp(R);\ byteclamp(G);\ byteclamp(B);\ }while(0) /* the format support for this code is not very good, but it * works for the devices I have tested with, conversion even * for chroma subsampled images is something we should let * babl handle. */ YUV82RGB8 (*ysrc, *usrc, *vsrc, R, G, B); dst[0] = B; dst[1] = G; dst[2] = R; dst += 3; ysrc++; if (x % 2) { usrc++; vsrc++; } } } gegl_buffer_set (output, NULL, NULL, foobuf, GEGL_AUTO_ROWSTRIDE); } else { gegl_buffer_set (output, NULL, NULL, capbuf, GEGL_AUTO_ROWSTRIDE); } return TRUE; }
/* 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; }
static gint gegl_jpg_load_buffer_import_jpg (GeglBuffer *gegl_buffer, const gchar *path, gint dest_x, gint dest_y) { gint row_stride; struct jpeg_decompress_struct cinfo; struct jpeg_error_mgr jerr; FILE *infile; JSAMPARRAY buffer; const Babl *format; GeglRectangle write_rect; if ((infile = fopen (path, "rb")) == NULL) { g_warning ("unable to open %s for jpeg import", path); return -1; } jpeg_create_decompress (&cinfo); cinfo.err = jpeg_std_error (&jerr); jpeg_stdio_src (&cinfo, infile); (void) jpeg_read_header (&cinfo, TRUE); (void) jpeg_start_decompress (&cinfo); if (cinfo.output_components == 1) format = babl_format ("Y' u8"); else if (cinfo.output_components == 3) format = babl_format ("R'G'B' u8"); else { g_warning ("attempted to load unsupported JPEG (components=%d)", cinfo.output_components); jpeg_destroy_decompress (&cinfo); return -1; } row_stride = cinfo.output_width * cinfo.output_components; if ((row_stride) % 2) (row_stride)++; /* allocated with the jpeg library, and freed with the decompress context */ buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); write_rect.x = dest_x; write_rect.y = dest_y; write_rect.width = cinfo.output_width; write_rect.height = 1; while (cinfo.output_scanline < cinfo.output_height) { jpeg_read_scanlines (&cinfo, buffer, 1); gegl_buffer_set (gegl_buffer, &write_rect, 0, format, buffer[0], GEGL_AUTO_ROWSTRIDE); write_rect.y += 1; } jpeg_destroy_decompress (&cinfo); fclose (infile); return 0; }
static void set_background (GeglProperties *o, const GeglRectangle *rect, GeglBuffer *input, GeglBuffer *output, gint division_x, gint division_y, gint offset_x, gint offset_y) { const Babl *format; gfloat *dest_buf; gfloat *buf; gint x; gint y; gint index; gint clear_x0; gint clear_y0; gint clear_x1; gint clear_y1; format = babl_format ("RGBA float"); dest_buf = g_new0 (gfloat, 4 * rect->width * rect->height); if (o->fractional_type == GEGL_FRACTIONAL_TYPE_IGNORE) { clear_x0 = offset_x; clear_y0 = offset_y; clear_x1 = clear_x0 + o->tile_width * (rect->width / o->tile_width); clear_y1 = clear_y0 + o->tile_height * (rect->height / o->tile_height); } else { clear_x0 = 0; clear_y0 = 0; clear_x1 = clear_x0 + rect->width; clear_y1 = clear_y0 + rect->height; } switch (o->background_type) { case GEGL_BACKGROUND_TYPE_TRANSPARENT: gegl_buffer_set_color (output, rect, gegl_color_new ("rgba(0.0,0.0,0.0,0.0)")); break; case GEGL_BACKGROUND_TYPE_COLOR: gegl_buffer_set_color (output, rect, o->bg_color); break; case GEGL_BACKGROUND_TYPE_INVERT: gegl_buffer_get (input, rect, 1.0, format, dest_buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); buf = dest_buf; for (y = clear_y0; y < clear_y1; y++) { for (x = clear_x0; x < clear_x1; x++) { index = 4 * (y * rect->width + x); buf[index] = 1 - buf[index]; buf[index+1] = 1 - buf[index+1]; buf[index+2] = 1 - buf[index+2]; } } gegl_buffer_set (output, rect, 0, format, dest_buf, GEGL_AUTO_ROWSTRIDE); break; case GEGL_BACKGROUND_TYPE_IMAGE: gegl_buffer_get (input, rect, 1.0, format, dest_buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); gegl_buffer_set (output, rect, 0, format, dest_buf, GEGL_AUTO_ROWSTRIDE); break; } g_free (dest_buf); }
static void snn_mean (GeglBuffer *src, GeglBuffer *dst, const GeglRectangle *dst_rect, gdouble dradius, gint pairs) { gint x,y; gint offset; gfloat *src_buf; gfloat *dst_buf; gint radius = dradius; gint src_width = gegl_buffer_get_width (src); gint src_height = gegl_buffer_get_height (src); src_buf = g_new0 (gfloat, gegl_buffer_get_pixel_count (src) * 4); dst_buf = g_new0 (gfloat, dst_rect->width * dst_rect->height * 4); gegl_buffer_get (src, NULL, 1.0, babl_format ("RGBA float"), src_buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); offset = 0; for (y=0; y<dst_rect->height; y++) { gfloat *center_pix; center_pix = src_buf + ((radius) + (y+radius)* src_width)*4; for (x=0; x<dst_rect->width; x++) { gint u,v; gfloat accumulated[4]={0,}; gint count=0; /* iterate through the upper left quater of pixels */ for (v=-radius;v<=0;v++) for (u=-radius;u<= (pairs==1?radius:0);u++) { gfloat *selected_pix = center_pix; gfloat best_diff = 1000.0; gint i; /* skip computations for the center pixel */ if (u != 0 && v != 0) { /* compute the coordinates of the symmetric pairs for * this locaiton in the quadrant */ gint xs[4], ys[4]; xs[0] = x+u+radius; xs[1] = x-u+radius; xs[2] = x-u+radius; xs[3] = x+u+radius; ys[0] = y+v+radius; ys[1] = y-v+radius; ys[2] = y+v+radius; ys[3] = y-v+radius; /* check which member of the symmetric quadruple to use */ for (i=0;i<pairs*2;i++) { if (xs[i] >= 0 && xs[i] < src_width && ys[i] >= 0 && ys[i] < src_height) { gfloat *tpix = src_buf + (xs[i]+ys[i]* src_width)*4; gfloat diff = colordiff (tpix, center_pix); if (diff < best_diff) { best_diff = diff; selected_pix = tpix; } } } } /* accumulate the components of the best sample from * the symmetric quadruple */ for (i=0;i<4;i++) { accumulated[i] += selected_pix[i]; } count++; if (u==0 && v==0) break; /* to avoid doubly processing when using only 1 pair */ } for (u=0; u<4; u++) dst_buf[offset*4+u] = accumulated[u]/count; offset++; center_pix += 4; } } gegl_buffer_set (dst, dst_rect, 0, babl_format ("RGBA float"), dst_buf, GEGL_AUTO_ROWSTRIDE); g_free (src_buf); g_free (dst_buf); }
static void demosaic (GeglChantO *op, GeglBuffer *src, const GeglRectangle *src_rect, GeglBuffer *dst, const GeglRectangle *dst_rect) { gint x,y; gint offset; gfloat *src_buf; gfloat *dst_buf; src_buf = g_new0 (gfloat, src_rect->width * src_rect->height * 1); dst_buf = g_new0 (gfloat, dst_rect->width * dst_rect->height * 3); gegl_buffer_get (src, 1.0, src_rect, babl_format ("Y float"), src_buf, GEGL_AUTO_ROWSTRIDE); offset=0; for (y=src_rect->y; y < dst_rect->height + src_rect->y; y++) { gint src_offset = (y-src_rect->y) * src_rect->width; for (x=src_rect->x; x < dst_rect->width + src_rect->x; x++) { gfloat red=0.0; gfloat green=0.0; gfloat blue=0.0; if (y<dst_rect->height+dst_rect->y && x<dst_rect->width+dst_rect->x) { if ((y + op->pattern%2)%2==0) { if ((x+op->pattern/2)%2==1) { blue=src_buf[src_offset+1]; green=src_buf[src_offset]; red=src_buf[src_offset + src_rect->width]; } else { blue=src_buf[src_offset]; green=src_buf[src_offset+1]; red=src_buf[src_offset+1+src_rect->width]; } } else { if ((x+op->pattern/2)%2==1) { blue=src_buf[src_offset + src_rect->width + 1]; green=src_buf[src_offset + 1]; red=src_buf[src_offset]; } else { blue=src_buf[src_offset + src_rect->width]; green=src_buf[src_offset]; red=src_buf[src_offset + 1]; } } } dst_buf [offset*3+0] = red; dst_buf [offset*3+1] = green; dst_buf [offset*3+2] = blue; offset++; src_offset++; } } gegl_buffer_set (dst, dst_rect, babl_format ("RGB float"), dst_buf, GEGL_AUTO_ROWSTRIDE); g_free (src_buf); g_free (dst_buf); }
static gboolean process (GeglOperation *operation, GeglBuffer *input, GeglBuffer *output, const GeglRectangle *result, gint level) { GeglChantO *o = GEGL_CHANT_PROPERTIES (operation); GeglOperationAreaFilter *op_area = GEGL_OPERATION_AREA_FILTER (operation); gfloat *src_buf; gfloat *dst_buf; gint n_pixels = result->width * result->height; GeglRectangle src_rect; gfloat *current_pix; gfloat *target_pix; gfloat *dst_pix; gint x, y; gint total_src_pixels; gint total_dst_pixels; gint bleed_max; gint bleed_index; gfloat blend_coefficient; GHashTable *bleed_table; static GMutex mutex = { 0, }; g_mutex_lock (&mutex); if (!o->chant_data) { o->chant_data = g_hash_table_new_full (tuple_hash, tuple_equal, g_free, g_free); calculate_bleed (operation, input); } g_mutex_unlock (&mutex); bleed_table = (GHashTable*) o->chant_data; src_rect.x = result->x - op_area->left; src_rect.width = result->width + op_area->left + op_area->right; src_rect.y = result->y - op_area->top; src_rect.height = result->height + op_area->top + op_area->bottom; total_src_pixels = src_rect.width * src_rect.height; total_dst_pixels = result->width * result->height; src_buf = gegl_malloc (4 * total_src_pixels * sizeof (gfloat)); dst_buf = gegl_malloc (4 * total_dst_pixels * sizeof (gfloat)); gegl_buffer_get (input, &src_rect, 1.0, babl_format ("RGBA float"), src_buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); current_pix = src_buf + 4*(o->strength + src_rect.width * o->strength); dst_pix = dst_buf; x = 0; y = 0; n_pixels = result->width * result->height; bleed_max = 0; bleed_index = 0; while (n_pixels--) { gint i; pair key = {x + result->x, y + result->y}; gint *bleed = g_hash_table_lookup (bleed_table, &key); if (x == 0) { for (i = 0; i < o->strength; i++) { pair key = {result->x - i, y + result->y}; gint *bleed = g_hash_table_lookup (bleed_table, &key); if (bleed) { bleed_max = *bleed; bleed_index = *bleed - i; break; } } } for (i = 0; i < 4; i++) dst_pix[i] = current_pix[i]; if (bleed) { gfloat blend_color[4]; gfloat blend_amount[4]; gfloat *blend_pix; bleed_max = *bleed; bleed_index = *bleed; target_pix = current_pix; blend_pix = current_pix - 12; for (i = 0; i < 4; i++) { blend_amount[i] = target_pix[i] - blend_pix[i]; blend_color[i] = blend_pix[i] + blend_amount[i]; dst_pix[i] = (2.0 * blend_color[i] + dst_pix[i])/3.0; } } else if (bleed_index > 0) { gfloat blend_color[4]; gfloat blend_amount[4]; gfloat *blend_pix; bleed_index--; blend_coefficient = 1.0 - ((gfloat) bleed_index)/(gfloat) bleed_max; blend_pix = current_pix - 4 * (bleed_max - bleed_index) - 12; target_pix = current_pix; for (i = 0; i < 4; i++) { blend_amount[i] = target_pix[i] - blend_pix[i]; blend_color[i] = blend_pix[i] + blend_amount[i] * blend_coefficient; dst_pix[i] = (2.0 * blend_color[i] + dst_pix[i])/3.0; } } x++; current_pix += 4; dst_pix += 4; if (x >= result->width) { bleed_max = 0; bleed_index = 0; x = 0; y++; current_pix += 8 * o->strength; } } gegl_buffer_set (output, result, 1, babl_format ("RGBA float"), dst_buf, GEGL_AUTO_ROWSTRIDE); gegl_free (src_buf); gegl_free (dst_buf); return TRUE; }
gint32 load_image (const gchar *filename, GimpRunMode runmode, gboolean preview, gboolean *resolution_loaded, GError **error) { 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; GimpImageBaseType image_type; GimpImageType layer_type; GeglBuffer *buffer = NULL; const Babl *format; gint tile_height; gint scanlines; gint i, start, end; cmsHTRANSFORM cmyk_transform = NULL; /* 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; gimp_progress_init_printf (_("Opening '%s'"), gimp_filename_to_utf8 (filename)); } 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; } 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 (); if (buffer) g_object_unref (buffer); 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, except set the DCT * method. */ cinfo.dct_method = JDCT_FLOAT; /* 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_with_precision (cinfo.output_width, cinfo.output_height, image_type, GIMP_PRECISION_U8_GAMMA); 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); } if (! preview) { GString *comment_buffer = NULL; guint8 *profile = NULL; guint profile_size = 0; /* 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 } } if (jpeg_load_resolution (image_ID, &cinfo)) { if (resolution_loaded) *resolution_loaded = TRUE; } /* 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); } /* 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. */ buffer = gimp_drawable_get_buffer (layer_ID); format = babl_format (image_type == GIMP_RGB ? "R'G'B' u8" : "Y' u8"); 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, cinfo.output_width * scanlines, cmyk_transform); gegl_buffer_set (buffer, GEGL_RECTANGLE (0, start, cinfo.output_width, scanlines), 0, format, buf, GEGL_AUTO_ROWSTRIDE); 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. */ if (cmyk_transform) cmsDeleteTransform (cmyk_transform); /* Step 8: Release JPEG decompression object */ /* This is an important step since it will release a good deal of memory. */ jpeg_destroy_decompress (&cinfo); g_object_unref (buffer); /* 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_image_insert_layer (image_ID, layer_ID, -1, 0); return image_ID; }
static void process_floyd_steinberg (GeglBuffer *input, GeglBuffer *output, const GeglRectangle *result, guint *channel_bits) { GeglRectangle line_rect; guint16 *line_buf; gdouble *error_buf [2]; guint channel_mask [4]; gint y; line_rect.x = result->x; line_rect.y = result->y; line_rect.width = result->width; line_rect.height = 1; line_buf = g_new (guint16, line_rect.width * 4); error_buf [0] = g_new0 (gdouble, line_rect.width * 4); error_buf [1] = g_new0 (gdouble, line_rect.width * 4); generate_channel_masks (channel_bits, channel_mask); for (y = 0; y < result->height; y++) { gdouble *error_buf_swap; gint step; gint start_x; gint end_x; gint x; /* Serpentine scanning; reverse direction every row */ if (y & 1) { start_x = result->width - 1; end_x = -1; step = -1; } else { start_x = 0; end_x = result->width; step = 1; } /* Pull input row */ gegl_buffer_get (input, &line_rect, 1.0, babl_format ("RGBA u16"), line_buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); /* Process the row */ for (x = start_x; x != end_x; x += step) { guint16 *pixel = &line_buf [x * 4]; guint ch; for (ch = 0; ch < 4; ch++) { gdouble value; gdouble value_clamped; gdouble quantized; gdouble qerror; value = pixel [ch] + error_buf [0] [x * 4 + ch]; value_clamped = CLAMP (value, 0.0, 65535.0); quantized = quantize_value ((guint) (value_clamped + 0.5), channel_bits [ch], channel_mask [ch]); qerror = value - quantized; pixel [ch] = (guint16) quantized; /* Distribute the error */ error_buf [1] [x * 4 + ch] += qerror * 5.0 / 16.0; /* Down */ if (x + step >= 0 && x + step < result->width) { error_buf [0] [(x + step) * 4 + ch] += qerror * 6.0 / 16.0; /* Ahead */ error_buf [1] [(x + step) * 4 + ch] += qerror * 1.0 / 16.0; /* Down, ahead */ } if (x - step >= 0 && x - step < result->width) { error_buf [1] [(x - step) * 4 + ch] += qerror * 3.0 / 16.0; /* Down, behind */ } } } /* Swap error accumulation rows */ error_buf_swap = error_buf [0]; error_buf [0] = error_buf [1]; error_buf [1] = error_buf_swap; /* Clear error buffer for next-plus-one line */ memset (error_buf [1], 0, line_rect.width * 4 * sizeof (gdouble)); /* Push output row */ gegl_buffer_set (output, &line_rect, 0, babl_format ("RGBA u16"), line_buf, GEGL_AUTO_ROWSTRIDE); line_rect.y++; } g_free (line_buf); g_free (error_buf [0]); g_free (error_buf [1]); }
static gboolean reinhard05_process (GeglOperation *operation, GeglBuffer *input, GeglBuffer *output, const GeglRectangle *result) { const GeglChantO *o = GEGL_CHANT_PROPERTIES (operation); const gint pix_stride = 4, /* RGBA */ RGB = 3; gfloat *lum, *pix; gfloat key, contrast, intensity, chrom = o->chromatic, chrom_comp = 1.0 - o->chromatic, light = o->light, light_comp = 1.0 - o->light; stats world_lin, world_log, channel [RGB], normalise; gint i, c; g_return_val_if_fail (operation, FALSE); g_return_val_if_fail (input, FALSE); g_return_val_if_fail (output, FALSE); g_return_val_if_fail (result, FALSE); g_return_val_if_fail (babl_format_get_n_components (babl_format (OUTPUT_FORMAT)) == pix_stride, FALSE); g_return_val_if_fail (chrom >= 0.0 && chrom <= 1.0, FALSE); g_return_val_if_fail (chrom_comp >= 0.0 && chrom_comp <= 1.0, FALSE); g_return_val_if_fail (light >= 0.0 && light <= 1.0, FALSE); g_return_val_if_fail (light_comp >= 0.0 && light_comp <= 1.0, FALSE); /* Obtain the pixel data */ lum = g_new (gfloat, result->width * result->height), gegl_buffer_get (input, 1.0, result, babl_format ("Y float"), lum, GEGL_AUTO_ROWSTRIDE); pix = g_new (gfloat, result->width * result->height * pix_stride); gegl_buffer_get (input, 1.0, result, babl_format (OUTPUT_FORMAT), pix, GEGL_AUTO_ROWSTRIDE); /* Collect the image stats, averages, etc */ reinhard05_stats_start (&world_lin); reinhard05_stats_start (&world_log); reinhard05_stats_start (&normalise); for (i = 0; i < RGB; ++i) { reinhard05_stats_start (channel + i); } for (i = 0; i < result->width * result->height; ++i) { reinhard05_stats_update (&world_lin, lum[i] ); reinhard05_stats_update (&world_log, logf (2.3e-5f + lum[i])); for (c = 0; c < RGB; ++c) { reinhard05_stats_update (channel + c, pix[i * pix_stride + c]); } } g_return_val_if_fail (world_lin.min >= 0.0, FALSE); reinhard05_stats_finish (&world_lin); reinhard05_stats_finish (&world_log); for (i = 0; i < RGB; ++i) { reinhard05_stats_finish (channel + i); } /* Calculate key parameters */ key = (logf (world_lin.max) - world_log.avg) / (logf (world_lin.max) - logf (2.3e-5f + world_lin.min)); contrast = 0.3 + 0.7 * powf (key, 1.4); intensity = expf (-o->brightness); g_return_val_if_fail (contrast >= 0.3 && contrast <= 1.0, FALSE); /* Apply the operator */ for (i = 0; i < result->width * result->height; ++i) { gfloat local, global, adapt; if (lum[i] == 0.0) continue; for (c = 0; c < RGB; ++c) { gfloat *_p = pix + i * pix_stride + c, p = *_p; local = chrom * p + chrom_comp * lum[i]; global = chrom * channel[c].avg + chrom_comp * world_lin.avg; adapt = light * local + light_comp * global; p /= p + powf (intensity * adapt, contrast); *_p = p; reinhard05_stats_update (&normalise, p); } } /* Normalise the pixel values */ reinhard05_stats_finish (&normalise); for (i = 0; i < result->width * result->height; ++i) { for (c = 0; c < pix_stride; ++c) { gfloat *p = pix + i * pix_stride + c; *p = (*p - normalise.min) / normalise.range; } } /* Cleanup and set the output */ gegl_buffer_set (output, result, babl_format (OUTPUT_FORMAT), pix, GEGL_AUTO_ROWSTRIDE); g_free (pix); g_free (lum); return TRUE; }
static gboolean process (GeglOperation *operation, GeglBuffer *output, const GeglRectangle *result, gint level) { GeglChantO *o = GEGL_CHANT_PROPERTIES (operation); FILE *fp; pnm_struct img; GeglRectangle rect = {0,0,0,0}; gboolean ret = FALSE; fp = (!strcmp (o->path, "-") ? stdin : fopen (o->path,"rb")); if (!fp) return FALSE; if (!ppm_load_read_header (fp, &img)) goto out; /* Allocating Array Size */ /* Should use g_try_malloc(), but this causes crashes elsewhere because the * error signalled by returning FALSE isn't properly acted upon. Therefore * g_malloc() is used here which aborts if the requested memory size can't be * allocated causing a controlled crash. */ img.data = (guchar*) g_malloc (img.numsamples * img.bpc); /* No-op without g_try_malloc(), see above. */ if (! img.data) { g_warning ("Couldn't allocate %" G_GSIZE_FORMAT " bytes, giving up.", ((gsize)img.numsamples * img.bpc)); goto out; } rect.height = img.height; rect.width = img.width; switch (img.bpc) { case 1: gegl_buffer_get (output, &rect, 1.0, babl_format ("R'G'B' u8"), img.data, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); break; case 2: gegl_buffer_get (output, &rect, 1.0, babl_format ("R'G'B' u16"), img.data, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); break; default: g_warning ("%s: Programmer stupidity error", G_STRLOC); } ppm_load_read_image (fp, &img); switch (img.bpc) { case 1: gegl_buffer_set (output, &rect, 0, babl_format ("R'G'B' u8"), img.data, GEGL_AUTO_ROWSTRIDE); break; case 2: gegl_buffer_set (output, &rect, 0, babl_format ("R'G'B' u16"), img.data, GEGL_AUTO_ROWSTRIDE); break; default: g_warning ("%s: Programmer stupidity error", G_STRLOC); } g_free (img.data); ret = TRUE; out: if (stdin != fp) fclose (fp); return ret; }
gboolean gegl_buffer_iterator_next (GeglBufferIterator *iterator) { GeglBufferIterators *i = (gpointer)iterator; gboolean result = FALSE; gint no; if (i->is_finished) g_error ("%s called on finished buffer iterator", G_STRFUNC); if (i->iteration_no == 0) { for (no=0; no<i->iterators;no++) { gint j; gboolean found = FALSE; for (j=0; j<no; j++) if (i->buffer[no]==i->buffer[j]) { found = TRUE; break; } if (!found) gegl_buffer_lock (i->buffer[no]); if (gegl_cl_is_accelerated ()) gegl_buffer_cl_cache_flush (i->buffer[no], &i->rect[no]); } } else { /* complete pending write work */ for (no=0; no<i->iterators;no++) { if (i->flags[no] & GEGL_BUFFER_WRITE) { if (i->flags[no] & GEGL_BUFFER_SCAN_COMPATIBLE && i->flags[no] & GEGL_BUFFER_FORMAT_COMPATIBLE && i->roi[no].width == i->i[no].buffer->tile_storage->tile_width && (i->flags[no] & GEGL_BUFFER_FORMAT_COMPATIBLE)) { /* direct access, don't need to do anything */ #if DEBUG_DIRECT direct_write += i->roi[no].width * i->roi[no].height; #endif } else { #if DEBUG_DIRECT in_direct_write += i->roi[no].width * i->roi[no].height; #endif ensure_buf (i, no); /* XXX: should perhaps use _set_unlocked, and keep the lock in the * iterator. */ gegl_buffer_set (i->buffer[no], &(i->roi[no]), 0, i->format[no], i->buf[no], GEGL_AUTO_ROWSTRIDE); /* XXX: use correct level */ } } } } g_assert (i->iterators > 0); /* then we iterate all */ for (no=0; no<i->iterators;no++) { if (i->flags[no] & GEGL_BUFFER_SCAN_COMPATIBLE) { gboolean res; res = gegl_buffer_tile_iterator_next (&i->i[no]); if (no == 0) { result = res; } i->roi[no] = i->i[no].roi2; /* since they were scan compatible this should be true */ if (res != result) { g_print ("%i==%i != 0==%i\n", no, res, result); } g_assert (res == result); if ((i->flags[no] & GEGL_BUFFER_FORMAT_COMPATIBLE) && i->roi[no].width == i->i[no].buffer->tile_storage->tile_width ) { /* direct access */ i->data[no]=i->i[no].sub_data; #if DEBUG_DIRECT direct_read += i->roi[no].width * i->roi[no].height; #endif } else { ensure_buf (i, no); if (i->flags[no] & GEGL_BUFFER_READ) { gegl_buffer_get_unlocked (i->buffer[no], 1.0, &(i->roi[no]), i->format[no], i->buf[no], GEGL_AUTO_ROWSTRIDE); } i->data[no]=i->buf[no]; #if DEBUG_DIRECT in_direct_read += i->roi[no].width * i->roi[no].height; #endif } } else { /* we copy the roi from iterator 0 */ i->roi[no] = i->roi[0]; i->roi[no].x += (i->rect[no].x-i->rect[0].x); i->roi[no].y += (i->rect[no].y-i->rect[0].y); ensure_buf (i, no); if (i->flags[no] & GEGL_BUFFER_READ) { gegl_buffer_get_unlocked (i->buffer[no], 1.0, &(i->roi[no]), i->format[no], i->buf[no], GEGL_AUTO_ROWSTRIDE); } i->data[no]=i->buf[no]; #if DEBUG_DIRECT in_direct_read += i->roi[no].width * i->roi[no].height; #endif } i->length = i->roi[no].width * i->roi[no].height; } i->iteration_no++; if (result == FALSE) gegl_buffer_iterator_stop (iterator); return result; }
static gboolean process (GeglOperation *operation, GeglBuffer *input, GeglBuffer *output, const GeglRectangle *result, gint level) { GeglChantO *o = GEGL_CHANT_PROPERTIES (operation); GeglRectangle boundary = get_effective_area (operation); const Babl *format = babl_format ("RGBA float"); gint x,y; gfloat *src_buf, *dst_buf; gfloat dest[4]; gint i, offset = 0; gboolean inside; gdouble px, py; GeglMatrix2 scale; /* a matrix indicating scaling factors around the current center pixel. */ src_buf = g_new0 (gfloat, result->width * result->height * 4); dst_buf = g_new0 (gfloat, result->width * result->height * 4); gegl_buffer_get (input, result, 1.0, format, src_buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); if (o->middle) { o->pole_x = boundary.width / 2; o->pole_y = boundary.height / 2; } for (y = result->y; y < result->y + result->height; y++) for (x = result->x; x < result->x + result->width; x++) { #define gegl_unmap(u,v,ud,vd) { \ gdouble rx, ry; \ inside = calc_undistorted_coords ((gdouble)x, (gdouble)y, \ &rx, &ry, o, boundary); \ ud = rx; \ vd = ry; \ } gegl_sampler_compute_scale (scale, x, y); gegl_unmap(x,y,px,py); #undef gegl_unmap if (inside) gegl_buffer_sample (input, px, py, &scale, dest, format, GEGL_SAMPLER_NOHALO, GEGL_ABYSS_NONE); else for (i=0; i<4; i++) dest[i] = 0.0; for (i=0; i<4; i++) dst_buf[offset++] = dest[i]; } gegl_buffer_set (output, result, 0, format, dst_buf, GEGL_AUTO_ROWSTRIDE); g_free (src_buf); g_free (dst_buf); return TRUE; }
static gboolean process (GeglOperation *operation, GeglBuffer *input, GeglBuffer *output, const GeglRectangle *result, gint level) { GeglChantO *o = GEGL_CHANT_PROPERTIES (operation); gint x = result->x; /* initial x */ gint y = result->y; /* and y coordinates */ gfloat *dst_buf = g_slice_alloc (result->width * result->height * 4 * sizeof (gfloat)); gfloat *out_pixel = dst_buf; GeglSampler *sampler = gegl_buffer_sampler_new (input, babl_format ("RGBA float"), o->sampler_type); gint n_pixels = result->width * result->height; GeglAbyssPolicy abyss = o->clamp ? GEGL_ABYSS_CLAMP : GEGL_ABYSS_NONE; gdouble scalex; gdouble scaley; if (o->aspect > 1.0) { scalex = 1.0; scaley = o->aspect; } else if (o->aspect < 1.0) { scalex = 1.0 / o->aspect; scaley = 1.0; } else { scalex = 1.0; scaley = 1.0; } while (n_pixels--) { gdouble radius; gdouble shift; gdouble dx; gdouble dy; gdouble ux; gdouble uy; dx = (x - o->x) * scalex; dy = (y - o->y) * scaley; radius = sqrt (dx * dx + dy * dy); shift = o->amplitude * sin (2.0 * G_PI * radius / o->period + 2.0 * G_PI * o->phi); ux = dx / radius; uy = dy / radius; gegl_sampler_get (sampler, x + (shift + ux) / scalex, y + (shift + uy) / scaley, NULL, out_pixel, abyss); out_pixel += 4; /* update x and y coordinates */ x++; if (x >= result->x + result->width) { x = result->x; y++; } } gegl_buffer_set (output, result, 0, babl_format ("RGBA float"), dst_buf, GEGL_AUTO_ROWSTRIDE); g_slice_free1 (result->width * result->height * 4 * sizeof (gfloat), dst_buf); g_object_unref (sampler); return TRUE; }
static gboolean process (GeglOperation *operation, GeglBuffer *input, GeglBuffer *output, const GeglRectangle *roi, gint level) { GeglProperties *o = GEGL_PROPERTIES (operation); const Babl *format = gegl_operation_get_format (operation, "output"); gint components = babl_format_get_n_components (format); gboolean has_alpha = babl_format_has_alpha (format); gfloat *src_buff; gfloat *dst_buff; GeglRectangle rect; gint x, y, ix, iy, b, idx; rect = gegl_operation_get_required_for_output (operation, "input", roi); src_buff = g_new (gfloat, rect.width * rect.height * components); dst_buff = g_new0 (gfloat, roi->width * roi->height * components); gegl_buffer_get (input, &rect, 1.0, format, src_buff, GEGL_AUTO_ROWSTRIDE, o->border_behavior); for (y = 0; y < roi->height; y++) { iy = y + 1; for (x = 0; x < roi->width; x++) { ix = x + 1; for (b = 0; b < 3; b++) { #define SRCPIX(X,Y,B) src_buff[((X) + (Y) * rect.width) * components + B] gfloat window[9]; window[0] = SRCPIX(ix - 1, iy - 1, b); window[1] = SRCPIX(ix, iy - 1, b); window[2] = SRCPIX(ix + 1, iy - 1, b); window[3] = SRCPIX(ix - 1, iy, b); window[4] = SRCPIX(ix, iy, b); window[5] = SRCPIX(ix + 1, iy, b); window[6] = SRCPIX(ix - 1, iy + 1, b); window[7] = SRCPIX(ix, iy + 1, b); window[8] = SRCPIX(ix + 1, iy + 1, b); idx = (x + y * roi->width) * components + b; switch (o->algorithm) { default: case GEGL_EDGE_SOBEL: dst_buff[idx] = edge_sobel (window, o->amount); break; case GEGL_EDGE_PREWITT: dst_buff[idx] = edge_prewitt (window, o->amount); break; case GEGL_EDGE_GRADIENT: dst_buff[idx] = edge_gradient (window, o->amount); break; case GEGL_EDGE_ROBERTS: dst_buff[idx] = edge_roberts (window, o->amount); break; case GEGL_EDGE_DIFFERENTIAL: dst_buff[idx] = edge_differential (window, o->amount); break; case GEGL_EDGE_LAPLACE: dst_buff[idx] = edge_laplace (window, o->amount); break; } } if (has_alpha) dst_buff[idx + 1] = SRCPIX(ix, iy, 3); } #undef SRCPIX } gegl_buffer_set (output, roi, level, format, dst_buff, GEGL_AUTO_ROWSTRIDE); g_free (src_buff); g_free (dst_buff); return TRUE; }
static gboolean matting_process (GeglOperation *operation, GeglBuffer *input_buf, GeglBuffer *aux_buf, GeglBuffer *output_buf, const GeglRectangle *result, int level) { const GeglProperties *o = GEGL_PROPERTIES (operation); gfloat *input = NULL; guchar *trimap = NULL; gfloat *output = NULL; BufferRecord *buffer = NULL; gboolean success = FALSE; int w, h, i, x, y, xdiff, ydiff, neighbour_mask; GArray *foreground_samples, *background_samples; GArray *unknown_positions; g_return_val_if_fail (babl_format_get_n_components (babl_format (FORMAT_INPUT )) == COMPONENTS_INPUT, FALSE); g_return_val_if_fail (babl_format_get_n_components (babl_format (FORMAT_AUX )) == COMPONENTS_AUX, FALSE); g_return_val_if_fail (babl_format_get_n_components (babl_format (FORMAT_OUTPUT)) == COMPONENTS_OUTPUT, FALSE); g_return_val_if_fail (operation, FALSE); g_return_val_if_fail (input_buf, FALSE); g_return_val_if_fail (aux_buf, FALSE); g_return_val_if_fail (output_buf, FALSE); g_return_val_if_fail (result, FALSE); w = result->width; h = result->height; input = g_new (gfloat, w * h * COMPONENTS_INPUT); trimap = g_new (guchar, w * h * COMPONENTS_AUX); output = g_new0 (gfloat, w * h * COMPONENTS_OUTPUT); buffer = g_new0 (BufferRecord, w * h); gegl_buffer_get (input_buf, result, 1.0, babl_format (FORMAT_INPUT), input, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); gegl_buffer_get ( aux_buf, result, 1.0, babl_format (FORMAT_AUX), trimap, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); foreground_samples = g_array_new(FALSE, FALSE, sizeof(ColorSample)); background_samples = g_array_new(FALSE, FALSE, sizeof(ColorSample)); unknown_positions = g_array_new(FALSE, FALSE, sizeof(Position)); // Get mask for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { int mask = trimap[y * w + x]; for (ydiff = -1; ydiff <= 1; ydiff++) { // Borders if (y+ydiff < 0 || y+ydiff >= h) continue; for (xdiff = -1; xdiff <= 1; xdiff++) { // Borders if (x+xdiff < 0 || x+xdiff >= w) continue; neighbour_mask = trimap[(y + ydiff) * w + x + xdiff]; if (neighbour_mask != mask && (mask == 0 || mask == 255)) { int index = y*w+x; ColorSample s; s.pos.x = x; s.pos.y = y; COLOR(s.color[c] = input[index*3 + c]); if (mask == 255) { g_array_append_val(foreground_samples, s); buffer[index].fg_distance = 0; buffer[index].bg_distance = FLT_MAX; } else { g_array_append_val(background_samples, s); buffer[index].fg_distance = 0; buffer[index].bg_distance = FLT_MAX; } // Go to next pixel xdiff = 1; ydiff = 1; } } } } } /* If we have no information to work with, there is nothing to process. */ if (foreground_samples->len == 0 || background_samples->len == 0) { success = FALSE; goto cleanup; } // Initialize unknowns for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { int index = y * w + x; if (trimap[index] != 0 && trimap[index] != 255) { Position p; p.x = x; p.y = y; g_array_append_val(unknown_positions, p); buffer[index].fg_distance = FLT_MAX; buffer[index].bg_distance = FLT_MAX; buffer[index].fg_index = rand() % foreground_samples->len; buffer[index].bg_index = rand() % background_samples->len; } } } g_array_sort(foreground_samples, color_compare); g_array_sort(background_samples, color_compare); // Do real iterations for (i = 0; i < o->iterations; i++) { unsigned j; GEGL_NOTE (GEGL_DEBUG_PROCESS, "Iteration %i", i); for (j=0; j<unknown_positions->len; j++) { Position p = g_array_index(unknown_positions, Position, j); do_random_search(foreground_samples, background_samples, input, buffer, p.x, p.y, w); } for (j=0; j<unknown_positions->len; j++) { Position p = g_array_index(unknown_positions, Position, j); do_propagate(foreground_samples, background_samples, input, buffer, trimap, p.x, p.y, w, h); } } // Fill results in for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { int index = y * w + x; if (trimap[index] == 0 || trimap[index] == 255) { if (trimap[index] == 0) { output[index] = 0; } else if (trimap[index] == 255) { output[index] = 1; } } else { ColorSample background, foreground; foreground = g_array_index(foreground_samples, ColorSample, buffer[index].fg_index); background = g_array_index(background_samples, ColorSample, buffer[index].bg_index); output[index] = get_alpha(foreground.color, background.color, &input[index * 3]); } } } // Save to buffer gegl_buffer_set (output_buf, result, 0, babl_format (FORMAT_OUTPUT), output, GEGL_AUTO_ROWSTRIDE); success = TRUE; cleanup: g_free (input); g_free (trimap); g_free (output); g_free (buffer); g_array_free (foreground_samples, TRUE); g_array_free (background_samples, TRUE); g_array_free (unknown_positions, TRUE); return success; }
static gboolean process (GeglOperation *operation, GeglBuffer *input, GeglBuffer *output, const GeglRectangle *roi, gint level) { GeglRectangle src_rect; GeglRectangle *whole_region; GeglProperties *o = GEGL_PROPERTIES (operation); GeglOperationAreaFilter *op_area; op_area = GEGL_OPERATION_AREA_FILTER (operation); whole_region = gegl_operation_source_get_bounding_box (operation, "input"); if (gegl_operation_use_opencl (operation)) if (cl_process (operation, input, output, roi)) return TRUE; if (o->size_x * o->size_y < SQR (ALLOC_THRESHOLD_SIZE)) { gfloat background_color[4]; gfloat *input_buf = g_new (gfloat, (CHUNK_SIZE + o->size_x * 2) * (CHUNK_SIZE + o->size_y * 2) * 4); gfloat *output_buf = g_new (gfloat, SQR (CHUNK_SIZE) * 4); gint i, j; gegl_color_get_pixel (o->background, babl_format("RaGaBaA float"), background_color); for (j = 0; (j-1) * CHUNK_SIZE < roi->height; j++) for (i = 0; (i-1) * CHUNK_SIZE < roi->width; i++) { GeglRectangle chunked_result; GeglRectangle chunked_sizes; chunked_result = *GEGL_RECTANGLE (roi->x + i * CHUNK_SIZE, roi->y + j * CHUNK_SIZE, CHUNK_SIZE, CHUNK_SIZE); gegl_rectangle_intersect (&chunked_result, &chunked_result, roi); if (chunked_result.width < 1 || chunked_result.height < 1) continue; src_rect = chunked_result; src_rect.x -= op_area->left; src_rect.y -= op_area->top; src_rect.width += op_area->left + op_area->right; src_rect.height += op_area->top + op_area->bottom; gegl_buffer_get (input, &src_rect, 1.0, babl_format ("RaGaBaA float"), input_buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_CLAMP); gegl_rectangle_copy (&chunked_sizes, &chunked_result); chunked_sizes.x = 0; chunked_sizes.y = 0; set_rectangle (output_buf, &chunked_sizes, &chunked_sizes, chunked_result.width, background_color, GEGL_PIXELIZE_NORM_INFINITY); pixelize (input_buf, output_buf, &chunked_result, &src_rect, whole_region, o); gegl_buffer_set (output, &chunked_result, 0, babl_format ("RaGaBaA float"), output_buf, GEGL_AUTO_ROWSTRIDE); } g_free (input_buf); g_free (output_buf); } else { gegl_buffer_set_color (output, roi, o->background); pixelize_noalloc (input, output, roi, whole_region, o); } return TRUE; }
gboolean gegl_buffer_cl_iterator_next (GeglBufferClIterator *iterator, gboolean *err) { GeglBufferClIterators *i = (gpointer)iterator; gboolean result = FALSE; gint no, j; cl_int cl_err = 0; if (i->is_finished) g_error ("%s called on finished buffer iterator", G_STRFUNC); if (i->iteration_no == 0) { for (no=0; no<i->iterators;no++) { if (i->buffer[no]) { gint j; gboolean found = FALSE; for (j=0; j<no; j++) if (i->buffer[no]==i->buffer[j]) { found = TRUE; break; } if (!found) gegl_buffer_lock (i->buffer[no]); if (i->flags[no] == GEGL_CL_BUFFER_WRITE || (i->flags[no] == GEGL_CL_BUFFER_READ && (i->area[no][0] > 0 || i->area[no][1] > 0 || i->area[no][2] > 0 || i->area[no][3] > 0))) { gegl_buffer_cl_cache_flush (i->buffer[no], &i->rect[no]); } } } } else { /* complete pending write work */ for (no=0; no<i->iterators;no++) { if (i->flags[no] == GEGL_CL_BUFFER_WRITE) { /* Wait Processing */ cl_err = gegl_clEnqueueBarrier(gegl_cl_get_command_queue()); if (cl_err != CL_SUCCESS) CL_ERROR; /* color conversion in the GPU (output) */ if (i->conv[no] == GEGL_CL_COLOR_CONVERT) for (j=0; j < i->n; j++) { cl_err = gegl_cl_color_conv (i->tex_op[no][j], i->tex_buf[no][j], i->size[no][j], i->format[no], i->buffer[no]->soft_format); if (cl_err == FALSE) CL_ERROR; } /* Wait Processing */ cl_err = gegl_clEnqueueBarrier(gegl_cl_get_command_queue()); if (cl_err != CL_SUCCESS) CL_ERROR; /* GPU -> CPU */ for (j=0; j < i->n; j++) { gpointer data; /* tile-ize */ if (i->conv[no] == GEGL_CL_COLOR_NOT_SUPPORTED) { data = gegl_clEnqueueMapBuffer(gegl_cl_get_command_queue(), i->tex_op[no][j], CL_TRUE, CL_MAP_READ, 0, i->size[no][j] * i->op_cl_format_size [no], 0, NULL, NULL, &cl_err); if (cl_err != CL_SUCCESS) CL_ERROR; /* color conversion using BABL */ gegl_buffer_set (i->buffer[no], &i->roi[no][j], 0, i->format[no], data, GEGL_AUTO_ROWSTRIDE); cl_err = gegl_clEnqueueUnmapMemObject (gegl_cl_get_command_queue(), i->tex_op[no][j], data, 0, NULL, NULL); if (cl_err != CL_SUCCESS) CL_ERROR; } else #ifdef OPENCL_USE_CACHE { gegl_buffer_cl_cache_new (i->buffer[no], &i->roi[no][j], i->tex_buf[no][j]); /* don't release this texture */ i->tex_buf[no][j] = NULL; } #else { data = gegl_clEnqueueMapBuffer(gegl_cl_get_command_queue(), i->tex_buf[no][j], CL_TRUE, CL_MAP_READ, 0, i->size[no][j] * i->buf_cl_format_size [no], 0, NULL, NULL, &cl_err); if (cl_err != CL_SUCCESS) CL_ERROR; /* color conversion using BABL */ gegl_buffer_set (i->buffer[no], &i->roi[no][j], i->format[no], data, GEGL_AUTO_ROWSTRIDE); cl_err = gegl_clEnqueueUnmapMemObject (gegl_cl_get_command_queue(), i->tex_buf[no][j], data, 0, NULL, NULL); if (cl_err != CL_SUCCESS) CL_ERROR; } #endif } } } /* Run! */ cl_err = gegl_clFinish(gegl_cl_get_command_queue()); if (cl_err != CL_SUCCESS) CL_ERROR; for (no=0; no < i->iterators; no++) for (j=0; j < i->n; j++) { if (i->tex_buf_from_cache [no][j]) { gboolean ok = gegl_buffer_cl_cache_release (i->tex_buf[no][j]); g_assert (ok); } if (i->tex_buf[no][j] && !i->tex_buf_from_cache [no][j]) gegl_clReleaseMemObject (i->tex_buf[no][j]); if (i->tex_op [no][j]) gegl_clReleaseMemObject (i->tex_op [no][j]); i->tex [no][j] = NULL; i->tex_buf[no][j] = NULL; i->tex_op [no][j] = NULL; } } g_assert (i->iterators > 0); result = (i->roi_no >= i->rois)? FALSE : TRUE; i->n = MIN(GEGL_CL_NTEX, i->rois - i->roi_no); /* then we iterate all */ for (no=0; no<i->iterators;no++) { for (j = 0; j < i->n; j++) { GeglRectangle r = {i->rect[no].x + i->roi_all[i->roi_no+j].x - i->area[no][0], i->rect[no].y + i->roi_all[i->roi_no+j].y - i->area[no][2], i->roi_all[i->roi_no+j].width + i->area[no][0] + i->area[no][1], i->roi_all[i->roi_no+j].height + i->area[no][2] + i->area[no][3]}; i->roi [no][j] = r; i->size[no][j] = r.width * r.height; } if (i->flags[no] == GEGL_CL_BUFFER_READ) { for (j=0; j < i->n; j++) { gpointer data; /* un-tile */ switch (i->conv[no]) { case GEGL_CL_COLOR_NOT_SUPPORTED: { gegl_buffer_cl_cache_flush (i->buffer[no], &i->roi[no][j]); g_assert (i->tex_op[no][j] == NULL); i->tex_op[no][j] = gegl_clCreateBuffer (gegl_cl_get_context (), CL_MEM_ALLOC_HOST_PTR | CL_MEM_READ_ONLY, i->size[no][j] * i->op_cl_format_size [no], NULL, &cl_err); if (cl_err != CL_SUCCESS) CL_ERROR; /* pre-pinned memory */ data = gegl_clEnqueueMapBuffer(gegl_cl_get_command_queue(), i->tex_op[no][j], CL_TRUE, CL_MAP_WRITE, 0, i->size[no][j] * i->op_cl_format_size [no], 0, NULL, NULL, &cl_err); if (cl_err != CL_SUCCESS) CL_ERROR; /* color conversion using BABL */ gegl_buffer_get (i->buffer[no], &i->roi[no][j], 1.0, i->format[no], data, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); cl_err = gegl_clEnqueueUnmapMemObject (gegl_cl_get_command_queue(), i->tex_op[no][j], data, 0, NULL, NULL); if (cl_err != CL_SUCCESS) CL_ERROR; i->tex[no][j] = i->tex_op[no][j]; break; } case GEGL_CL_COLOR_EQUAL: { i->tex_buf[no][j] = gegl_buffer_cl_cache_get (i->buffer[no], &i->roi[no][j]); if (i->tex_buf[no][j]) i->tex_buf_from_cache [no][j] = TRUE; /* don't free texture from cache */ else { gegl_buffer_cl_cache_flush (i->buffer[no], &i->roi[no][j]); g_assert (i->tex_buf[no][j] == NULL); i->tex_buf[no][j] = gegl_clCreateBuffer (gegl_cl_get_context (), CL_MEM_ALLOC_HOST_PTR | CL_MEM_READ_ONLY, i->size[no][j] * i->buf_cl_format_size [no], NULL, &cl_err); if (cl_err != CL_SUCCESS) CL_ERROR; /* pre-pinned memory */ data = gegl_clEnqueueMapBuffer(gegl_cl_get_command_queue(), i->tex_buf[no][j], CL_TRUE, CL_MAP_WRITE, 0, i->size[no][j] * i->buf_cl_format_size [no], 0, NULL, NULL, &cl_err); if (cl_err != CL_SUCCESS) CL_ERROR; /* color conversion will be performed in the GPU later */ gegl_buffer_cl_worker_transf (i->buffer[no], data, i->buf_cl_format_size [no], i->roi[no][j], FALSE); cl_err = gegl_clEnqueueUnmapMemObject (gegl_cl_get_command_queue(), i->tex_buf[no][j], data, 0, NULL, NULL); if (cl_err != CL_SUCCESS) CL_ERROR; } i->tex[no][j] = i->tex_buf[no][j]; break; } case GEGL_CL_COLOR_CONVERT: { i->tex_buf[no][j] = gegl_buffer_cl_cache_get (i->buffer[no], &i->roi[no][j]); if (i->tex_buf[no][j]) i->tex_buf_from_cache [no][j] = TRUE; /* don't free texture from cache */ else { gegl_buffer_cl_cache_flush (i->buffer[no], &i->roi[no][j]); g_assert (i->tex_buf[no][j] == NULL); i->tex_buf[no][j] = gegl_clCreateBuffer (gegl_cl_get_context (), CL_MEM_ALLOC_HOST_PTR | CL_MEM_READ_ONLY, i->size[no][j] * i->buf_cl_format_size [no], NULL, &cl_err); if (cl_err != CL_SUCCESS) CL_ERROR; /* pre-pinned memory */ data = gegl_clEnqueueMapBuffer(gegl_cl_get_command_queue(), i->tex_buf[no][j], CL_TRUE, CL_MAP_WRITE, 0, i->size[no][j] * i->buf_cl_format_size [no], 0, NULL, NULL, &cl_err); if (cl_err != CL_SUCCESS) CL_ERROR; /* color conversion will be performed in the GPU later */ /* get buffer data using multiple worker threads to increase bandwidth */ gegl_buffer_cl_worker_transf (i->buffer[no], data, i->buf_cl_format_size [no], i->roi[no][j], FALSE); cl_err = gegl_clEnqueueUnmapMemObject (gegl_cl_get_command_queue(), i->tex_buf[no][j], data, 0, NULL, NULL); if (cl_err != CL_SUCCESS) CL_ERROR; } g_assert (i->tex_op[no][j] == NULL); i->tex_op[no][j] = gegl_clCreateBuffer (gegl_cl_get_context (), CL_MEM_READ_WRITE, i->size[no][j] * i->op_cl_format_size [no], NULL, &cl_err); if (cl_err != CL_SUCCESS) CL_ERROR; /* color conversion in the GPU (input) */ g_assert (i->tex_buf[no][j] && i->tex_op[no][j]); cl_err = gegl_cl_color_conv (i->tex_buf[no][j], i->tex_op[no][j], i->size[no][j], i->buffer[no]->soft_format, i->format[no]); if (cl_err == FALSE) CL_ERROR; i->tex[no][j] = i->tex_op[no][j]; break; } } } /* Wait Processing */ cl_err = gegl_clEnqueueBarrier(gegl_cl_get_command_queue()); if (cl_err != CL_SUCCESS) CL_ERROR; } else if (i->flags[no] == GEGL_CL_BUFFER_WRITE) { for (j=0; j < i->n; j++) { switch (i->conv[no]) { case GEGL_CL_COLOR_NOT_SUPPORTED: { g_assert (i->tex_op[no][j] == NULL); i->tex_op[no][j] = gegl_clCreateBuffer (gegl_cl_get_context (), CL_MEM_ALLOC_HOST_PTR | CL_MEM_WRITE_ONLY, i->size[no][j] * i->op_cl_format_size [no], NULL, &cl_err); if (cl_err != CL_SUCCESS) CL_ERROR; i->tex[no][j] = i->tex_op[no][j]; break; } case GEGL_CL_COLOR_EQUAL: { g_assert (i->tex_buf[no][j] == NULL); i->tex_buf[no][j] = gegl_clCreateBuffer (gegl_cl_get_context (), CL_MEM_ALLOC_HOST_PTR | CL_MEM_READ_WRITE, /* cache */ i->size[no][j] * i->buf_cl_format_size [no], NULL, &cl_err); if (cl_err != CL_SUCCESS) CL_ERROR; i->tex[no][j] = i->tex_buf[no][j]; break; } case GEGL_CL_COLOR_CONVERT: { g_assert (i->tex_buf[no][j] == NULL); i->tex_buf[no][j] = gegl_clCreateBuffer (gegl_cl_get_context (), CL_MEM_ALLOC_HOST_PTR | CL_MEM_READ_WRITE, /* cache */ i->size[no][j] * i->buf_cl_format_size [no], NULL, &cl_err); if (cl_err != CL_SUCCESS) CL_ERROR; g_assert (i->tex_op[no][j] == NULL); i->tex_op[no][j] = gegl_clCreateBuffer (gegl_cl_get_context (), CL_MEM_READ_WRITE, i->size[no][j] * i->op_cl_format_size [no], NULL, &cl_err); if (cl_err != CL_SUCCESS) CL_ERROR; i->tex[no][j] = i->tex_op[no][j]; break; } } } } else if (i->flags[no] == GEGL_CL_BUFFER_AUX) { for (j=0; j < i->n; j++) { g_assert (i->tex_op[no][j] == NULL); i->tex_op[no][j] = gegl_clCreateBuffer (gegl_cl_get_context (), CL_MEM_READ_WRITE, i->size[no][j] * i->op_cl_format_size [no], NULL, &cl_err); if (cl_err != CL_SUCCESS) CL_ERROR; i->tex[no][j] = i->tex_op[no][j]; } } } i->roi_no += i->n; i->iteration_no++; if (result == FALSE) { for (no=0; no<i->iterators;no++) { if (i->buffer[no]) { gint j; gboolean found = FALSE; for (j=0; j<no; j++) if (i->buffer[no]==i->buffer[j]) { found = TRUE; break; } if (!found) gegl_buffer_unlock (i->buffer[no]); g_object_unref (i->buffer[no]); } } i->is_finished = TRUE; g_free (i->roi_all); g_slice_free (GeglBufferClIterators, i); } *err = FALSE; return result; error: for (no=0; no<i->iterators;no++) for (j=0; j < i->n; j++) { if (i->tex_buf[no][j]) gegl_clReleaseMemObject (i->tex_buf[no][j]); if (i->tex_op [no][j]) gegl_clReleaseMemObject (i->tex_op [no][j]); i->tex [no][j] = NULL; i->tex_buf[no][j] = NULL; i->tex_op [no][j] = NULL; } *err = TRUE; return FALSE; }
static gboolean process (GeglOperation *operation, GeglBuffer *output, const GeglRectangle *result, gint level) { GeglProperties *o = GEGL_PROPERTIES (operation); Priv *p = (Priv*)o->user_data; { if (p->video_fcontext && !decode_frame (operation, o->frame)) { long sample_start = 0; if (p->audio_stream) { int sample_count; gegl_audio_fragment_set_sample_rate (o->audio, p->audio_stream->codec->sample_rate); gegl_audio_fragment_set_channels (o->audio, 2); gegl_audio_fragment_set_channel_layout (o->audio, GEGL_CH_LAYOUT_STEREO); sample_count = samples_per_frame (o->frame, o->frame_rate, p->audio_stream->codec->sample_rate, &sample_start); gegl_audio_fragment_set_sample_count (o->audio, sample_count); decode_audio (operation, p->prevpts, p->prevpts + 5.0); { int i; for (i = 0; i < sample_count; i++) { get_sample_data (p, sample_start + i, &o->audio->data[0][i], &o->audio->data[1][i]); } } } if (p->video_stream->codec->pix_fmt == AV_PIX_FMT_RGB24) { GeglRectangle extent = {0,0,p->width,p->height}; gegl_buffer_set (output, &extent, 0, babl_format("R'G'B' u8"), p->lavc_frame->data[0], GEGL_AUTO_ROWSTRIDE); } else { struct SwsContext *img_convert_ctx; GeglRectangle extent = {0,0,p->width,p->height}; img_convert_ctx = sws_getContext(p->width, p->height, p->video_stream->codec->pix_fmt, p->width, p->height, AV_PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL); if (!p->rgb_frame) p->rgb_frame = alloc_picture (AV_PIX_FMT_RGB24, p->width, p->height); sws_scale (img_convert_ctx, (void*)p->lavc_frame->data, p->lavc_frame->linesize, 0, p->height, p->rgb_frame->data, p->rgb_frame->linesize); gegl_buffer_set (output, &extent, 0, babl_format("R'G'B' u8"), p->rgb_frame->data[0], GEGL_AUTO_ROWSTRIDE); sws_freeContext (img_convert_ctx); } } } return TRUE; }
static gboolean process (GeglOperation *operation, GeglBuffer *input, GeglBuffer *output, const GeglRectangle *result, gint level) { GeglProperties *o = GEGL_PROPERTIES (operation); GeglOperationAreaFilter *op_area = GEGL_OPERATION_AREA_FILTER (operation); const Babl *format = babl_format ("RGBA float"); GeglRectangle rect; GeglRectangle boundary = get_effective_area (operation); gint x, y; gfloat *dst_buf, *src_buf; rect.x = CLAMP (result->x - op_area->left, boundary.x, boundary.x + boundary.width); rect.width = CLAMP (result->width + op_area->left + op_area->right, 0, boundary.width); rect.y = CLAMP (result->y - op_area->top, boundary.y, boundary.y + boundary.width); rect.height = CLAMP (result->height + op_area->top + op_area->bottom, 0, boundary.height); dst_buf = g_new0 (gfloat, result->height * result->width * 4); src_buf = g_new0 (gfloat, rect.height * rect.width * 4); gegl_buffer_get (input, result, 1.0, format, dst_buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); gegl_buffer_get (input, &rect, 1.0, format, src_buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); if (o->orientation == GEGL_ORIENTATION_HORIZONTAL) { for (y = result->y; y < result->y + result->height; y++) if ((o->keep == GEGL_DEINTERLACE_KEEP_EVEN && (y % 2 == 0)) || (o->keep == GEGL_DEINTERLACE_KEEP_ODD && (y % 2 != 0))) { deinterlace_horizontal (src_buf, dst_buf, result, &rect, &boundary, o->keep, y, o->size); } } else { for (x = result->x; x < result->x + result->width; x++) if ((o->keep == GEGL_DEINTERLACE_KEEP_EVEN && (x % 2 == 0)) || (o->keep == GEGL_DEINTERLACE_KEEP_ODD && (x % 2 != 0))) { deinterlace_vertical (src_buf, dst_buf, result, &rect, &boundary, o->keep, x, o->size); } } gegl_buffer_set (output, result, 0, format, dst_buf, GEGL_AUTO_ROWSTRIDE); g_free (src_buf); g_free (dst_buf); return TRUE; }
static void ico_image_get_reduced_buf (guint32 layer, gint bpp, gint *num_colors, guchar **cmap_out, guchar **buf_out) { gint32 tmp_image; gint32 tmp_layer; gint w, h; guchar *buf; guchar *cmap = NULL; GeglBuffer *buffer = gimp_drawable_get_buffer (layer); const Babl *format; w = gegl_buffer_get_width (buffer); h = gegl_buffer_get_height (buffer); switch (gimp_drawable_type (layer)) { case GIMP_RGB_IMAGE: format = babl_format ("R'G'B' u8"); break; case GIMP_RGBA_IMAGE: format = babl_format ("R'G'B'A u8"); break; case GIMP_GRAY_IMAGE: format = babl_format ("Y' u8"); break; case GIMP_GRAYA_IMAGE: format = babl_format ("Y'A u8"); break; case GIMP_INDEXED_IMAGE: case GIMP_INDEXEDA_IMAGE: format = gegl_buffer_get_format (buffer); default: g_return_if_reached (); } *num_colors = 0; buf = g_new (guchar, w * h * 4); if (bpp <= 8 || bpp == 24 || babl_format_get_bytes_per_pixel (format) != 4) { gint32 image = gimp_item_get_image (layer); GeglBuffer *tmp; 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, "tmp", w, h, gimp_drawable_type (layer), 100, GIMP_NORMAL_MODE); gimp_image_insert_layer (tmp_image, tmp_layer, -1, 0); tmp = gimp_drawable_get_buffer (tmp_layer); gegl_buffer_get (buffer, GEGL_RECTANGLE (0, 0, w, h), 1.0, format, buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); gegl_buffer_copy (buffer, NULL, GEGL_ABYSS_NONE, tmp, NULL); g_object_unref (tmp); if (! gimp_drawable_is_rgb (tmp_layer)) gimp_image_convert_rgb (tmp_image); if (bpp <= 8) { 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_buffer (tmp_layer); gegl_buffer_set (tmp, GEGL_RECTANGLE (0, 0, w, h), 0, format, buf, GEGL_AUTO_ROWSTRIDE); g_object_unref (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); cmap = gimp_image_get_colormap (tmp_image, num_colors); } gimp_image_convert_rgb (tmp_image); } else if (bpp == 24) { GimpParam *return_vals; gint n_return_vals; 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); } gimp_layer_add_alpha (tmp_layer); tmp = gimp_drawable_get_buffer (tmp_layer); gegl_buffer_get (tmp, GEGL_RECTANGLE (0, 0, w, h), 1.0, NULL, buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); g_object_unref (tmp); gimp_image_delete (tmp_image); } else { gegl_buffer_get (buffer, GEGL_RECTANGLE (0, 0, w, h), 1.0, format, buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); } g_object_unref (buffer); *cmap_out = cmap; *buf_out = buf; }
static void draw_tiles (GeglProperties *o, const GeglRectangle *rect, GeglBuffer *input, GeglBuffer *output, gint num_of_tiles, Tile *tiles) { const Babl *format; gfloat *tile_buffer; Tile *t; gint i; format = babl_format ("RGBA float"); tile_buffer = g_new0 (gfloat, 4 * o->tile_width * o->tile_height); if (o->wrap_around) { for (t = tiles, i = 0; i < num_of_tiles; i++, t++) { GeglRectangle tile_rect = { t->x, t->y, t->width, t->height }; gegl_buffer_get (input, &tile_rect, 1.0, format, tile_buffer, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); tile_rect.x += t->move_x; tile_rect.y += t->move_y; gegl_buffer_set (output, &tile_rect, 0, format, tile_buffer, GEGL_AUTO_ROWSTRIDE); if (tile_rect.x < 0 || tile_rect.x + tile_rect.width > rect->width || tile_rect.y < 0 || tile_rect.y + tile_rect.height > rect->height) { if (tile_rect.x < 0) { tile_rect.x = rect->width + tile_rect.x; } else if (tile_rect.x+tile_rect.width > rect->width) { tile_rect.x -= rect->width; } if (tile_rect.y < 0) { tile_rect.y = rect->height + tile_rect.y; } else if (tile_rect.y + tile_rect.height > rect->height) { tile_rect.y -= rect->height; } gegl_buffer_set (output, &tile_rect, 0, format, tile_buffer, GEGL_AUTO_ROWSTRIDE); } } } else { for (t = tiles, i = 0; i < num_of_tiles; i++, t++) { GeglRectangle tile_rect = { t->x, t->y, t->width, t->height }; gegl_buffer_get (input, &tile_rect, 1.0, format, tile_buffer, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); tile_rect.x += t->move_x; tile_rect.y += t->move_y; gegl_buffer_set (output, &tile_rect, 0, format, tile_buffer, GEGL_AUTO_ROWSTRIDE); } } g_free (tile_buffer); }
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; GeglBuffer *buffer; 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); cur_progress = 0; max_progress = height; if (len > (G_MAXSIZE / height / (alpha_frame ? (promote_to_rgb ? 4 : 2) : 1))) { g_message ("'%s' has a larger image size than GIMP can handle.", gimp_filename_to_utf8 (filename)); return -1; } if (alpha_frame) dest = (guchar *) g_malloc ((gsize)len * (gsize)height * (promote_to_rgb ? 4 : 2)); else dest = (guchar *) g_malloc ((gsize)len * (gsize)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"); buffer = gimp_drawable_get_buffer (layer_ID); gegl_buffer_set (buffer, GEGL_RECTANGLE (0, 0, len, height), 0, NULL, dest, GEGL_AUTO_ROWSTRIDE); g_free (dest); g_object_unref (buffer); gimp_progress_update (1.0); return image_ID; }
static void edge_laplace (GeglBuffer *src, const GeglRectangle *src_rect, GeglBuffer *dst, const GeglRectangle *dst_rect) { gint x,y; gint offset; gfloat *src_buf; gfloat *temp_buf; gfloat *dst_buf; gint src_width = src_rect->width; src_buf = g_new0 (gfloat, src_rect->width * src_rect->height * 4); temp_buf = g_new0 (gfloat, src_rect->width * src_rect->height * 4); dst_buf = g_new0 (gfloat, dst_rect->width * dst_rect->height * 4); gegl_buffer_get (src, src_rect, 1.0, babl_format ("RGBA float"), src_buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); for (y=0; y<dst_rect->height; y++) for (x=0; x<dst_rect->width; x++) { gfloat *src_pix; gfloat gradient[4] = {0.0f, 0.0f, 0.0f, 0.0f}; gint c; gfloat minval, maxval; gint i=x+LAPLACE_RADIUS, j=y+LAPLACE_RADIUS; offset = i + j * src_width; src_pix = src_buf + offset * 4; for (c=0;c<3;c++) { minmax (src_pix[c-src_width*4], src_pix[c+src_width*4], src_pix[c-4], src_pix[c+4], src_pix[c], &minval, &maxval); /* four-neighbourhood */ gradient[c] = 0.5f * fmaxf((maxval-src_pix[c]), (src_pix[c]-minval)); gradient[c] = (src_pix[c-4-src_width*4] + src_pix[c-src_width*4] + src_pix[c+4-src_width*4] + src_pix[c-4] -8.0f* src_pix[c] +src_pix[c+4] + src_pix[c-4+src_width*4] + src_pix[c+src_width*4] + src_pix[c+4+src_width*4]) > 0.0f? gradient[c] : -1.0f*gradient[c]; } //alpha gradient[3] = src_pix[3]; for (c=0; c<4;c++) temp_buf[offset*4+c] = gradient[c]; } //1-pixel edges offset = 0; for (y=0; y<dst_rect->height; y++) for (x=0; x<dst_rect->width; x++) { gfloat value[4] = {0.0f, 0.0f, 0.0f, 0.0f}; gint c; gint i=x+LAPLACE_RADIUS, j=y+LAPLACE_RADIUS; gfloat *src_pix = temp_buf + (i + j * src_width) * 4; for (c=0;c<3;c++) { gfloat current = src_pix[c]; current = ((current > 0.0f) && (src_pix[c-4-src_width*4] < 0.0f || src_pix[c+4-src_width*4] < 0.0f || src_pix[c -src_width*4] < 0.0f || src_pix[c-4+src_width*4] < 0.0f || src_pix[c+4+src_width*4] < 0.0f || src_pix[ +src_width*4] < 0.0f || src_pix[c-4 ] < 0.0f || src_pix[c+4 ] < 0.0f))? current : 0.0f; value[c] = current; } //alpha value[3] = src_pix[3]; for (c=0; c<4;c++) dst_buf[offset*4+c] = value[c]; offset++; } gegl_buffer_set (dst, dst_rect, 0, babl_format ("RGBA float"), dst_buf, GEGL_AUTO_ROWSTRIDE); g_free (src_buf); g_free (temp_buf); g_free (dst_buf); }
GeglBuffer * gimp_drawable_transform_buffer_rotate (GimpDrawable *drawable, GimpContext *context, GeglBuffer *orig_buffer, gint orig_offset_x, gint orig_offset_y, GimpRotationType rotate_type, gdouble center_x, gdouble center_y, gboolean clip_result, gint *new_offset_x, gint *new_offset_y) { GeglBuffer *new_buffer; GeglRectangle src_rect; GeglRectangle dest_rect; gint orig_x, orig_y; gint orig_width, orig_height; gint orig_bpp; gint new_x, new_y; gint new_width, new_height; g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL); g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), NULL); g_return_val_if_fail (GIMP_IS_CONTEXT (context), NULL); g_return_val_if_fail (GEGL_IS_BUFFER (orig_buffer), NULL); orig_x = orig_offset_x; orig_y = orig_offset_y; orig_width = gegl_buffer_get_width (orig_buffer); orig_height = gegl_buffer_get_height (orig_buffer); orig_bpp = babl_format_get_bytes_per_pixel (gegl_buffer_get_format (orig_buffer)); switch (rotate_type) { case GIMP_ROTATE_90: gimp_drawable_transform_rotate_point (orig_x, orig_y + orig_height, rotate_type, center_x, center_y, &new_x, &new_y); new_width = orig_height; new_height = orig_width; break; case GIMP_ROTATE_180: gimp_drawable_transform_rotate_point (orig_x + orig_width, orig_y + orig_height, rotate_type, center_x, center_y, &new_x, &new_y); new_width = orig_width; new_height = orig_height; break; case GIMP_ROTATE_270: gimp_drawable_transform_rotate_point (orig_x + orig_width, orig_y, rotate_type, center_x, center_y, &new_x, &new_y); new_width = orig_height; new_height = orig_width; break; default: g_return_val_if_reached (NULL); break; } if (clip_result && (new_x != orig_x || new_y != orig_y || new_width != orig_width || new_height != orig_height)) { GimpRGB bg; GeglColor *color; gint clip_x, clip_y; gint clip_width, clip_height; new_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, orig_width, orig_height), gegl_buffer_get_format (orig_buffer)); *new_offset_x = orig_x; *new_offset_y = orig_y; /* "Outside" a channel is transparency, not the bg color */ if (GIMP_IS_CHANNEL (drawable)) gimp_rgba_set (&bg, 0.0, 0.0, 0.0, 0.0); else gimp_context_get_background (context, &bg); color = gimp_gegl_color_new (&bg); gegl_buffer_set_color (new_buffer, NULL, color); g_object_unref (color); if (gimp_rectangle_intersect (orig_x, orig_y, orig_width, orig_height, new_x, new_y, new_width, new_height, &clip_x, &clip_y, &clip_width, &clip_height)) { gint saved_orig_x = orig_x; gint saved_orig_y = orig_y; new_x = clip_x - orig_x; new_y = clip_y - orig_y; switch (rotate_type) { case GIMP_ROTATE_90: gimp_drawable_transform_rotate_point (clip_x + clip_width, clip_y, GIMP_ROTATE_270, center_x, center_y, &orig_x, &orig_y); orig_x -= saved_orig_x; orig_y -= saved_orig_y; orig_width = clip_height; orig_height = clip_width; break; case GIMP_ROTATE_180: orig_x = clip_x - orig_x; orig_y = clip_y - orig_y; orig_width = clip_width; orig_height = clip_height; break; case GIMP_ROTATE_270: gimp_drawable_transform_rotate_point (clip_x, clip_y + clip_height, GIMP_ROTATE_90, center_x, center_y, &orig_x, &orig_y); orig_x -= saved_orig_x; orig_y -= saved_orig_y; orig_width = clip_height; orig_height = clip_width; break; } new_width = clip_width; new_height = clip_height; } else { new_width = 0; new_height = 0; } } else { new_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, new_width, new_height), gegl_buffer_get_format (orig_buffer)); *new_offset_x = new_x; *new_offset_y = new_y; orig_x = 0; orig_y = 0; new_x = 0; new_y = 0; } if (new_width < 1 || new_height < 1) return new_buffer; src_rect.x = orig_x; src_rect.y = orig_y; src_rect.width = orig_width; src_rect.height = orig_height; dest_rect.x = new_x; dest_rect.y = new_y; dest_rect.width = new_width; dest_rect.height = new_height; switch (rotate_type) { case GIMP_ROTATE_90: { guchar *buf = g_new (guchar, new_height * orig_bpp); gint i; g_assert (new_height == orig_width); src_rect.y = orig_y + orig_height - 1; src_rect.height = 1; dest_rect.x = new_x; dest_rect.width = 1; for (i = 0; i < orig_height; i++) { src_rect.y = orig_y + orig_height - 1 - i; dest_rect.x = new_x + i; gegl_buffer_get (orig_buffer, &src_rect, 1.0, NULL, buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); gegl_buffer_set (new_buffer, &dest_rect, 0, NULL, buf, GEGL_AUTO_ROWSTRIDE); } g_free (buf); } break; case GIMP_ROTATE_180: { guchar *buf = g_new (guchar, new_width * orig_bpp); gint i, j, k; g_assert (new_width == orig_width); src_rect.y = orig_y + orig_height - 1; src_rect.height = 1; dest_rect.y = new_y; dest_rect.height = 1; for (i = 0; i < orig_height; i++) { src_rect.y = orig_y + orig_height - 1 - i; dest_rect.y = new_y + i; gegl_buffer_get (orig_buffer, &src_rect, 1.0, NULL, buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); for (j = 0; j < orig_width / 2; j++) { guchar *left = buf + j * orig_bpp; guchar *right = buf + (orig_width - 1 - j) * orig_bpp; for (k = 0; k < orig_bpp; k++) { guchar tmp = left[k]; left[k] = right[k]; right[k] = tmp; } } gegl_buffer_set (new_buffer, &dest_rect, 0, NULL, buf, GEGL_AUTO_ROWSTRIDE); } g_free (buf); } break; case GIMP_ROTATE_270: { guchar *buf = g_new (guchar, new_width * orig_bpp); gint i; g_assert (new_width == orig_height); src_rect.x = orig_x + orig_width - 1; src_rect.width = 1; dest_rect.y = new_y; dest_rect.height = 1; for (i = 0; i < orig_width; i++) { src_rect.x = orig_x + orig_width - 1 - i; dest_rect.y = new_y + i; gegl_buffer_get (orig_buffer, &src_rect, 1.0, NULL, buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); gegl_buffer_set (new_buffer, &dest_rect, 0, NULL, buf, GEGL_AUTO_ROWSTRIDE); } g_free (buf); } break; } return new_buffer; }
static gint gegl_buffer_import_png (GeglBuffer *gegl_buffer, GInputStream *stream, gint dest_x, gint dest_y, gint *ret_width, gint *ret_height, const Babl *format, // can be NULL GError **err) { gint width; gint bit_depth; gint bpp; gint number_of_passes=1; png_uint_32 w; png_uint_32 h; png_structp load_png_ptr; png_infop load_info_ptr; guchar *pixels; /*png_bytep *rows;*/ unsigned int i; png_bytep *row_p = NULL; g_return_val_if_fail(stream, -1); if (!check_valid_png_header(stream, err)) { return -1; } load_png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, error_fn, NULL); if (!load_png_ptr) { return -1; } load_info_ptr = png_create_info_struct (load_png_ptr); if (!load_info_ptr) { png_destroy_read_struct (&load_png_ptr, &load_info_ptr, NULL); return -1; } if (setjmp (png_jmpbuf (load_png_ptr))) { png_destroy_read_struct (&load_png_ptr, &load_info_ptr, NULL); if (row_p) g_free (row_p); return -1; } png_set_read_fn(load_png_ptr, stream, read_fn); png_set_sig_bytes (load_png_ptr, 8); // we already read header png_read_info (load_png_ptr, load_info_ptr); { int color_type; int interlace_type; png_get_IHDR (load_png_ptr, load_info_ptr, &w, &h, &bit_depth, &color_type, &interlace_type, NULL, NULL); width = w; if (ret_width) *ret_width = w; if (ret_height) *ret_height = h; if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) { png_set_expand (load_png_ptr); bit_depth = 8; } if (png_get_valid (load_png_ptr, load_info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha (load_png_ptr); color_type |= PNG_COLOR_MASK_ALPHA; } switch (color_type) { case PNG_COLOR_TYPE_GRAY: bpp = 1; break; case PNG_COLOR_TYPE_GRAY_ALPHA: bpp = 2; break; case PNG_COLOR_TYPE_RGB: bpp = 3; break; case PNG_COLOR_TYPE_RGB_ALPHA: bpp = 4; break; case (PNG_COLOR_TYPE_PALETTE | PNG_COLOR_MASK_ALPHA): bpp = 4; break; case PNG_COLOR_TYPE_PALETTE: bpp = 3; break; default: g_warning ("color type mismatch"); png_destroy_read_struct (&load_png_ptr, &load_info_ptr, NULL); return -1; } if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb (load_png_ptr); if (bit_depth == 16) bpp = bpp << 1; if (!format) format = get_babl_format(bit_depth, color_type); #if BYTE_ORDER == LITTLE_ENDIAN if (bit_depth == 16) png_set_swap (load_png_ptr); #endif if (interlace_type == PNG_INTERLACE_ADAM7) number_of_passes = png_set_interlace_handling (load_png_ptr); if (png_get_valid (load_png_ptr, load_info_ptr, PNG_INFO_gAMA)) { gdouble gamma; png_get_gAMA (load_png_ptr, load_info_ptr, &gamma); png_set_gamma (load_png_ptr, 2.2, gamma); } else { png_set_gamma (load_png_ptr, 2.2, 0.45455); } png_read_update_info (load_png_ptr, load_info_ptr); } pixels = g_malloc0 (width*bpp); { gint pass; GeglRectangle rect; for (pass=0; pass<number_of_passes; pass++) { for(i=0; i<h; i++) { gegl_rectangle_set (&rect, 0, i, width, 1); if (pass != 0) gegl_buffer_get (gegl_buffer, &rect, 1.0, format, pixels, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); png_read_rows (load_png_ptr, &pixels, NULL, 1); gegl_buffer_set (gegl_buffer, &rect, 0, format, pixels, GEGL_AUTO_ROWSTRIDE); } } } png_read_end (load_png_ptr, NULL); png_destroy_read_struct (&load_png_ptr, &load_info_ptr, NULL); g_free (pixels); return 0; }
static gboolean find_contiguous_segment (const gfloat *col, GeglBuffer *src_buffer, GeglBuffer *mask_buffer, const Babl *format, gint n_components, gboolean has_alpha, gint width, gboolean select_transparent, GimpSelectCriterion select_criterion, gboolean antialias, gfloat threshold, gint initial_x, gint initial_y, gint *start, gint *end) { gfloat s[MAX_CHANNELS]; gfloat mask_row[width]; gfloat diff; gegl_buffer_sample (src_buffer, initial_x, initial_y, NULL, s, format, GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE); diff = pixel_difference (col, s, antialias, threshold, n_components, has_alpha, select_transparent, select_criterion); /* check the starting pixel */ if (! diff) return FALSE; mask_row[initial_x] = diff; *start = initial_x - 1; while (*start >= 0 && diff) { gegl_buffer_sample (src_buffer, *start, initial_y, NULL, s, format, GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE); diff = pixel_difference (col, s, antialias, threshold, n_components, has_alpha, select_transparent, select_criterion); mask_row[*start] = diff; if (diff) (*start)--; } diff = 1; *end = initial_x + 1; while (*end < width && diff) { gegl_buffer_sample (src_buffer, *end, initial_y, NULL, s, format, GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE); diff = pixel_difference (col, s, antialias, threshold, n_components, has_alpha, select_transparent, select_criterion); mask_row[*end] = diff; if (diff) (*end)++; } gegl_buffer_set (mask_buffer, GEGL_RECTANGLE (*start, initial_y, *end - *start, 1), 0, babl_format ("Y float"), &mask_row[*start], GEGL_AUTO_ROWSTRIDE); return TRUE; }
static void kuwahara (GeglBuffer *src, GeglBuffer *dst, gint radius) { gint u,v; gint offset; gfloat *src_buf; gfloat *dst_buf; src_buf = g_new0 (gfloat, gegl_buffer_get_pixel_count (src) * 4); dst_buf = g_new0 (gfloat, gegl_buffer_get_pixel_count (dst) * 4); gegl_buffer_get (src, NULL, 1.0, babl_format ("RGBA float"), src_buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); offset = 0; for (v=0; v<gegl_buffer_get_height (dst); v++) for (u=0; u<gegl_buffer_get_width (dst); u++) { gint component; for (component=0; component<3; component++) { gfloat value=0.0; gfloat best=1000000.0; gfloat mean = 0.0; gfloat variance = 0.0; compute_rectangle (src_buf, gegl_buffer_get_width (src), gegl_buffer_get_height (src), u - radius - 1, v - radius - 1, 1 + radius, 1 + radius, component, NULL, /* min */ NULL, /* max */ &mean, &variance); if (variance<best) { best = variance; value = mean; } compute_rectangle (src_buf, gegl_buffer_get_width (src), gegl_buffer_get_height (src), u, v - radius - 1, 1 + radius, 1 + radius, component, NULL, /* min */ NULL, /* max */ &mean, &variance); if (variance<best) { best = variance; value = mean; } compute_rectangle (src_buf, gegl_buffer_get_width (src), gegl_buffer_get_height (src), u - radius - 1, v, 1 + radius, 1 + radius, component, NULL, /* min */ NULL, /* max */ &mean, &variance); if (variance<best) { best = variance; value = mean; } compute_rectangle (src_buf, gegl_buffer_get_width (src), gegl_buffer_get_height (src), u, v, 1 + radius, 1 + radius, component, NULL, /* min */ NULL, /* max */ &mean, &variance); if (variance<best) { best = variance; value = mean; } dst_buf [offset++] = value; } dst_buf [offset] = src_buf[offset]; offset++; } gegl_buffer_set (dst, NULL, 0, babl_format ("RGBA float"), dst_buf, GEGL_AUTO_ROWSTRIDE); g_free (src_buf); g_free (dst_buf); }
static gboolean process (GeglOperation *operation, GeglBuffer *output, const GeglRectangle *result) { GeglChantO *o = GEGL_CHANT_PROPERTIES (operation); GeglRectangle rect = {0,0,0,0}; jas_image_t *image; gint width, height, depth; gsize bpc; guchar *data = NULL; gboolean ret; int components[3]; jas_matrix_t *matrices[3] = {NULL, NULL, NULL}; gint i; gint row; gboolean b; gushort *ptr_s; guchar *ptr_b; image = NULL; width = height = depth = 0; if (!query_jp2 (o->path, &width, &height, &depth, &image)) return FALSE; rect.height = height; rect.width = width; switch (depth) { case 8: bpc = sizeof (guchar); break; case 16: bpc = sizeof (gushort); break; default: g_warning ("%s: Programmer stupidity error", G_STRLOC); return FALSE; } data = (guchar *) g_malloc (width * height * 3 * bpc); ptr_s = (gushort *) data; ptr_b = data; switch (depth) { case 16: gegl_buffer_get (output, 1.0, &rect, babl_format ("R'G'B' u16"), data, GEGL_AUTO_ROWSTRIDE); break; case 8: default: gegl_buffer_get (output, 1.0, &rect, babl_format ("R'G'B' u8"), data, GEGL_AUTO_ROWSTRIDE); } ret = FALSE; b = FALSE; do { components[0] = jas_image_getcmptbytype (image, JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_R)); components[1] = jas_image_getcmptbytype (image, JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_G)); components[2] = jas_image_getcmptbytype (image, JAS_IMAGE_CT_COLOR(JAS_IMAGE_CT_RGB_B)); if ((components[0] < 0) || (components[1] < 0) || (components[2] < 0)) { g_warning (_("One or more of R, G, B components are missing " "from '%s'"), o->path); break; } if (jas_image_cmptsgnd (image, components[0]) || jas_image_cmptsgnd (image, components[1]) || jas_image_cmptsgnd (image, components[2])) { g_warning (_("One or more of R, G, B components have signed " "data in '%s'"), o->path); break; } for (i = 0; i < 3; i++) matrices[i] = jas_matrix_create(1, width); for (row = 0; row < height; row++) { gint plane, col; jas_seqent_t *jrow[3] = {NULL, NULL, NULL}; for (plane = 0; plane < 3; plane++) { int r = jas_image_readcmpt (image, components[plane], 0, row, width, 1, matrices[plane]); if (r) { g_warning (_("Error reading row %d component %d from '%s'"), row, plane, o->path); b = TRUE; break; } } if (b) break; for (plane = 0; plane < 3; plane++) jrow[plane] = jas_matrix_getref (matrices[plane], 0, 0); for (col = 0; col < width; col++) { switch (depth) { case 16: *ptr_s++ = (gushort) jrow[0][col]; *ptr_s++ = (gushort) jrow[1][col]; *ptr_s++ = (gushort) jrow[2][col]; break; case 8: default: *ptr_b++ = (guchar) jrow[0][col]; *ptr_b++ = (guchar) jrow[1][col]; *ptr_b++ = (guchar) jrow[2][col]; } } } if (b) break; switch (depth) { case 16: gegl_buffer_set (output, &rect, babl_format ("R'G'B' u16"), data, GEGL_AUTO_ROWSTRIDE); break; case 8: default: gegl_buffer_set (output, &rect, babl_format ("R'G'B' u8"), data, GEGL_AUTO_ROWSTRIDE); } ret = TRUE; } while (FALSE); /* structured goto */ for (i = 0; i < 3; i++) if (matrices[i]) jas_matrix_destroy (matrices[i]); if (data) g_free (data); if (image) jas_image_destroy (image); return ret; }