void  image_add_thumbnail_frame(GdkPixbuf *img)
{
    guint32 outline     = IMAGEFU_COLOR(0xFF, 0x55, 0x55, 0x55);
    guint32 transparent = IMAGEFU_COLOR(0x00, 0xFF, 0xFF, 0xFF);
    guint32 shadow      = IMAGEFU_COLOR(0x22, 0x00, 0x00, 0x00);
    int width = gdk_pixbuf_get_width(img);
    int height = gdk_pixbuf_get_height(img);
    if (width <= 2)
        return;
    if (height <= 2)
        return;

    image_draw_rect_outline(img, 0, 0, width, height, transparent);
    image_draw_rect_outline(img, 1, 1, width-2, height-2, outline);
    image_draw_hline(img, 2, height-1, width-2, shadow);
    image_draw_vline(img, width-1, 2, height-2, shadow);
}
static void
histogram_imager_generate_color_table (HistogramImager *self, gboolean force)
{
    /* Regenerate the contents of the color mapping table, a mapping from all
     * possible histogram values to the corresponding ARGB color, in the current image.
     */
    guint count;
    float pixel_scale = histogram_imager_get_pixel_scale (self);
    gulong usable_density = histogram_imager_get_max_usable_density (self);
    float luma;
    double one_over_gamma = 1/self->gamma;
    float distance = 0;
    gulong color_table_size;
    struct {
	int r, g, b, a;
    } current, previous;

    /* Our actual color table size should be either the maximum
     * usable density, or our histogram's current peak density,
     * whichever is smaller.
     */
    if (usable_density > self->peak_density)
	usable_density = self->peak_density;

    /* If the table is already the right size and we aren't being
     * forced to regenerate it, stop now.
     */
    color_table_size = usable_density + 1;
    if ((!force) && self->color_table.filled_size == color_table_size)
	return;

    /* Make sure our table is appropriately sized */
    histogram_imager_resize_color_table (self, color_table_size);

    /* Generate one color for every currently-possible count value that
     * doesn't fully saturate our image, as determined by histogram_imager_get_max_usable_density
     */
    for (count=0; count < self->color_table.filled_size; count++) {

	/* Scale and gamma-correct */
	luma = count * pixel_scale;
	luma = pow(luma, one_over_gamma);

	/* Optionally clamp before interpolating */
	if (self->clamped && luma > 1)
	    luma = 1;

	/* Linearly interpolate between fgcolor and bgcolor */
	current.r = ((int)(self->bgcolor.red   * (1-luma) + self->fgcolor.red   * luma)) >> 8;
	current.g = ((int)(self->bgcolor.green * (1-luma) + self->fgcolor.green * luma)) >> 8;
	current.b = ((int)(self->bgcolor.blue  * (1-luma) + self->fgcolor.blue  * luma)) >> 8;
	current.a = ((int)(self->bgalpha       * (1-luma) + self->fgalpha       * luma)) >> 8;

	/* Always clamp color components */
	if (current.r<0) current.r = 0;  if (current.r>255) current.r = 255;
	if (current.g<0) current.g = 0;  if (current.g>255) current.g = 255;
	if (current.b<0) current.b = 0;  if (current.b>255) current.b = 255;
	if (current.a<0) current.a = 0;  if (current.a>255) current.a = 255;

	/* Colors are always ARGB order in little endian */
	self->color_table.table[count] = IMAGEFU_COLOR(current.a, current.r, current.g, current.b);

	/* Update our elapsed distance */
	if (count > 0) {
	    distance += sqrt( (current.r - previous.r) * (current.r - previous.r) +
			      (current.g - previous.g) * (current.g - previous.g) +
			      (current.b - previous.b) * (current.b - previous.b) +
			      (current.a - previous.a) * (current.a - previous.a) );
	}
	previous = current;

	/* "distance" is the distance we've traveled from the background to this
	 * point in the color hypercube. Our quality metric is based on the number
	 * of histogram samples per color cube samples: our 'quality' table stores
	 * the current count divided by its corresponding distance.
	 */
	if (distance > 0) {
	    self->color_table.quality[count] = count / distance;
	}
	else {
	    /* We shouldn't ever use quality entries where the distance
	     * is zero- this value is pretty arbitrary.
	     */
	    self->color_table.quality[count] = 0;
	}
    }
}