void update(double time, uint32_t* out, const uint32_t* in1, const uint32_t* in2, const uint32_t* in3) { uint8_t *dst = reinterpret_cast<uint8_t*>(out); const uint8_t *src1 = reinterpret_cast<const uint8_t*>(in1); const uint8_t *src2 = reinterpret_cast<const uint8_t*>(in2); for (int i=0; i<size; ++i) { uint32_t tmp; uint8_t alpha_src1 = src1[3]; uint8_t alpha_src2 = src2[3]; uint8_t alpha_dst; uint8_t w1 = alpha_src2; uint8_t w2 = 0xff ^ alpha_src1; // w2 = 255 - alpha_1 // compute destination alpha alpha_dst = dst[3] = w1; // compute destination values if (alpha_dst == 0) for (int b=0; b<3; ++b) dst[b] = 0; else for (int b=0; b<3; ++b) dst[b] = CLAMP0255( (uint32_t)( (uint32_t) (INT_MULT(src1[b], alpha_src1, tmp) * w1 + INT_MULT(src2[b], alpha_src2, tmp) * w2) / alpha_dst) ); src1 += 4; src2 += 4; dst += 4; } }
/* * For each i in [0, HISTSIZE), hist[i] is the number of occurrences of the * value i. Return a value in [0, HISTSIZE) weighted heavily toward the * most frequent values in the histogram. * * Assuming that hist_max is the maximum number of occurrences for any * one value in the histogram, the weight given to each value i is * * weight = (hist[i] / hist_max)^exponent * * (i.e. the normalized histogram frequency raised to some power) */ static inline guchar weighted_average_value (gint hist[HISTSIZE], gfloat exponent) { gint i; gint hist_max = 1; gint exponent_int = 0; gfloat sum = 0.0; gfloat div = 1.0e-6; gint value; for (i = 0; i < HISTSIZE; i++) hist_max = MAX (hist_max, hist[i]); if ((exponent - floor (exponent)) < 0.001 && exponent <= 255.0) exponent_int = (gint) exponent; for (i = 0; i < HISTSIZE; i++) { gfloat ratio = (gfloat) hist[i] / (gfloat) hist_max; gfloat weight; if (exponent_int) weight = fast_powf (ratio, exponent_int); else weight = pow (ratio, exponent); sum += weight * (gfloat) i; div += weight; } value = (gint) (sum / div); return (guchar) CLAMP0255 (value); }
static void graya_filter (gint width, /* I - Width of line in pixels */ guchar *src, /* I - Source line */ guchar *dst, /* O - Destination line */ intneg *neg0, /* I - Top negative coefficient line */ intneg *neg1, /* I - Middle negative coefficient line */ intneg *neg2) /* I - Bottom negative coefficient line */ { intpos pixel; /* New pixel value */ *dst++ = *src++; *dst++ = *src++; width -= 2; while (width > 0) { pixel = (pos_lut[*src++] - neg0[-2] - neg0[0] - neg0[2] - neg1[-2] - neg1[2] - neg2[-2] - neg2[0] - neg2[2]); pixel = (pixel + 4) >> 3; *dst++ = CLAMP0255 (pixel); *dst++ = *src++; neg0 += 2; neg1 += 2; neg2 += 2; width --; } *dst++ = *src++; *dst++ = *src++; }
static gint edge_detect (const guchar *data) { gint ret; switch (evals.edgemode) { case SOBEL: ret = sobel (data); break; case PREWITT: ret = prewitt (data); break; case GRADIENT: ret = gradient (data); break; case ROBERTS: ret = roberts (data); break; case DIFFERENTIAL: ret = differential (data); break; case LAPLACE: ret = laplace (data); break; default: ret = -1; break; } return CLAMP0255 (ret); }
void updateLookUpTables(const uint32_t* in) { unsigned int size = width*height; // First pass : build histograms. // Reset histograms. memset(rhist, 0, 256*sizeof(unsigned int)); memset(ghist, 0, 256*sizeof(unsigned int)); memset(bhist, 0, 256*sizeof(unsigned int)); // Update histograms. const unsigned char *in_ptr = (const unsigned char*) in; for (unsigned int i=0; i<size; ++i) { // update 'em rhist[*in_ptr++]++; ghist[*in_ptr++]++; bhist[*in_ptr++]++; in_ptr++; // skip alpha } // Second pass : update look-up tables. in_ptr = (const unsigned char*) in; // Cumulative intensities of histograms. unsigned int rcum = 0, gcum = 0, bcum = 0; for (int i=0; i<256; ++i) { // update cumulatives rcum += rhist[i]; gcum += ghist[i]; bcum += bhist[i]; // update 'em rlut[i] = CLAMP0255( (rcum << 8) / size ); // = 256 * rcum / size glut[i] = CLAMP0255( (gcum << 8) / size ); // = 256 * gcum / size blut[i] = CLAMP0255( (bcum << 8) / size ); // = 256 * bcum / size in_ptr++; // skip alpha } }
static guchar* rgb_to_hsl (GimpDrawable *drawable, LICEffectChannel effect_channel) { guchar *themap, data[4]; gint x, y; GimpRGB color; GimpHSL color_hsl; gdouble val = 0.0; glong maxc, index = 0; GimpPixelRgn region; GRand *gr; gr = g_rand_new (); maxc = drawable->width * drawable->height; gimp_pixel_rgn_init (®ion, drawable, border_x, border_y, border_w, border_h, FALSE, FALSE); themap = g_new (guchar, maxc); for (y = 0; y < region.h; y++) { for (x = 0; x < region.w; x++) { data[3] = 255; gimp_pixel_rgn_get_pixel (®ion, data, x, y); gimp_rgba_set_uchar (&color, data[0], data[1], data[2], data[3]); gimp_rgb_to_hsl (&color, &color_hsl); switch (effect_channel) { case LIC_HUE: val = color_hsl.h * 255; break; case LIC_SATURATION: val = color_hsl.s * 255; break; case LIC_BRIGHTNESS: val = color_hsl.l * 255; break; } /* add some random to avoid unstructured areas. */ val += g_rand_double_range (gr, -1.0, 1.0); themap[index++] = (guchar) CLAMP0255 (RINT (val)); } } g_rand_free (gr); return themap; }
void alpha_demultiply(unsigned char *src, unsigned int n) { float mult; while (n--) { mult = (src[IDX_RGBA_A] == 0 ? 255.0f : 255.0f / (float)src[IDX_RGBA_A]); for (int i=0; i<SIZE_RGB; ++i) src[i] = CLAMP0255( (unsigned int) ((float)src[i] * mult ) ); src += SIZE_RGBA; } }
static inline guchar cm_mix_pixel (CmChannelType *ch, guchar r, guchar g, guchar b, gdouble norm) { gdouble c = ch->red_gain * r + ch->green_gain * g + ch->blue_gain * b; c *= norm; return (guchar) CLAMP0255 (c); }
virtual void update(double time, uint32_t* out, const uint32_t* in, const uint32_t* in2, const uint32_t* in3) { // Rebuild the lookup table in case the prarameters have changed. updateLUT(); unsigned char *pixel = (unsigned char *) in; unsigned char *dest = (unsigned char *) out; if (fabs(m_sat-1) < 0.001) { // Calculating the saturation is expensive. So first check whether // we really need to do it. // Keeping the if/else outside of the loop gives a little speed gain. // Worth the duplicate code, as only 4 lines so far :) for (unsigned int i = 0; i < size; i++) { *dest++ = m_lutR[*pixel++]; *dest++ = m_lutG[*pixel++]; *dest++ = m_lutB[*pixel++]; *dest++ = m_lutA[*pixel++]; } } else { double luma; for (unsigned int i = 0; i < size; i++) { luma = 0.2126 * m_lutR[*(pixel+0)] + 0.7152 * m_lutG[*(pixel+1)] + 0.0722 * m_lutB[*(pixel+2)]; *dest++ = CLAMP0255(luma + m_sat*(m_lutR[*pixel++]-luma)); *dest++ = CLAMP0255(luma + m_sat*(m_lutG[*pixel++]-luma)); *dest++ = CLAMP0255(luma + m_sat*(m_lutB[*pixel++]-luma)); *dest++ = m_lutA[*pixel++]; } } }
void HSLFilter::setSaturation(double val) { val = CLAMP(val, -100.0, 100.0); int value; for (int i = 0; i < 65536; ++i) { value = lround( (i * (100.0 + val)) / 100.0 ); d->stransfer16[i] = CLAMP065535(value); } for (int i = 0; i < 256; ++i) { value = lround( (i * (100.0 + val)) / 100.0 ); d->stransfer[i] = CLAMP0255(value); } }
/* * For each i in [0, HISTSIZE), hist[i] is the number of occurrences of * pixels with intensity i. hist_rgb[][i] is the average color of those * pixels with intensity i, but with each channel multiplied by hist[i]. * Write to dest a pixel whose color is a weighted average of all the * colors in hist_rgb[][], biased heavily toward those with the most * frequently-occurring intensities (as noted in hist[]). * * The weight formula is the same as in weighted_average_value(). */ static inline void weighted_average_color (gint hist[HISTSIZE], gint hist_rgb[4][HISTSIZE], gfloat exponent, guchar *dest, gint bpp) { gint i, b; gint hist_max = 1; gint exponent_int = 0; gfloat div = 1.0e-6; gfloat color[4] = { 0.0, 0.0, 0.0, 0.0 }; for (i = 0; i < HISTSIZE; i++) hist_max = MAX (hist_max, hist[i]); if ((exponent - floor (exponent)) < 0.001 && exponent <= 255.0) exponent_int = (gint) exponent; for (i = 0; i < HISTSIZE; i++) { gfloat ratio = (gfloat) hist[i] / (gfloat) hist_max; gfloat weight; if (exponent_int) weight = fast_powf (ratio, exponent_int); else weight = pow (ratio, exponent); if (hist[i] > 0) for (b = 0; b < bpp; b++) color[b] += weight * (gfloat) hist_rgb[b][i] / (gfloat) hist[i]; div += weight; } for (b = 0; b < bpp; b++) { gint c = (gint) (color[b] / div); dest[b] = (guchar) CLAMP0255 (c); } }
static void transfer_pixels (gdouble *src1, gdouble *src2, guchar *dest, gint jump, gint width) { gint i; gdouble sum; for (i = 0; i < width; i++) { sum = src1[i] + src2[i]; sum = CLAMP0255 (sum); *dest = (guchar) sum; dest += jump; } }
/* This function chooses a gray value for the text color, based on * the average luminance of the text area of the splash image. */ static gboolean splash_average_text_area (GimpSplash *splash, GdkPixbuf *pixbuf, GdkColor *color) { const guchar *pixels; gint rowstride; gint channels; gint luminance = 0; guint sum[3] = { 0, 0, 0 }; GdkRectangle image = { 0, 0, 0, 0 }; GdkRectangle area = { 0, 0, 0, 0 }; g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), FALSE); g_return_val_if_fail (gdk_pixbuf_get_bits_per_sample (pixbuf) == 8, FALSE); image.width = gdk_pixbuf_get_width (pixbuf); image.height = gdk_pixbuf_get_height (pixbuf); rowstride = gdk_pixbuf_get_rowstride (pixbuf); channels = gdk_pixbuf_get_n_channels (pixbuf); pixels = gdk_pixbuf_get_pixels (pixbuf); splash_position_layouts (splash, "Short text", "Somewhat longer text", &area); splash_position_layouts (splash, "", "", NULL); if (gdk_rectangle_intersect (&image, &area, &area)) { const gint count = area.width * area.height; gint x, y; pixels += area.x * channels; pixels += area.y * rowstride; for (y = 0; y < area.height; y++) { const guchar *src = pixels; for (x = 0; x < area.width; x++) { sum[0] += src[0]; sum[1] += src[1]; sum[2] += src[2]; src += channels; } pixels += rowstride; } luminance = GIMP_RGB_LUMINANCE (sum[0] / count, sum[1] / count, sum[2] / count); luminance = CLAMP0255 (luminance > 127 ? luminance - 223 : luminance + 223); } color->red = color->green = color->blue = (luminance << 8 | luminance); return gdk_colormap_alloc_color (gtk_widget_get_colormap (splash->area), color, FALSE, TRUE); }
void BCGFilter::applyBCG(uchar* const bits, uint width, uint height, bool sixteenBits) { if (!bits) { return; } uint size = width * height; int progress; if (!sixteenBits) // 8 bits image. { uchar* data = bits; for (uint i = 0; runningFlag() && (i < size); ++i) { switch (d->settings.channel) { case BlueChannel: data[0] = CLAMP0255(d->map[data[0]]); break; case GreenChannel: data[1] = CLAMP0255(d->map[data[1]]); break; case RedChannel: data[2] = CLAMP0255(d->map[data[2]]); break; default: // all channels data[0] = CLAMP0255(d->map[data[0]]); data[1] = CLAMP0255(d->map[data[1]]); data[2] = CLAMP0255(d->map[data[2]]); break; } data += 4; progress = (int)(((double)i * 100.0) / size); if (progress % 5 == 0) { postProgress(progress); } } } else // 16 bits image. { ushort* data = reinterpret_cast<ushort*>(bits); for (uint i = 0; runningFlag() && (i < size); ++i) { switch (d->settings.channel) { case BlueChannel: data[0] = CLAMP065535(d->map16[data[0]]); break; case GreenChannel: data[1] = CLAMP065535(d->map16[data[1]]); break; case RedChannel: data[2] = CLAMP065535(d->map16[data[2]]); break; default: // all channels data[0] = CLAMP065535(d->map16[data[0]]); data[1] = CLAMP065535(d->map16[data[1]]); data[2] = CLAMP065535(d->map16[data[2]]); break; } data += 4; progress = (int)(((double)i * 100.0) / size); if (progress % 5 == 0) { postProgress(progress); } } } }
static void compute_difference (GimpDrawable *drawable, GimpDrawable *drawable1, GimpDrawable *drawable2, guchar *maxval) { GimpPixelRgn src1_rgn, src2_rgn, dest_rgn; gint width, height; gint bpp; gpointer pr; gint x, y, k; gint x1, y1, x2, y2; gboolean has_alpha; *maxval = 0; gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2); width = (x2 - x1); height = (y2 - y1); if (width < 1 || height < 1) return; bpp = drawable->bpp; has_alpha = gimp_drawable_has_alpha (drawable->drawable_id); gimp_pixel_rgn_init (&src1_rgn, drawable1, 0, 0, drawable1->width, drawable1->height, FALSE, FALSE); gimp_pixel_rgn_init (&src2_rgn, drawable2, 0, 0, drawable1->width, drawable1->height, FALSE, FALSE); gimp_pixel_rgn_init (&dest_rgn, drawable, 0, 0, drawable->width, drawable->height, TRUE, TRUE); for (pr = gimp_pixel_rgns_register (3, &src1_rgn, &src2_rgn, &dest_rgn); pr != NULL; pr = gimp_pixel_rgns_process (pr)) { guchar *src1 = src1_rgn.data; guchar *src2 = src2_rgn.data; guchar *dest = dest_rgn.data; gint row = src1_rgn.y - y1; for (y = 0; y < src1_rgn.h; y++, row++) { guchar *s1 = src1; guchar *s2 = src2; guchar *d = dest; gint col = src1_rgn.x - x1; for (x = 0; x < src1_rgn.w; x++, col++) { if (has_alpha) { for (k = 0; k < bpp-1; k++) { d[k] = CLAMP0255 (s1[k] - s2[k]); *maxval = MAX (d[k], *maxval); } } else { for (k = 0; k < bpp; k++) { d[k] = CLAMP0255 (s1[k] - s2[k]); *maxval = MAX (d[k], *maxval); } } s1 += bpp; s2 += bpp; d += bpp; } src1 += src1_rgn.rowstride; src2 += src2_rgn.rowstride; dest += dest_rgn.rowstride; } } }
static void curves_plot_curve (Curves *curves, gint channel, gint p1, gint p2, gint p3, gint p4) { gint i; gdouble x0, x3; gdouble y0, y1, y2, y3; gdouble dx, dy; gdouble y, t; gdouble slope; /* the outer control points for the bezier curve. */ x0 = curves->points[channel][p2][0]; y0 = curves->points[channel][p2][1]; x3 = curves->points[channel][p3][0]; y3 = curves->points[channel][p3][1]; /* * the x values of the inner control points are fixed at * x1 = 1/3*x0 + 2/3*x3 and x2 = 2/3*x0 + 1/3*x3 * this ensures that the x values increase linearily with the * parameter t and enables us to skip the calculation of the x * values altogehter - just calculate y(t) evenly spaced. */ dx = x3 - x0; dy = y3 - y0; g_return_if_fail (dx > 0); if (p1 == p2 && p3 == p4) { /* No information about the neighbors, * calculate y1 and y2 to get a straight line */ y1 = y0 + dy / 3.0; y2 = y0 + dy * 2.0 / 3.0; } else if (p1 == p2 && p3 != p4) { /* only the right neighbor is available. Make the tangent at the * right endpoint parallel to the line between the left endpoint * and the right neighbor. Then point the tangent at the left towards * the control handle of the right tangent, to ensure that the curve * does not have an inflection point. */ slope = (curves->points[channel][p4][1] - y0) / (curves->points[channel][p4][0] - x0); y2 = y3 - slope * dx / 3.0; y1 = y0 + (y2 - y0) / 2.0; } else if (p1 != p2 && p3 == p4) { /* see previous case */ slope = (y3 - curves->points[channel][p1][1]) / (x3 - curves->points[channel][p1][0]); y1 = y0 + slope * dx / 3.0; y2 = y3 + (y1 - y3) / 2.0; } else /* (p1 != p2 && p3 != p4) */ { /* Both neighbors are available. Make the tangents at the endpoints * parallel to the line between the opposite endpoint and the adjacent * neighbor. */ slope = (y3 - curves->points[channel][p1][1]) / (x3 - curves->points[channel][p1][0]); y1 = y0 + slope * dx / 3.0; slope = (curves->points[channel][p4][1] - y0) / (curves->points[channel][p4][0] - x0); y2 = y3 - slope * dx / 3.0; } /* * finally calculate the y(t) values for the given bezier values. We can * use homogenously distributed values for t, since x(t) increases linearily. */ for (i = 0; i <= dx; i++) { t = i / dx; y = y0 * (1-t) * (1-t) * (1-t) + 3 * y1 * (1-t) * (1-t) * t + 3 * y2 * (1-t) * t * t + y3 * t * t * t; curves->curve[channel][ROUND(x0) + i] = CLAMP0255 (ROUND (y)); } }
/** * jpeg_detect_original_settings: * @cinfo: a pointer to a JPEG decompressor info. * @image_ID: the image to which the parasite should be attached. * * Analyze the image being decompressed (@cinfo) and extract the * sampling factors, quantization tables and overall image quality. * Store this information in a parasite and attach it to @image_ID. * * This function must be called after jpeg_read_header() so that * @cinfo contains the quantization tables and the sampling factors * for each component. * * Return Value: TRUE if a parasite has been attached to @image_ID. */ gboolean jpeg_detect_original_settings (struct jpeg_decompress_struct *cinfo, gint32 image_ID) { guint parasite_size; guchar *parasite_data; GimpParasite *parasite; guchar *dest; gint quality; gint num_quant_tables = 0; gint t; gint i; g_return_val_if_fail (cinfo != NULL, FALSE); if (cinfo->jpeg_color_space == JCS_UNKNOWN || cinfo->out_color_space == JCS_UNKNOWN) return FALSE; quality = jpeg_detect_quality (cinfo); /* no need to attach quantization tables if they are the ones from IJG */ if (quality <= 0) { for (t = 0; t < 4; t++) if (cinfo->quant_tbl_ptrs[t]) num_quant_tables++; } parasite_size = 4 + cinfo->num_components * 2 + num_quant_tables * 128; parasite_data = g_new (guchar, parasite_size); dest = parasite_data; *dest++ = CLAMP0255 (cinfo->jpeg_color_space); *dest++ = ABS (quality); *dest++ = CLAMP0255 (cinfo->num_components); *dest++ = num_quant_tables; for (i = 0; i < cinfo->num_components; i++) { *dest++ = CLAMP0255 (cinfo->comp_info[i].h_samp_factor); *dest++ = CLAMP0255 (cinfo->comp_info[i].v_samp_factor); } if (quality <= 0) { for (t = 0; t < 4; t++) if (cinfo->quant_tbl_ptrs[t]) for (i = 0; i < DCTSIZE2; i++) { guint16 c = cinfo->quant_tbl_ptrs[t]->quantval[i]; *dest++ = c / 256; *dest++ = c & 255; } } parasite = gimp_parasite_new ("jpeg-settings", GIMP_PARASITE_PERSISTENT, parasite_size, parasite_data); g_free (parasite_data); gimp_image_parasite_attach (image_ID, parasite); gimp_parasite_free (parasite); return TRUE; }
void color_balance_create_lookup_tables (ColorBalance *cb) { gdouble *cyan_red_transfer[3]; gdouble *magenta_green_transfer[3]; gdouble *yellow_blue_transfer[3]; gint i; gint32 r_n, g_n, b_n; g_return_if_fail (cb != NULL); if (! transfer_initialized) { color_balance_transfer_init (); transfer_initialized = TRUE; } /* Set the transfer arrays (for speed) */ cyan_red_transfer[GIMP_SHADOWS] = (cb->cyan_red[GIMP_SHADOWS] > 0) ? shadows_add : shadows_sub; cyan_red_transfer[GIMP_MIDTONES] = (cb->cyan_red[GIMP_MIDTONES] > 0) ? midtones_add : midtones_sub; cyan_red_transfer[GIMP_HIGHLIGHTS] = (cb->cyan_red[GIMP_HIGHLIGHTS] > 0) ? highlights_add : highlights_sub; magenta_green_transfer[GIMP_SHADOWS] = (cb->magenta_green[GIMP_SHADOWS] > 0) ? shadows_add : shadows_sub; magenta_green_transfer[GIMP_MIDTONES] = (cb->magenta_green[GIMP_MIDTONES] > 0) ? midtones_add : midtones_sub; magenta_green_transfer[GIMP_HIGHLIGHTS] = (cb->magenta_green[GIMP_HIGHLIGHTS] > 0) ? highlights_add : highlights_sub; yellow_blue_transfer[GIMP_SHADOWS] = (cb->yellow_blue[GIMP_SHADOWS] > 0) ? shadows_add : shadows_sub; yellow_blue_transfer[GIMP_MIDTONES] = (cb->yellow_blue[GIMP_MIDTONES] > 0) ? midtones_add : midtones_sub; yellow_blue_transfer[GIMP_HIGHLIGHTS] = (cb->yellow_blue[GIMP_HIGHLIGHTS] > 0) ? highlights_add : highlights_sub; for (i = 0; i < 256; i++) { r_n = i; g_n = i; b_n = i; r_n += cb->cyan_red[GIMP_SHADOWS] * cyan_red_transfer[GIMP_SHADOWS][r_n]; r_n = CLAMP0255 (r_n); r_n += cb->cyan_red[GIMP_MIDTONES] * cyan_red_transfer[GIMP_MIDTONES][r_n]; r_n = CLAMP0255 (r_n); r_n += cb->cyan_red[GIMP_HIGHLIGHTS] * cyan_red_transfer[GIMP_HIGHLIGHTS][r_n]; r_n = CLAMP0255 (r_n); g_n += cb->magenta_green[GIMP_SHADOWS] * magenta_green_transfer[GIMP_SHADOWS][g_n]; g_n = CLAMP0255 (g_n); g_n += cb->magenta_green[GIMP_MIDTONES] * magenta_green_transfer[GIMP_MIDTONES][g_n]; g_n = CLAMP0255 (g_n); g_n += cb->magenta_green[GIMP_HIGHLIGHTS] * magenta_green_transfer[GIMP_HIGHLIGHTS][g_n]; g_n = CLAMP0255 (g_n); b_n += cb->yellow_blue[GIMP_SHADOWS] * yellow_blue_transfer[GIMP_SHADOWS][b_n]; b_n = CLAMP0255 (b_n); b_n += cb->yellow_blue[GIMP_MIDTONES] * yellow_blue_transfer[GIMP_MIDTONES][b_n]; b_n = CLAMP0255 (b_n); b_n += cb->yellow_blue[GIMP_HIGHLIGHTS] * yellow_blue_transfer[GIMP_HIGHLIGHTS][b_n]; b_n = CLAMP0255 (b_n); cb->r_lookup[i] = r_n; cb->g_lookup[i] = g_n; cb->b_lookup[i] = b_n; } }