Beispiel #1
0
/* Scroll to make an xywh area visible. If the area is larger than the
 * viewport, position the view at the bottom left if the xywh area ... 
 * this is usually right for workspaces.
 */
void
workspaceview_scroll( Workspaceview *wview, int x, int y, int w, int h )
{
	GtkAdjustment *hadj = gtk_scrolled_window_get_hadjustment( 
		GTK_SCROLLED_WINDOW( wview->window ) );
	GtkAdjustment *vadj = gtk_scrolled_window_get_vadjustment( 
		GTK_SCROLLED_WINDOW( wview->window ) );
        Rect *vp = &wview->vp;
        int nx, ny;

        nx = hadj->value;
        if( x + w > IM_RECT_RIGHT( vp ) )
                nx = IM_MAX( 0, (x + w) - vp->width );
        if( x < nx )
                nx = x;

        ny = vadj->value;
        if( y + h > IM_RECT_BOTTOM( vp ) )
                ny = IM_MAX( 0, (y + h) - vp->height );
        if( y < ny )
                ny = y;

#ifdef DEBUG
        printf( "workspaceview_scroll: x=%d, y=%d, w=%d, h=%d, "
                "nx = %d, ny = %d\n", x, y, w, h, nx, ny );
#endif /*DEBUG*/

	adjustments_set_value( hadj, vadj, nx, ny );
}
Beispiel #2
0
static xmlNode *
column_save( Model *model, xmlNode *xnode )
{
	Column *col = COLUMN( model );
	int x = IM_MAX( 0, col->x - column_left_offset );
	int y = IM_MAX( 0, col->y - column_top_offset );

	xmlNode *xthis;

	if( !(xthis = MODEL_CLASS( parent_class )->save( model, xnode )) )
		return( NULL );

	/* Save sform for backwards compat with nip 7.8 ... now a workspace
	 * property.
	 */
	if( !set_iprop( xthis, "x", x ) ||
		!set_iprop( xthis, "y", y ) ||
		!set_sprop( xthis, "open", bool_to_char( col->open ) ) ||
		!set_sprop( xthis, "selected",
			bool_to_char( col->selected ) ) ||
		!set_sprop( xthis, "sform", bool_to_char( FALSE ) ) ||
		!set_iprop( xthis, "next", col->next ) || 
		!set_sprop( xthis, "name", IOBJECT( col )->name ) )
		return( NULL );

	/* Caption can be NULL for untitled columns.
	 */
	if( IOBJECT( col )->caption )
		if( !set_sprop( xthis, "caption", IOBJECT( col )->caption ) ) 
			return( NULL );

	return( xthis );
}
Beispiel #3
0
static void imlib_sub_line_op(image_t *img, int line, void *other, void *data, bool vflipped)
{
    bool reverse = ((imlib_sub_line_op_state_t *) data)->reverse;
    image_t *mask = ((imlib_sub_line_op_state_t *) data)->mask;

    switch(img->bpp) {
        case IMAGE_BPP_BINARY: {
            uint32_t *data = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line);
            for (int i = 0, j = img->w; i < j; i++) {
                if ((!mask) || image_get_mask_pixel(mask, i, line)) {
                    int dataPixel = IMAGE_GET_BINARY_PIXEL_FAST(data, i);
                    int otherPixel = IMAGE_GET_BINARY_PIXEL_FAST(((uint32_t *) other), i);
                    int p = reverse ? (otherPixel - dataPixel) : (dataPixel - otherPixel);
                    p = IM_MAX(p, COLOR_BINARY_MIN);
                    IMAGE_PUT_BINARY_PIXEL_FAST(data, i, p);
                }
            }
            break;
        }
        case IMAGE_BPP_GRAYSCALE: {
            uint8_t *data = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line);
            for (int i = 0, j = img->w; i < j; i++) {
                if ((!mask) || image_get_mask_pixel(mask, i, line)) {
                    int dataPixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(data, i);
                    int otherPixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(((uint8_t *) other), i);
                    int p = reverse ? (otherPixel - dataPixel) : (dataPixel - otherPixel);
                    p = IM_MAX(p, COLOR_GRAYSCALE_MIN);
                    IMAGE_PUT_GRAYSCALE_PIXEL_FAST(data, i, p);
                }
            }
            break;
        }
        case IMAGE_BPP_RGB565: {
            uint16_t *data = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line);
            for (int i = 0, j = img->w; i < j; i++) {
                if ((!mask) || image_get_mask_pixel(mask, i, line)) {
                    int dataPixel = IMAGE_GET_RGB565_PIXEL_FAST(data, i);
                    int otherPixel = IMAGE_GET_RGB565_PIXEL_FAST(((uint16_t *) other), i);
                    int dR = COLOR_RGB565_TO_R5(dataPixel);
                    int dG = COLOR_RGB565_TO_G6(dataPixel);
                    int dB = COLOR_RGB565_TO_B5(dataPixel);
                    int oR = COLOR_RGB565_TO_R5(otherPixel);
                    int oG = COLOR_RGB565_TO_G6(otherPixel);
                    int oB = COLOR_RGB565_TO_B5(otherPixel);
                    int r = reverse ? (oR - dR) : (dR - oR);
                    int g = reverse ? (oG - dG) : (dG - oG);
                    int b = reverse ? (oB - dB) : (dB - oB);
                    r = IM_MAX(r, COLOR_R5_MIN);
                    g = IM_MAX(g, COLOR_G6_MIN);
                    b = IM_MAX(b, COLOR_B5_MIN);
                    IMAGE_PUT_RGB565_PIXEL_FAST(data, i, COLOR_R5_G6_B5_TO_RGB565(r, g, b));
                }
            }
            break;
        }
        default: {
            break;
        }
    }
}
Beispiel #4
0
void rectangle_united(rectangle_t *dst, rectangle_t *src)
{
    int leftX = IM_MIN(dst->x, src->x);
    int topY = IM_MIN(dst->y, src->y);
    int rightX = IM_MAX(dst->x + dst->w, src->x + src->w);
    int bottomY = IM_MAX(dst->y + dst->h, src->y + src->h);
    dst->x = leftX;
    dst->y = topY;
    dst->w = rightX - leftX;
    dst->h = bottomY - topY;
}
Beispiel #5
0
static void imlib_max_line_op(image_t *img, int line, void *other, void *data, bool vflipped)
{
    image_t *mask = (image_t *) data;

    switch(img->bpp) {
        case IMAGE_BPP_BINARY: {
            uint32_t *data = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, line);
            for (int i = 0, j = img->w; i < j; i++) {
                if ((!mask) || image_get_mask_pixel(mask, i, line)) {
                    int dataPixel = IMAGE_GET_BINARY_PIXEL_FAST(data, i);
                    int otherPixel = IMAGE_GET_BINARY_PIXEL_FAST(((uint32_t *) other), i);
                    int p = IM_MAX(dataPixel, otherPixel);
                    IMAGE_PUT_BINARY_PIXEL_FAST(data, i, p);
                }
            }
            break;
        }
        case IMAGE_BPP_GRAYSCALE: {
            uint8_t *data = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, line);
            for (int i = 0, j = img->w; i < j; i++) {
                if ((!mask) || image_get_mask_pixel(mask, i, line)) {
                    int dataPixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(data, i);
                    int otherPixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(((uint8_t *) other), i);
                    int p = IM_MAX(dataPixel, otherPixel);
                    IMAGE_PUT_GRAYSCALE_PIXEL_FAST(data, i, p);
                }
            }
            break;
        }
        case IMAGE_BPP_RGB565: {
            uint16_t *data = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, line);
            for (int i = 0, j = img->w; i < j; i++) {
                if ((!mask) || image_get_mask_pixel(mask, i, line)) {
                    int dataPixel = IMAGE_GET_RGB565_PIXEL_FAST(data, i);
                    int otherPixel = IMAGE_GET_RGB565_PIXEL_FAST(((uint16_t *) other), i);
                    int r = IM_MAX(COLOR_RGB565_TO_R5(dataPixel), COLOR_RGB565_TO_R5(otherPixel));
                    int g = IM_MAX(COLOR_RGB565_TO_G6(dataPixel), COLOR_RGB565_TO_G6(otherPixel));
                    int b = IM_MAX(COLOR_RGB565_TO_B5(dataPixel), COLOR_RGB565_TO_B5(otherPixel));
                    IMAGE_PUT_RGB565_PIXEL_FAST(data, i, COLOR_R5_G6_B5_TO_RGB565(r, g, b));
                }
            }
            break;
        }
        default: {
            break;
        }
    }
}
Beispiel #6
0
int 
im_subtract( IMAGE *in1, IMAGE *in2, IMAGE *out )
{	
	/* Basic checks.
	 */
	if( im_piocheck( in1, out ) || im_pincheck( in2 ) )
		return( -1 );
	if( in1->Bands != in2->Bands &&
		(in1->Bands != 1 && in2->Bands != 1) ) {
		im_error( "im_subtract", _( "not same number of bands" ) );
		return( -1 );
	}
	if( in1->Coding != IM_CODING_NONE || in2->Coding != IM_CODING_NONE ) {
		im_error( "im_subtract", _( "not uncoded" ) );
		return( -1 );
	}
	if( im_cp_descv( out, in1, in2, NULL ) )
		return( -1 );

	/* What number of bands will we write?
	 */
	out->Bands = IM_MAX( in1->Bands, in2->Bands );

	/* What output type will we write? int, float or complex.
	 */
	if( im_iscomplex( in1 ) || im_iscomplex( in2 ) ) {
		/* What kind of complex?
		 */
		if( in1->BandFmt == IM_BANDFMT_DPCOMPLEX || 
			in2->BandFmt == IM_BANDFMT_DPCOMPLEX )
			/* Output will be DPCOMPLEX. 
			 */
			out->BandFmt = IM_BANDFMT_DPCOMPLEX;
		else
			out->BandFmt = IM_BANDFMT_COMPLEX;
	}
	else if( im_isfloat( in1 ) || im_isfloat( in2 ) ) {
		/* What kind of float?
		 */
		if( in1->BandFmt == IM_BANDFMT_DOUBLE || 
			in2->BandFmt == IM_BANDFMT_DOUBLE )
			out->BandFmt = IM_BANDFMT_DOUBLE;
		else
			out->BandFmt = IM_BANDFMT_FLOAT;
	}
	else 
		/* Must be int+int -> int.
		 */
		out->BandFmt = iformat[in1->BandFmt][in2->BandFmt];

	/* And process!
	 */
	if( im__cast_and_call( in1, in2, out, 
		(im_wrapmany_fn) subtract_buffer, NULL ) )
		return( -1 );

	/* Success!
	 */
	return( 0 );
}
Beispiel #7
0
static void *
workspaceview_layout_find_similar_x( Columnview *cview, 
	WorkspaceLayout *layout )
{
	int x = GTK_WIDGET( cview )->allocation.x;

	gboolean snap;

	snap = FALSE;

	/* Special case: a colum at zero makes a new column on the far left.
	 */
	if( layout->area.left == 0 && 
		x == 0 ) 
		snap = TRUE;

	if( layout->area.left > 0 &&
		ABS( x - layout->area.left ) < 
			workspaceview_layout_snap_threshold ) 
		snap = TRUE;
	
	if( snap ) { 
		layout->current_columns = g_slist_prepend(
			layout->current_columns, cview );
		layout->area.width = IM_MAX( layout->area.width, 
			GTK_WIDGET( cview )->allocation.width ); 
	}

	return( NULL );
}
/* As above, but do the vertical resample. lsk is how much we add to move down
 * a line in p, boff is [0,1,2,3] for which buffer line is mask[3].
 */
static void
make_yline( StretchInfo *sin, int lsk, int boff, 
	unsigned short *p, unsigned short *q, int w, int m )
{
	int bands = sin->in->Bands;
	int we = w * bands;
	int *mask = &sin->mask[m][0];
	int tot;
	int x;

	/* Offsets for subsequent pixels. Down a line each time.
	 */
	int o0 = lsk*boff;
	int o1 = lsk*((boff + 1) % 4);
	int o2 = lsk*((boff + 2) % 4);
	int o3 = lsk*((boff + 3) % 4);

	for( x = 0; x < we; x++ ) {
		tot = p[o0]*mask[0] + p[o1]*mask[1] + 
			p[o2]*mask[2] + p[o3]*mask[3];
		tot = IM_MAX( 0, tot );
		p++;
		*q++ = (tot + 16384) >> 15;
	}
}
Beispiel #9
0
/* Calculate the shrink factors. 
 *
 * We shrink in two stages: first, a shrink with a block average. This can
 * only accurately shrink by integer factors. We then do a second shrink with
 * a supplied interpolator to get the exact size we want.
 */
static int
calculate_shrink( int width, int height, double *residual )
{
	/* We shrink to make the largest dimension equal to size.
	 */
	int dimension = IM_MAX( width, height );

	double factor = dimension / (double) thumbnail_size;

	/* If the shrink factor is <=1.0, we need to zoom rather than shrink.
	 * Just set the factor to 1 in this case.
	 */
	double factor2 = factor < 1.0 ? 1.0 : factor;

	/* Int component of shrink.
	 */
	int shrink = floor( factor2 );

	/* Size after int shrink.
	 */
	int isize = floor( dimension / shrink );

	/* Therefore residual scale factor is.
	 */
	if( residual )
		*residual = thumbnail_size / (double) isize;

	return( shrink );
}
Beispiel #10
0
static int set_auto_gain(sensor_t *sensor, int enable, float gain_db, float gain_db_ceiling)
{
    uint8_t reg;
    int ret = cambus_readb(sensor->slv_addr, REG_COM8, &reg);
    ret |= cambus_writeb(sensor->slv_addr, REG_COM8, (reg & (~REG_COM8_AGC)) | ((enable != 0) ? REG_COM8_AGC : 0));

    if ((enable == 0) && (!isnanf(gain_db)) && (!isinf(gain_db))) {
        float gain = IM_MAX(IM_MIN(fast_expf((gain_db / 20.0) * fast_log(10.0)), 128.0), 1.0);

        int gain_temp = fast_roundf(fast_log2(IM_MAX(gain / 2.0, 1.0)));
        int gain_hi = 0x3F >> (6 - gain_temp);
        int gain_lo = IM_MIN(fast_roundf(((gain / (1 << gain_temp)) - 1.0) * 16.0), 15);

        ret |= cambus_writeb(sensor->slv_addr, REG_GAIN, ((gain_hi & 0x0F) << 4) | (gain_lo << 0));
        ret |= cambus_readb(sensor->slv_addr, REG_VREF, &reg);
        ret |= cambus_writeb(sensor->slv_addr, REG_VREF, ((gain_hi & 0x30) << 2) | (reg & 0x3F));
    } else if ((enable != 0) && (!isnanf(gain_db_ceiling)) && (!isinf(gain_db_ceiling))) {
Beispiel #11
0
static int set_auto_gain(sensor_t *sensor, int enable, float gain_db, float gain_db_ceiling)
{
   uint8_t reg;
   int ret = cambus_readb(sensor->slv_addr, BANK_SEL, &reg);
   ret |= cambus_writeb(sensor->slv_addr, BANK_SEL, reg | BANK_SEL_SENSOR);
   ret |= cambus_readb(sensor->slv_addr, COM8, &reg);
   ret |= cambus_writeb(sensor->slv_addr, COM8, (reg & (~COM8_AGC_EN)) | ((enable != 0) ? COM8_AGC_EN : 0));

   if ((enable == 0) && (!isnanf(gain_db)) && (!isinff(gain_db))) {
       float gain = IM_MAX(IM_MIN(fast_expf((gain_db / 20.0) * fast_log(10.0)), 32.0), 1.0);

       int gain_temp = fast_roundf(fast_log2(IM_MAX(gain / 2.0, 1.0)));
       int gain_hi = 0xF >> (4 - gain_temp);
       int gain_lo = IM_MIN(fast_roundf(((gain / (1 << gain_temp)) - 1.0) * 16.0), 15);

       ret |= cambus_writeb(sensor->slv_addr, GAIN, (gain_hi << 4) | (gain_lo << 0));
   } else if ((enable != 0) && (!isnanf(gain_db_ceiling)) && (!isinff(gain_db_ceiling))) {
Beispiel #12
0
void imlib_chrominvar(image_t *img)
{
    switch(img->bpp) {
        case IMAGE_BPP_BINARY: {
            break;
        }
        case IMAGE_BPP_GRAYSCALE: {
            break;
        }
        case IMAGE_BPP_RGB565: {
            for (int y = 0, yy = img->h; y < yy; y++) {
                uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y);
                for (int x = 0, xx = img->w; x < xx; x++) {
                    int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x);
                    float r_lin = xyz_table[COLOR_RGB565_TO_R8(pixel)];
                    float g_lin = xyz_table[COLOR_RGB565_TO_G8(pixel)];
                    float b_lin = xyz_table[COLOR_RGB565_TO_B8(pixel)];

                    float lin_sum = r_lin + g_lin + b_lin;

                    float r_lin_div = 0.0f;
                    float g_lin_div = 0.0f;
                    float b_lin_div = 0.0f;

                    if (lin_sum > 0.0f) {
                        lin_sum = 1.0f / lin_sum;
                        r_lin_div = r_lin * lin_sum;
                        g_lin_div = g_lin * lin_sum;
                        b_lin_div = b_lin * lin_sum;
                    }

                    int r_lin_div_int = IM_MAX(IM_MIN(r_lin_div * 255.0f, COLOR_R8_MAX), COLOR_R8_MIN);
                    int g_lin_div_int = IM_MAX(IM_MIN(g_lin_div * 255.0f, COLOR_G8_MAX), COLOR_G8_MIN);
                    int b_lin_div_int = IM_MAX(IM_MIN(b_lin_div * 255.0f, COLOR_B8_MAX), COLOR_B8_MIN);

                    IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr, x, COLOR_R8_G8_B8_TO_RGB565(r_lin_div_int, g_lin_div_int, b_lin_div_int));
                }
            }

            break;
        }
        default: {
            break;
        }
    }
}
Beispiel #13
0
/* Set output area of trn so that it just holds all of our input pels.
 */
void
im__transform_set_area( Transformation *trn )
{
	double xA, xB, xC, xD;
	double yA, yB, yC, yD;	
	int xmin, xmax, ymin, ymax;

	im__transform_forward( trn, 
		trn->iarea.left, trn->iarea.top, 
		&xA, &yA );
	im__transform_forward( trn, 
		IM_RECT_RIGHT( &trn->iarea ) - 1, trn->iarea.top, 
		&xB, &yB );
	im__transform_forward( trn, 
		trn->iarea.left, IM_RECT_BOTTOM( &trn->iarea ) - 1, 
		&xC, &yC );
	im__transform_forward( trn, 
		IM_RECT_RIGHT( &trn->iarea ) - 1, 
			IM_RECT_BOTTOM( &trn->iarea ) - 1, 
		&xD, &yD );

	xmin = IM_MIN( xA, IM_MIN( xB, IM_MIN( xC, xD ) ) );
	ymin = IM_MIN( yA, IM_MIN( yB, IM_MIN( yC, yD ) ) );
	xmax = IM_MAX( xA, IM_MAX( xB, IM_MAX( xC, xD ) ) );
	ymax = IM_MAX( yA, IM_MAX( yB, IM_MAX( yC, yD ) ) );

	trn->oarea.left = xmin;
	trn->oarea.top = ymin;
	trn->oarea.width = xmax - xmin + 1;
	trn->oarea.height = ymax - ymin + 1;
}
Beispiel #14
0
/* Transform a rect using a point transformer.
 */
static void
transform_rect( const Transformation *trn, transform_fn transform,
                const Rect *in,		/* In input space */
                Rect *out )		/* In output space */
{
    double x1, y1;		/* Map corners */
    double x2, y2;
    double x3, y3;
    double x4, y4;
    double left, right, top, bottom;

    /* Map input Rect.
     */
    transform( trn, in->left, in->top, &x1, &y1 );
    transform( trn, in->left, IM_RECT_BOTTOM( in ), &x3, &y3 );
    transform( trn, IM_RECT_RIGHT( in ), in->top, &x2, &y2 );
    transform( trn, IM_RECT_RIGHT( in ), IM_RECT_BOTTOM( in ), &x4, &y4 );

    /* Find bounding box for these four corners. Round-to-nearest to try
     * to stop rounding errors growing images.
     */
    left = IM_MIN( x1, IM_MIN( x2, IM_MIN( x3, x4 ) ) );
    right = IM_MAX( x1, IM_MAX( x2, IM_MAX( x3, x4 ) ) );
    top = IM_MIN( y1, IM_MIN( y2, IM_MIN( y3, y4 ) ) );
    bottom = IM_MAX( y1, IM_MAX( y2, IM_MAX( y3, y4 ) ) );

    out->left = IM_RINT( left );
    out->top = IM_RINT( top );
    out->width = IM_RINT( right - left );
    out->height = IM_RINT( bottom - top );
}
Beispiel #15
0
// https://en.wikipedia.org/wiki/Lab_color_space -> CIELAB-CIEXYZ conversions
// https://en.wikipedia.org/wiki/SRGB -> Specification of the transformation
uint16_t imlib_lab_to_rgb(uint8_t l, int8_t a, int8_t b)
{
    float x = ((l + 16) * 0.008621f) + (a * 0.002f);
    float y = ((l + 16) * 0.008621f);
    float z = ((l + 16) * 0.008621f) - (b * 0.005f);

    x = ((x > 0.206897f) ? (x*x*x) : ((0.128419f * x) - 0.017713f)) * 095.047f;
    y = ((y > 0.206897f) ? (y*y*y) : ((0.128419f * y) - 0.017713f)) * 100.000f;
    z = ((z > 0.206897f) ? (z*z*z) : ((0.128419f * z) - 0.017713f)) * 108.883f;

    float r_lin = ((x * +3.2406f) + (y * -1.5372f) + (z * -0.4986f)) / 100.0f;
    float g_lin = ((x * -0.9689f) + (y * +1.8758f) + (z * +0.0415f)) / 100.0f;
    float b_lin = ((x * +0.0557f) + (y * -0.2040f) + (z * +1.0570f)) / 100.0f;

    r_lin = (r_lin>0.0031308f) ? ((1.055f*powf(r_lin, 0.416666f))-0.055f) : (r_lin*12.92f);
    g_lin = (g_lin>0.0031308f) ? ((1.055f*powf(g_lin, 0.416666f))-0.055f) : (g_lin*12.92f);
    b_lin = (b_lin>0.0031308f) ? ((1.055f*powf(b_lin, 0.416666f))-0.055f) : (b_lin*12.92f);

    uint32_t red   = IM_MAX(IM_MIN(fast_floorf(r_lin * COLOR_R8_MAX), COLOR_R8_MAX), COLOR_R8_MIN);
    uint32_t green = IM_MAX(IM_MIN(fast_floorf(g_lin * COLOR_G8_MAX), COLOR_G8_MAX), COLOR_G8_MIN);
    uint32_t blue  = IM_MAX(IM_MIN(fast_floorf(b_lin * COLOR_B8_MAX), COLOR_B8_MAX), COLOR_B8_MIN);

    return COLOR_R8_G8_B8_TO_RGB565(red, green, blue);
}
Beispiel #16
0
/* Join a sub-hist onto the main hist, then free it.
 */
static int
hist_stop( void *seq, void *a, void *b )
{
	Histogram *shist = (Histogram *) seq;
	Histogram *mhist = (Histogram *) a;
	int i;

	g_assert( shist->bands == mhist->bands && shist->size == mhist->size );

	/* Add on sub-data.
	 */
	mhist->mx = IM_MAX( mhist->mx, shist->mx );
	for( i = 0; i < mhist->bands * mhist->size; i++ )
		mhist->bins[i] += shist->bins[i];

	hist_free( shist );
	
	return( 0 );
}
/* Stretch a line of pels into a line in the buffer.
 */
static void
make_xline( StretchInfo *sin, 
	unsigned short *p, unsigned short *q, int w, int m )
{
	int bands = sin->in->Bands;
	int tot;
	int x, b;

	/* Offsets for subsequent pixels.
	 */
	int o1 = 1*bands;
	int o2 = 2*bands;
	int o3 = 3*bands;

	for( x = 0; x < w; x++ ) {
		int *mask = &sin->mask[m][0];
		unsigned short *p1 = p;

		/* Loop for this pel.
		 */
		for( b = 0; b < bands; b++ ) {
			tot = p1[0]*mask[0] + p1[o1]*mask[1] + 
				p1[o2]*mask[2] + p1[o3]*mask[3];
			tot = IM_MAX( 0, tot );
			p1++;
			*q++ = (tot + 16384) >> 15;
		}

		/* Move to next mask.
		 */
		m++;
		if( m == 34 )
			/* Back to mask 0, reuse this input pel.
			 */
			m = 0;
		else
			/* Move to next input pel.
			 */
			p += bands;
	}
}
Beispiel #18
0
static void imlib_remove_shadows_sub_line_op(image_t *img, int line, void *data, bool vflipped)
{
    imlib_remove_shadows_line_op_state_t *state = (imlib_remove_shadows_line_op_state_t *) data;

    if (state->lines_processed >= imlib_remove_shadows_kernel_rank) {
        int y = vflipped ? (line + imlib_remove_shadows_kernel_rank) : (line - imlib_remove_shadows_kernel_rank);
        int index = y % imlib_remove_shadows_kernel_size;

        for (int x = 0, xx = img->w; x < xx; x++) {
            int img_pixel = IMAGE_GET_RGB565_PIXEL_FAST(state->img_lines[index], x);
            int img_r = COLOR_RGB565_TO_R8(img_pixel);
            int img_g = COLOR_RGB565_TO_G8(img_pixel);
            int img_b = COLOR_RGB565_TO_B8(img_pixel);
            float img_v = IM_MAX(IM_MAX(img_r, img_g), img_b);
            int other_pixel = IMAGE_GET_RGB565_PIXEL_FAST(state->other_lines[index], x);
            int other_r = COLOR_RGB565_TO_R8(other_pixel);
            int other_g = COLOR_RGB565_TO_G8(other_pixel);
            int other_b = COLOR_RGB565_TO_B8(other_pixel);
            float other_v = IM_MAX(IM_MAX(other_r, other_g), other_b);
            float ratio = img_v / other_v;

            if ((0.3f < ratio) && (ratio < 1.0f)) {
                int minY = IM_MAX(y - imlib_remove_shadows_kernel_rank, 0);
                int maxY = IM_MIN(y + imlib_remove_shadows_kernel_rank, img->h - 1);
                int minX = IM_MAX(x - imlib_remove_shadows_kernel_rank, 0);
                int maxX = IM_MIN(x + imlib_remove_shadows_kernel_rank, img->w - 1);
                int windowArea = (maxX - minX + 1) * (maxY - minY + 1);
                int hDiffSum = 0;
                int sDiffSum = 0;

                for (int k_y = minY; k_y <= maxY; k_y++) {
                    int k_index = k_y % imlib_remove_shadows_kernel_size;

                    for (int k_x = minX; k_x <= maxX; k_x++) {
                        int k_img_pixel = IMAGE_GET_RGB565_PIXEL_FAST(state->img_lines[k_index], k_x);
                        int k_img_r = COLOR_RGB565_TO_R8(k_img_pixel);
                        int k_img_g = COLOR_RGB565_TO_G8(k_img_pixel);
                        int k_img_b = COLOR_RGB565_TO_B8(k_img_pixel);
                        int k_img_cmax = IM_MAX(IM_MAX(k_img_r, k_img_g), k_img_b);
                        int k_img_cmin = IM_MAX(IM_MAX(k_img_r, k_img_g), k_img_b);
                        float k_img_cdel = k_img_cmax - k_img_cmin;
                        float k_img_h = 0;
                        float k_img_s = k_img_cmax ? (k_img_cdel / k_img_cmax) : 0;
                        int k_other_pixel = IMAGE_GET_RGB565_PIXEL_FAST(state->other_lines[k_index], k_x);
                        int k_other_r = COLOR_RGB565_TO_R8(k_other_pixel);
                        int k_other_g = COLOR_RGB565_TO_G8(k_other_pixel);
                        int k_other_b = COLOR_RGB565_TO_B8(k_other_pixel);
                        int k_other_cmax = IM_MAX(IM_MAX(k_other_r, k_other_g), k_other_b);
                        int k_other_cmin = IM_MAX(IM_MAX(k_other_r, k_other_g), k_other_b);
                        float k_other_cdel = k_other_cmax - k_other_cmin;
                        float k_other_h = 0;
                        float k_other_s = k_other_cmax ? (k_other_cdel / k_other_cmax) : 0;

                        if (k_img_cdel) {
                            if (k_img_cmax == k_img_r) {
                                k_img_h = ((k_img_g - k_img_b) / k_img_cdel) + 0;
                            } else if (k_img_cmax == k_img_g) {
                                k_img_h = ((k_img_b - k_img_r) / k_img_cdel) + 2;
                            } else if (k_img_cmax == k_img_b) {
                                k_img_h = ((k_img_r - k_img_g) / k_img_cdel) + 4;
                            }
                            k_img_h *= 60;
                            if (k_img_h < 0) k_img_h += 360.0;
                        }

                        if (k_other_cdel) {
                            if (k_other_cmax == k_other_r) {
                                k_other_h = ((k_other_g - k_other_b) / k_other_cdel) + 0;
                            } else if (k_other_cmax == k_other_g) {
                                k_other_h = ((k_other_b - k_other_r) / k_other_cdel) + 2;
                            } else if (k_other_cmax == k_other_b) {
                                k_other_h = ((k_other_r - k_other_g) / k_other_cdel) + 4;
                            }
                            k_other_h *= 60;
                            if (k_other_h < 0) k_other_h += 360.0;
                        }

                        int hDiff = abs(k_img_h - k_other_h);
                        hDiffSum += (hDiff >= 90) ? (180 - hDiff) : hDiff;
                        sDiffSum += k_img_s - k_other_s;
                    }
                }

                bool hIsShadow = (hDiffSum / windowArea) < 48;
                bool sIsShadow = (sDiffSum / windowArea) < 40;
                IMAGE_PUT_RGB565_PIXEL_FAST(state->out_lines[index], x, (hIsShadow && sIsShadow) ? other_pixel : img_pixel);
            } else {
                IMAGE_PUT_RGB565_PIXEL_FAST(state->out_lines[index], x, img_pixel);
            }
        }
    }

    imlib_remove_shadows_sub_sub_line_op(img, line, data, vflipped);
}
Beispiel #19
0
void imlib_gamma_corr(image_t *img, float gamma, float contrast, float brightness)
{
    gamma = IM_DIV(1.0, gamma);
    switch(img->bpp) {
        case IMAGE_BPP_BINARY: {
            float pScale = COLOR_BINARY_MAX - COLOR_BINARY_MIN;
            float pDiv = 1 / pScale;
            int *p_lut = fb_alloc((COLOR_BINARY_MAX - COLOR_BINARY_MIN + 1) * sizeof(int));

            for (int i = COLOR_BINARY_MIN; i <= COLOR_BINARY_MAX; i++) {
                int p = ((fast_powf(i * pDiv, gamma) * contrast) + brightness) * pScale;
                p_lut[i] = IM_MIN(IM_MAX(p , COLOR_BINARY_MIN), COLOR_BINARY_MAX);
            }

            for (int y = 0, yy = img->h; y < yy; y++) {
                uint32_t *data = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y);
                for (int x = 0, xx = img->w; x < xx; x++) {
                    int dataPixel = IMAGE_GET_BINARY_PIXEL_FAST(data, x);
                    int p = p_lut[dataPixel];
                    IMAGE_PUT_BINARY_PIXEL_FAST(data, x, p);
                }
            }

            fb_free();
            break;
        }
        case IMAGE_BPP_GRAYSCALE: {
            float pScale = COLOR_GRAYSCALE_MAX - COLOR_GRAYSCALE_MIN;
            float pDiv = 1 / pScale;
            int *p_lut = fb_alloc((COLOR_GRAYSCALE_MAX - COLOR_GRAYSCALE_MIN + 1) * sizeof(int));

            for (int i = COLOR_GRAYSCALE_MIN; i <= COLOR_GRAYSCALE_MAX; i++) {
                int p = ((fast_powf(i * pDiv, gamma) * contrast) + brightness) * pScale;
                p_lut[i] = IM_MIN(IM_MAX(p , COLOR_GRAYSCALE_MIN), COLOR_GRAYSCALE_MAX);
            }

            for (int y = 0, yy = img->h; y < yy; y++) {
                uint8_t *data = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y);
                for (int x = 0, xx = img->w; x < xx; x++) {
                    int dataPixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(data, x);
                    int p = p_lut[dataPixel];
                    IMAGE_PUT_GRAYSCALE_PIXEL_FAST(data, x, p);
                }
            }

            fb_free();
            break;
        }
        case IMAGE_BPP_RGB565: {
            float rScale = COLOR_R5_MAX - COLOR_R5_MIN;
            float gScale = COLOR_G6_MAX - COLOR_G6_MIN;
            float bScale = COLOR_B5_MAX - COLOR_B5_MIN;
            float rDiv = 1 / rScale;
            float gDiv = 1 / gScale;
            float bDiv = 1 / bScale;
            int *r_lut = fb_alloc((COLOR_R5_MAX - COLOR_R5_MIN + 1) * sizeof(int));
            int *g_lut = fb_alloc((COLOR_G6_MAX - COLOR_G6_MIN + 1) * sizeof(int));
            int *b_lut = fb_alloc((COLOR_B5_MAX - COLOR_B5_MIN + 1) * sizeof(int));

            for (int i = COLOR_R5_MIN; i <= COLOR_R5_MAX; i++) {
                int r = ((fast_powf(i * rDiv, gamma) * contrast) + brightness) * rScale;
                r_lut[i] = IM_MIN(IM_MAX(r , COLOR_R5_MIN), COLOR_R5_MAX);
            }

            for (int i = COLOR_G6_MIN; i <= COLOR_G6_MAX; i++) {
                int g = ((fast_powf(i * gDiv, gamma) * contrast) + brightness) * gScale;
                g_lut[i] = IM_MIN(IM_MAX(g , COLOR_G6_MIN), COLOR_G6_MAX);
            }

            for (int i = COLOR_B5_MIN; i <= COLOR_B5_MAX; i++) {
                int b = ((fast_powf(i * bDiv, gamma) * contrast) + brightness) * bScale;
                b_lut[i] = IM_MIN(IM_MAX(b , COLOR_B5_MIN), COLOR_B5_MAX);
            }

            for (int y = 0, yy = img->h; y < yy; y++) {
                uint16_t *data = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y);
                for (int x = 0, xx = img->w; x < xx; x++) {
                    int dataPixel = IMAGE_GET_RGB565_PIXEL_FAST(data, x);
                    int r = r_lut[COLOR_RGB565_TO_R5(dataPixel)];
                    int g = g_lut[COLOR_RGB565_TO_G6(dataPixel)];
                    int b = b_lut[COLOR_RGB565_TO_B5(dataPixel)];
                    IMAGE_PUT_RGB565_PIXEL_FAST(data, x, COLOR_R5_G6_B5_TO_RGB565(r, g, b));
                }
            }

            fb_free();
            fb_free();
            fb_free();
            break;
        }
        default: {
            break;
        }
    }
}
Beispiel #20
0
static void imlib_erode_dilate(image_t *img, int ksize, int threshold, int e_or_d, image_t *mask)
{
    int brows = ksize + 1;
    image_t buf;
    buf.w = img->w;
    buf.h = brows;
    buf.bpp = img->bpp;

    switch(img->bpp) {
        case IMAGE_BPP_BINARY: {
            buf.data = fb_alloc(IMAGE_BINARY_LINE_LEN_BYTES(img) * brows);

            for (int y = 0, yy = img->h; y < yy; y++) {
                uint32_t *row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y);
                uint32_t *buf_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, (y % brows));

                for (int x = 0, xx = img->w; x < xx; x++) {
                    int pixel = IMAGE_GET_BINARY_PIXEL_FAST(row_ptr, x);
                    IMAGE_PUT_BINARY_PIXEL_FAST(buf_row_ptr, x, pixel);

                    if ((mask && (!image_get_mask_pixel(mask, x, y)))
                    || (pixel == e_or_d)) {
                        continue; // Short circuit.
                    }

                    int acc = e_or_d ? 0 : -1; // Don't count center pixel...

                    for (int j = -ksize; j <= ksize; j++) {
                        uint32_t *k_row_ptr = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img,
                            IM_MIN(IM_MAX(y + j, 0), (img->h - 1)));

                        for (int k = -ksize; k <= ksize; k++) {
                            acc += IMAGE_GET_BINARY_PIXEL_FAST(k_row_ptr,
                                IM_MIN(IM_MAX(x + k, 0), (img->w - 1)));
                        }
                    }

                    if (!e_or_d) {
                        // Preserve original pixel value... or clear it.
                        if (acc < threshold) IMAGE_CLEAR_BINARY_PIXEL_FAST(buf_row_ptr, x);
                    } else {
                        // Preserve original pixel value... or set it.
                        if (acc > threshold) IMAGE_SET_BINARY_PIXEL_FAST(buf_row_ptr, x);
                    }
                }

                if (y >= ksize) { // Transfer buffer lines...
                    memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, (y - ksize)),
                           IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)),
                           IMAGE_BINARY_LINE_LEN_BYTES(img));
                }
            }

            // Copy any remaining lines from the buffer image...
            for (int y = img->h - ksize, yy = img->h; y < yy; y++) {
                memcpy(IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y),
                       IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(&buf, (y % brows)),
                       IMAGE_BINARY_LINE_LEN_BYTES(img));
            }

            fb_free();
            break;
        }
        case IMAGE_BPP_GRAYSCALE: {
            buf.data = fb_alloc(IMAGE_GRAYSCALE_LINE_LEN_BYTES(img) * brows);

            for (int y = 0, yy = img->h; y < yy; y++) {
                uint8_t *row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y);
                uint8_t *buf_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&buf, (y % brows));

                for (int x = 0, xx = img->w; x < xx; x++) {
                    int pixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(row_ptr, x);
                    IMAGE_PUT_GRAYSCALE_PIXEL_FAST(buf_row_ptr, x, pixel);

                    if ((mask && (!image_get_mask_pixel(mask, x, y)))
                    || (COLOR_GRAYSCALE_TO_BINARY(pixel) == e_or_d)) {
                        continue; // Short circuit.
                    }

                    int acc = e_or_d ? 0 : -1; // Don't count center pixel...

                    for (int j = -ksize; j <= ksize; j++) {
                        uint8_t *k_row_ptr = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img,
                            IM_MIN(IM_MAX(y + j, 0), (img->h - 1)));

                        for (int k = -ksize; k <= ksize; k++) {
                            acc += COLOR_GRAYSCALE_TO_BINARY(IMAGE_GET_GRAYSCALE_PIXEL_FAST(k_row_ptr,
                                IM_MIN(IM_MAX(x + k, 0), (img->w - 1))));
                        }
                    }

                    if (!e_or_d) {
                        // Preserve original pixel value... or clear it.
                        if (acc < threshold) IMAGE_PUT_GRAYSCALE_PIXEL_FAST(buf_row_ptr, x,
                                                                            COLOR_GRAYSCALE_BINARY_MIN);
                    } else {
                        // Preserve original pixel value... or set it.
                        if (acc > threshold) IMAGE_PUT_GRAYSCALE_PIXEL_FAST(buf_row_ptr, x,
                                                                            COLOR_GRAYSCALE_BINARY_MAX);
                    }
                }

                if (y >= ksize) { // Transfer buffer lines...
                    memcpy(IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, (y - ksize)),
                           IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)),
                           IMAGE_GRAYSCALE_LINE_LEN_BYTES(img));
                }
            }

            // Copy any remaining lines from the buffer image...
            for (int y = img->h - ksize, yy = img->h; y < yy; y++) {
                memcpy(IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y),
                       IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(&buf, (y % brows)),
                       IMAGE_GRAYSCALE_LINE_LEN_BYTES(img));
            }

            fb_free();
            break;
        }
        case IMAGE_BPP_RGB565: {
            buf.data = fb_alloc(IMAGE_RGB565_LINE_LEN_BYTES(img) * brows);

            for (int y = 0, yy = img->h; y < yy; y++) {
                uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y);
                uint16_t *buf_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, (y % brows));

                for (int x = 0, xx = img->w; x < xx; x++) {
                    int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x);
                    IMAGE_PUT_RGB565_PIXEL_FAST(buf_row_ptr, x, pixel);

                    if ((mask && (!image_get_mask_pixel(mask, x, y)))
                    || (COLOR_RGB565_TO_BINARY(pixel) == e_or_d)) {
                        continue; // Short circuit.
                    }

                    int acc = e_or_d ? 0 : -1; // Don't count center pixel...

                    for (int j = -ksize; j <= ksize; j++) {
                        uint16_t *k_row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img,
                            IM_MIN(IM_MAX(y + j, 0), (img->h - 1)));

                        for (int k = -ksize; k <= ksize; k++) {
                            acc += COLOR_RGB565_TO_BINARY(IMAGE_GET_RGB565_PIXEL_FAST(k_row_ptr,
                                IM_MIN(IM_MAX(x + k, 0), (img->w - 1))));
                        }
                    }

                    if (!e_or_d) {
                        // Preserve original pixel value... or clear it.
                        if (acc < threshold) IMAGE_PUT_RGB565_PIXEL_FAST(buf_row_ptr, x,
                                                                         COLOR_RGB565_BINARY_MIN);
                    } else {
                        // Preserve original pixel value... or set it.
                        if (acc > threshold) IMAGE_PUT_RGB565_PIXEL_FAST(buf_row_ptr, x,
                                                                         COLOR_RGB565_BINARY_MAX);
                    }
                }

                if (y >= ksize) { // Transfer buffer lines...
                    memcpy(IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, (y - ksize)),
                           IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, ((y - ksize) % brows)),
                           IMAGE_RGB565_LINE_LEN_BYTES(img));
                }
            }

            // Copy any remaining lines from the buffer image...
            for (int y = img->h - ksize, yy = img->h; y < yy; y++) {
                memcpy(IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y),
                       IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&buf, (y % brows)),
                       IMAGE_RGB565_LINE_LEN_BYTES(img));
            }

            fb_free();
            break;
        }
        default: {
            break;
        }
    }
}
Beispiel #21
0
/* Process a buffer of data.
 */
void
imb_XYZ2disp( float *p, PEL *q, int n, struct im_col_display *d )
{
	struct im_col_tab_disp *table = im_col_display_get_table( d );
	float rstep = (d->d_YCR - d->d_Y0R) / 1500.0;
	float gstep = (d->d_YCG - d->d_Y0G) / 1500.0;
	float bstep = (d->d_YCB - d->d_Y0B) / 1500.0;

	int x;

	for( x = 0; x < n; x++ ) {
		float Yr, Yg, Yb;
		int i;
		int r, g, b;

		float X = p[0];
		float Y = p[1];
		float Z = p[2];

		p += 3;

		/* Multiply through the matrix to get luminosity values. 
		 */
		Yr =  table->mat_XYZ2lum[0][0] * X 
		    + table->mat_XYZ2lum[0][1] * Y 
		    + table->mat_XYZ2lum[0][2] * Z;
		Yg =  table->mat_XYZ2lum[1][0] * X 
		    + table->mat_XYZ2lum[1][1] * Y 
		    + table->mat_XYZ2lum[1][2] * Z;
		Yb =  table->mat_XYZ2lum[2][0] * X 
		    + table->mat_XYZ2lum[2][1] * Y 
		    + table->mat_XYZ2lum[2][2] * Z;

		/* Clip -ves.
		 */
		Yr = IM_MAX( Yr, d->d_Y0R );
		Yg = IM_MAX( Yg, d->d_Y0G );
		Yb = IM_MAX( Yb, d->d_Y0B );

		/* Turn luminosity to colour value.
		 */
		i = IM_MIN( 1500, (Yr - d->d_Y0R) / rstep );
		r = table->t_Yr2r[i];

		i = IM_MIN( 1500, (Yg - d->d_Y0G) / gstep );
		g = table->t_Yg2g[i];

		i = IM_MIN( 1500, (Yb - d->d_Y0B) / bstep );
		b = table->t_Yb2b[i];

		/* Clip output.
		 */
		r = IM_MIN( r, d->d_Vrwr );
		g = IM_MIN( g, d->d_Vrwg );
		b = IM_MIN( b, d->d_Vrwb );

		q[0] = r;
		q[1] = g;
		q[2] = b;

		q += 3;
	}
}
Beispiel #22
0
/* Break the mask into a set of lines.
 */
static int
boxes_break( Boxes *boxes )
{
	DOUBLEMASK *mask = boxes->mask;
	const int size = mask->xsize * mask->ysize;

	double max;
	double min;
	double depth;
	int layers_above;
	int layers_below;
	int z, n, x, y;

	/* Find mask range. We must always include the zero axis in the mask.
	 */
	max = 0;
	min = 0;
	for( n = 0; n < size; n++ ) {
		max = IM_MAX( max, mask->coeff[n] );
		min = IM_MIN( min, mask->coeff[n] );
	}

	VIPS_DEBUG_MSG( "boxes_new: min = %g, max = %g\n", min, max );

	/* The zero axis must fall on a layer boundary. Estimate the
	 * depth, find n-lines-above-zero, get exact depth, then calculate a
	 * fixed n-lines which includes any negative parts.
	 */
	depth = (max - min) / boxes->n_layers;
	layers_above = ceil( max / depth );
	depth = max / layers_above;
	layers_below = floor( min / depth );

	boxes->n_layers = layers_above - layers_below;

	VIPS_DEBUG_MSG( "boxes_new: depth = %g, n_layers = %d\n", 
		depth, boxes->n_layers );

	/* For each layer, generate a set of lines which are inside the
	 * perimeter. Work down from the top.
	 */
	for( z = 0; z < boxes->n_layers; z++ ) {
		/* How deep we are into the mask, as a double we can test
		 * against. Add half the layer depth so we can easily find >50%
		 * mask elements.
		 */
		double z_ph = max - (1 + z) * depth + depth / 2;

		/* Odd, but we must avoid rounding errors that make us miss 0
		 * in the line above.
		 */
		int z_positive = z < layers_above;

		for( y = 0; y < mask->ysize; y++ ) {
			int inside;

			/* Start outside the perimeter.
			 */
			inside = 0;

			for( x = 0; x < mask->xsize; x++ ) {
				double coeff = MASK( mask, x, y );

				/* The vertical line from mask[x, y] to 0 is 
				 * inside. Is our current square (x, y) part 
				 * of that line?
				 */
				if( (z_positive && coeff >= z_ph) ||
					(!z_positive && coeff <= z_ph) ) {
					if( !inside ) {
						boxes_start( boxes, x );
						inside = 1;
					}
				}
				else {
					if( inside ) {
						if( boxes_end( boxes, x, y,
							z_positive ? 1 : -1 ) )
							return( -1 );
						inside = 0;
					}
				}
			}

			if( inside && 
				boxes_end( boxes, mask->xsize, y, 
					z_positive ? 1 : -1 ) )
				return( -1 );
		}
	}

#ifdef DEBUG
	VIPS_DEBUG_MSG( "boxes_new: generated %d boxes\n", boxes->n_hline );
	boxes_hprint( boxes );
#endif /*DEBUG*/

	return( 0 );
}
Beispiel #23
0
void imlib_remove_shadows(image_t *img, const char *path, image_t *other, int scalar, bool single)
{
    if (!single) {
        imlib_remove_shadows_line_op_state_t state;

        for (int i = 0; i < imlib_remove_shadows_kernel_size; i++) {
            state.img_lines[i] = fb_alloc(img->w * sizeof(uint16_t));
            state.other_lines[i] = fb_alloc(img->w * sizeof(uint16_t));
            state.out_lines[i] = fb_alloc(img->w * sizeof(uint16_t));
        }

        state.lines_processed = 0;

        imlib_image_operation(img, path, other, scalar, imlib_remove_shadows_line_op, &state);

        for (int i = 0; i < imlib_remove_shadows_kernel_size; i++) {
            fb_free();
            fb_free();
            fb_free();
        }
    } else {

        // Create Shadow Mask

        image_t temp_image;
        temp_image.w = img->w;
        temp_image.h = img->h;
        temp_image.bpp = img->bpp;
        temp_image.data = fb_alloc(image_size(img));

        memcpy(temp_image.data, img->data, image_size(img));

        rectangle_t r;
        r.x = 0;
        r.y = 0;
        r.w = temp_image.w;
        r.h = temp_image.h;

        histogram_t h;
        h.LBinCount = COLOR_L_MAX - COLOR_L_MIN + 1;
        h.ABinCount = COLOR_A_MAX - COLOR_A_MIN + 1;
        h.BBinCount = COLOR_B_MAX - COLOR_B_MIN + 1;
        h.LBins = fb_alloc(h.LBinCount * sizeof(float));
        h.ABins = fb_alloc(h.ABinCount * sizeof(float));
        h.BBins = fb_alloc(h.BBinCount * sizeof(float));
        imlib_get_histogram(&h, &temp_image, &r, NULL, false);

        statistics_t s;
        imlib_get_statistics(&s, temp_image.bpp, &h);

        int sum = 0;
        int mean = s.LMean * 0.8f;

        for (int y = 0, yy = temp_image.h; y < yy; y++) {
            uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&temp_image, y);

            for (int x = 0, xx = temp_image.w; x < xx; x++) {
                sum += COLOR_RGB565_TO_L(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)) < mean;
            }
        }

        if (sum > ((temp_image.w * temp_image.h) / 20)) { // Don't do anything if the image is mostly flat.

            threshold_t t;
            imlib_get_threshold(&t, temp_image.bpp, &h);

            list_t thresholds;
            list_init(&thresholds, sizeof(color_thresholds_list_lnk_data_t));
            color_thresholds_list_lnk_data_t lnk_data;
            lnk_data.LMin = COLOR_L_MIN;
            lnk_data.AMin = COLOR_A_MIN;
            lnk_data.BMin = COLOR_B_MIN;
            lnk_data.LMax = t.LValue;
            lnk_data.AMax = COLOR_A_MAX;
            lnk_data.BMax = COLOR_B_MAX;
            list_push_back(&thresholds, &lnk_data);
            imlib_binary(&temp_image, &temp_image, &thresholds, false, false, NULL);
            list_free(&thresholds);

            imlib_erode(&temp_image, 3, 30, NULL);
            imlib_dilate(&temp_image, 1, 1, NULL);

            // Get Shadow Average

            image_t temp_image_2;
            temp_image_2.w = temp_image.w;
            temp_image_2.h = temp_image.h;
            temp_image_2.bpp = temp_image.bpp;
            temp_image_2.data = fb_alloc(image_size(&temp_image));

            memcpy(temp_image_2.data, temp_image.data, image_size(&temp_image));
            imlib_erode(&temp_image_2, 3, 48, NULL);

            int shadow_r_sum = 0;
            int shadow_g_sum = 0;
            int shadow_b_sum = 0;
            int shadow_count = 0;

            for (int y = 0, yy = temp_image_2.h; y < yy; y++) {
                uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&temp_image_2, y);
                uint16_t *row_ptr_2 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y);

                for (int x = 0, xx = temp_image_2.w; x < xx; x++) {
                    if (IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)) {
                        int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr_2, x);
                        int r = COLOR_RGB565_TO_R8(pixel);
                        int g = COLOR_RGB565_TO_G8(pixel);
                        int b = COLOR_RGB565_TO_R8(pixel);
                        shadow_r_sum += r;
                        shadow_g_sum += g;
                        shadow_b_sum += b;
                        shadow_count += 1;
                    }
                }
            }

            memcpy(temp_image_2.data, temp_image.data, image_size(&temp_image));
            imlib_invert(&temp_image_2);
            imlib_erode(&temp_image_2, 5, 120, NULL);
            imlib_invert(&temp_image_2);
            imlib_b_xor(&temp_image_2, NULL, &temp_image, 0, NULL);
            imlib_erode(&temp_image_2, 2, 24, NULL);

            int not_shadow_r_sum = 0;
            int not_shadow_g_sum = 0;
            int not_shadow_b_sum = 0;
            int not_shadow_count = 0;

            for (int y = 0, yy = temp_image_2.h; y < yy; y++) {
                uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&temp_image_2, y);
                uint16_t *row_ptr_2 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y);

                for (int x = 0, xx = temp_image_2.w; x < xx; x++) {
                    if (IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)) {
                        int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr_2, x);
                        int r = COLOR_RGB565_TO_R8(pixel);
                        int g = COLOR_RGB565_TO_G8(pixel);
                        int b = COLOR_RGB565_TO_R8(pixel);
                        not_shadow_r_sum += r;
                        not_shadow_g_sum += g;
                        not_shadow_b_sum += b;
                        not_shadow_count += 1;
                    }
                }
            }

            // Fill in the umbra... (inner part of the shadow)...

            memcpy(temp_image_2.data, temp_image.data, image_size(&temp_image));

            imlib_mean_filter(&temp_image, 2, false, 0, false, NULL);

            if (shadow_count && not_shadow_count) {

                float shadow_r_average = ((float) shadow_r_sum) / ((float) shadow_count);
                float shadow_g_average = ((float) shadow_g_sum) / ((float) shadow_count);
                float shadow_b_average = ((float) shadow_b_sum) / ((float) shadow_count);

                float not_shadow_r_average = ((float) not_shadow_r_sum) / ((float) not_shadow_count);
                float not_shadow_g_average = ((float) not_shadow_g_sum) / ((float) not_shadow_count);
                float not_shadow_b_average = ((float) not_shadow_b_sum) / ((float) not_shadow_count);

                float diff_r = not_shadow_r_average - shadow_r_average;
                float diff_g = not_shadow_g_average - shadow_g_average;
                float diff_b = not_shadow_b_average - shadow_b_average;

                for (int y = 0; y < img->h; y++) {
                    uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(&temp_image, y);
                    uint16_t *row_ptr_2 = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y);

                    for (int x = 0; x < img->w; x++) {
                        float alpha = ((float) (COLOR_RGB565_TO_Y(IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x)) - COLOR_Y_MIN)) / ((float) (COLOR_Y_MAX - COLOR_Y_MIN));
                        int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr_2, x);
                        int r = COLOR_RGB565_TO_R8(pixel);
                        int g = COLOR_RGB565_TO_G8(pixel);
                        int b = COLOR_RGB565_TO_B8(pixel);

                        int r_new = IM_MIN(IM_MAX(r + (diff_r * alpha), COLOR_R8_MIN), COLOR_R8_MAX);
                        int g_new = IM_MIN(IM_MAX(g + (diff_g * alpha), COLOR_G8_MIN), COLOR_G8_MAX);
                        int b_new = IM_MIN(IM_MAX(b + (diff_b * alpha), COLOR_B8_MIN), COLOR_B8_MAX);
                        IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr_2, x, COLOR_R8_G8_B8_TO_RGB565(r_new, g_new, b_new));
                    }
                }
            }

            // Fill in the penumbra... (outer part of the shadow)...

            memcpy(temp_image.data, temp_image_2.data, image_size(&temp_image_2));

            imlib_erode(&temp_image_2, 1, 8, NULL);
            imlib_b_xor(&temp_image, NULL, &temp_image_2, 0, NULL);
            imlib_dilate(&temp_image, 3, 0, NULL);
            imlib_median_filter(img, 2, 12, false, 0, false, &temp_image);

            fb_free(); // temp_image_2
        }

        fb_free(); // BBins
        fb_free(); // ABins
        fb_free(); // LBins

        fb_free(); // temp_image
    }
}
Beispiel #24
0
int
main( int argc, char *argv[] )
{
	int enlar = 0;
	int center = 0;
	int rev = 0;

	IMAGE *vips;
	FILE *out;
	int n1, n2;
	int x, y;
	int xsize, ysize;
	int c;
	PEL *p;

	if( im_init_world( argv[0] ) )
	        error_exit( "unable to start VIPS" );

	while( --argc > 0 && (*++argv)[0] == '-' )
		while( (c = *++argv[0]) )
			switch( c ) {
			case 'e':
				enlar = 1;
				break;

			case 'c':
				center = 1;
				break;

			case 'r':
				rev = 1;
				break;

			default:
				error_exit( "mitsub: illegal option %c", c );
			}

	if( argc != 2 )
		error_exit( "usage: mitsub [-ecr] vipsfile mitfile\n"
			"where:\n"
			"\tvipsfile may be 1, 3 or 4 bands for mono, IM_TYPE_RGB or "
			"IM_TYPE_CMYK printing\n" 
			"\tmitfile may be '-', meaning send to stdout\n"
			"\t-e means enlarge to fill page\n"
			"\t-c means centre within page\n"
			"\t-r means reverse black/white\n"
			"\tNOTE: data is sent raw, with 0 == no ink - all correction is up to "
			"you\n"
			"example:\n"
			"\t%% mitsub -ec fred.v - > /dev/bpp0" );

	if( !(vips = im_open( argv[0], "r" )) )
		error_exit( "mitsub: unable to open \"%s\" for input", 
			argv[0] );

	if( strcmp( argv[1], "-" ) == 0 )
		out = stdout;
	else if( !(out = fopen( argv[1], "w" )) )
		error_exit( "mitsub: unable to open \"%s\" for output", 
			argv[1] );

	if( vips->Coding != IM_CODING_NONE || vips->BandFmt != IM_BANDFMT_UCHAR )
		error_exit( "mitsub: uncoded uchar only" );
	if( vips->Bands != 1 && vips->Bands != 3 && vips->Bands != 4 )
		error_exit( "mitsub: 1,3 and 4 band images only" );

	/* Set xsize and ysize.
	 */
	if( vips->Xsize <= vips->Ysize ) {
		xsize = vips->Xsize;
		ysize = vips->Ysize;
	}
	else {
		im_diagnostics( "mitsub: rotating ..." );
		xsize = vips->Ysize;
		ysize = vips->Xsize;
	}

	/* Shrink if image is too big.
	 */
	if( xsize > HMAX || ysize > VMAX ) {
		double x_factor = HMAX/xsize;
		double y_factor = VMAX/ysize;
		double factor = IM_MAX( x_factor, y_factor );
		IMAGE *sh = im_open( "shrink", "t" );

		im_diagnostics( "mitsub: shrinking by %g ...", factor );
		if( !sh || im_shrink( vips, sh, factor, factor ) )
			error_exit( "mitsub: shrink failed" );

		vips = sh;
		enlar = 0;
	}

	/* On line command and buffer clear.
	 */
 	putc( 0x11, out );
	putc( 0x1b, out );
	putc( 'Z', out );

	/* Memory clear.
	 */
	putc( 0x1b, out );
	putc( 'Z', out );

	/* Media size. (Size A4)
	 */
	putc( 0x1b, out );
	putc( '#', out );
	putc( 'P', out );
	putc( '0', out );

	/* Enlargement.
	 */
	if( enlar ) {
		double rh, rv;
		int n, m;

		/* Enlarge method: ('0'=simple enlargement, 
		 * '1'=linear enlargement)
		 */
		putc( 0x1b, out );
		putc( '&', out );
		putc( 'O', out );
		putc( '1', out );	

		rh = HMAX/(double) xsize;
		rv = VMAX/(double) ysize;
		if( rh > 8 || rv > 8 ) {
			n = 8;
			m = 1;
		}
		else if( rh > rv ) {
			double fact = VMAX/255;

			n = 255;
			m = (int) ysize/fact + 1;
		}
		else {
			double fact = HMAX/255;

			n = 255;
			m = (int) xsize/fact + 1;
		}
		im_diagnostics( "mitsub: enlarging by %g ...", (double) n/m );

		/* Horizontal enlarge.
		 */	
		putc( 0x1b, out );
		putc( '&', out );
		putc( 'P', out );
		putc( n, out );
		putc( m, out );

		/* Vertical enlarge.
		 */
		putc( 0x1b, out );
		putc( '&', out );
		putc( 'Q', out );
		putc( n, out );
		putc( m, out );

	}
	else {
		/* No enlargement.
		 */
		putc( 0x1b, out );
		putc( '&', out );
		putc( 'O', out );
		putc( '1', out );	
		putc( 0x1b, out );
		putc( '&', out );
		putc( 'P', out );
		putc( 1, out );
		putc( 1, out );
		putc( 0x1b, out );
		putc( '&', out );
		putc( 'Q', out );
		putc( 1, out );
		putc( 1, out );
	}

	if( rev ) {
		/* Colour reversing.
		 */
		putc( 0x1b, out );
		putc( '&', out );
		putc( 'W', out );
		putc( '2', out  );
	}
	else {
		/* No reverse.
		 */
		putc( 0x1b, out );
		putc( '&', out );
		putc( 'W', out );
		putc( '0', out  );
	}

	/* Number of copies.
	 */
	putc( 0x1b, out );
	putc( '#', out );
	putc( 'C', out );
	putc( NBPRINT, out  );

	/* Left margin.
	 */
	putc( 0x1b, out );
	putc( '&', out );
	putc( 'S', out );
	putc( 0, out  );

	/* Top margin.
	 */
	putc( 0x1b, out );
	putc( '&', out );
	putc( 'T', out );
	putc( 0, out  );

	/* Centering. ('1' = centering available, '0'= no centering).
	 */
	if( center ) {
		im_diagnostics( "mitsub: centering ..." );
		putc( 0x1b, out );
		putc( '&', out );
		putc( 'C', out );
		putc( '1', out );	 
	}
	else {
		/* No centering.
		 */
		putc( 0x1b, out );
		putc( '&', out );
		putc( 'C', out );
		putc( '0', out );
	}

	/* Transfer format = pixel order method for colour, = frame order 
	 * method for monochrome.
	 */	
	switch( vips->Bands ) {
	case 3:
	case 4:
		putc( 0x1b, out );
		putc( '&', out );
		putc( 'A', out );
		putc( '2', out  );
		break;

	case 1:
		putc( 0x1b, out );
		putc( '&', out );
		putc( 'A', out );
		putc( '0', out  );	
		break;

	default:
		error_exit( "internal error" );
		/*NOTREACHED*/
	}

	/* Colour specification.
	 */
	switch( vips->Bands ) {
	case 4:
	case 1:
		/* IM_TYPE_CMYK. For mono, send just K.
		 */
		putc( 0x1b, out );
		putc( '&', out );
		putc( 'I', out );
		putc( '2', out );
		break;

	case 3:
		/* IM_TYPE_RGB.
		 */
		putc( 0x1b, out );
		putc( '&', out );
		putc( 'I', out );
		putc( '0', out );
		break;
	
	default:
		error_exit( "internal error" );
		/*NOTREACHED*/
	}

	/* Gray scale level.
	 */
	putc( 0x1b, out );
	putc( '#', out );
	putc( 'L', out );
	putc( 8, out );

	/* Rotation.
	 */
	if( vips->Xsize <= vips->Ysize ) {
		putc( 0x1b, out );
		putc( '#', out );
		putc( 'R', out );
		putc( '0', out );
	}
	else  {
		putc( 0x1b, out );
		putc( '#', out );
		putc( 'R', out );
		putc( '1', out );
	}
		
	/* Horizontal shift.
	 */ 
	putc( 0x1b, out );
	putc( '&', out );
	putc( 'J', out );
	putc( 0, out );
	putc( 0, out );

	/* Vertical shift.
	 */
	putc( 0x1b, out );
	putc( '&', out );
	putc( 'K', out );
	putc( 0, out );
	putc( 0, out );

	/* Number of horizontal pixels.
	 */
	n1 = vips->Xsize >> 8;
	n2 = vips->Xsize & 0xff;
	putc(  0x1b, out );
	putc( '&', out );
	putc( 'H', out );
	putc( n1, out );
	putc( n2, out );
	
	/* Number of vertical pixels.
	 */
	n1 = vips->Ysize >> 8;
	n2 = vips->Ysize & 0xff;
	putc( 0x1b, out );
	putc( '&', out );
	putc( 'V', out );
	putc( n1, out );
	putc( n2, out );

	/* Transfer colour (for monochrome image only).
	 */
	if( vips->Bands == 1 ) {
		putc( 0x1b, out );
		putc( 'C', out );
		putc( '4', out );
	}

	/* Image data transfer. Image must be sent as YMCK.
	 */
	putc( 0x1b, out );
	putc( 'O', out );
	if( im_incheck( vips ) )
		error_exit( "mitsub: unable to read image data" );
	p = (PEL *) vips->data;
	switch( vips->Bands ) {
	case 4:
		im_diagnostics( "mitsub: sending IM_TYPE_CMYK ..." );
		for( y = 0; y < vips->Ysize; y++ )
			for( x = 0; x < vips->Xsize; x++ ) {
 				putc( p[2], out );
				putc( p[1], out );
				putc( p[0], out );
				putc( p[3], out );
				p += 4;
			}
		break;

	case 3:
		im_diagnostics( "mitsub: sending IM_TYPE_RGB ..." );
		for( y = 0; y < vips->Ysize; y++ )
			for( x = 0; x < vips->Xsize; x++ ) {
 				putc( p[0], out );
				putc( p[1], out );
				putc( p[2], out );
				p += 3;
			}
		break;

	case 1:
		im_diagnostics( "mitsub: sending K ..." );
		for( y = 0; y < vips->Ysize; y++ )
			for( x = 0; x < vips->Xsize; x++ )
 				putc( *p++, out );
		break;
	}

	/* Form feed. Page end.
	 */
	putc( 0x0c, out  );

	/* Now try to reset printer to default settings. 
	 *
	 * No enlargement.
	 */
	putc( 0x1b, out );
	putc( '&', out );
	putc( 'O', out );
	putc( '1', out );	
	putc( 0x1b, out );
	putc( '&', out );
	putc( 'P', out );
	putc( 1, out );
	putc( 1, out );
	putc( 0x1b, out );
	putc( '&', out );
	putc( 'Q', out );
	putc( 1, out );
	putc( 1, out );

	/* No centering.
	 */
	putc( 0x1b, out );
	putc( '&', out );
	putc( 'C', out );
	putc( '0', out );

	/* No colour reverse.
	 */
	putc( 0x1b, out );
	putc( '&', out );
	putc( 'W', out );
	putc( '0', out  );

	return( 0 );
}
Beispiel #25
0
void imlib_illuminvar(image_t *img) // http://ai.stanford.edu/~alireza/publication/cic15.pdf
{
    switch(img->bpp) {
        case IMAGE_BPP_BINARY: {
            break;
        }
        case IMAGE_BPP_GRAYSCALE: {
            break;
        }
        case IMAGE_BPP_RGB565: {
            for (int y = 0, yy = img->h; y < yy; y++) {
                uint16_t *row_ptr = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y);
                for (int x = 0, xx = img->w; x < xx; x++) {
                    int pixel = IMAGE_GET_RGB565_PIXEL_FAST(row_ptr, x);
#ifdef IMLIB_ENABLE_INVARIANT_TABLE
                    int rgb565 = invariant_table[pixel];
#else
                    float r_lin = xyz_table[COLOR_RGB565_TO_R8(pixel)] + 1.0;
                    float g_lin = xyz_table[COLOR_RGB565_TO_G8(pixel)] + 1.0;
                    float b_lin = xyz_table[COLOR_RGB565_TO_B8(pixel)] + 1.0;

                    float r_lin_sharp = (r_lin *  0.9968f) + (g_lin *  0.0228f) + (b_lin * 0.0015f);
                    float g_lin_sharp = (r_lin * -0.0071f) + (g_lin *  0.9933f) + (b_lin * 0.0146f);
                    float b_lin_sharp = (r_lin *  0.0103f) + (g_lin * -0.0161f) + (b_lin * 0.9839f);

                    float lin_sharp_avg = r_lin_sharp * g_lin_sharp * b_lin_sharp;
                    lin_sharp_avg = (lin_sharp_avg > 0.0f) ? fast_cbrtf(lin_sharp_avg) : 0.0f;

                    float r_lin_sharp_div = 0.0f;
                    float g_lin_sharp_div = 0.0f;
                    float b_lin_sharp_div = 0.0f;

                    if (lin_sharp_avg > 0.0f) {
                        lin_sharp_avg = 1.0f / lin_sharp_avg;
                        r_lin_sharp_div = r_lin_sharp * lin_sharp_avg;
                        g_lin_sharp_div = g_lin_sharp * lin_sharp_avg;
                        b_lin_sharp_div = b_lin_sharp * lin_sharp_avg;
                    }

                    float r_lin_sharp_div_log = (r_lin_sharp_div > 0.0f) ? fast_log(r_lin_sharp_div) : 0.0f;
                    float g_lin_sharp_div_log = (g_lin_sharp_div > 0.0f) ? fast_log(g_lin_sharp_div) : 0.0f;
                    float b_lin_sharp_div_log = (b_lin_sharp_div > 0.0f) ? fast_log(b_lin_sharp_div) : 0.0f;

                    float chi_x = (r_lin_sharp_div_log * 0.7071f) + (g_lin_sharp_div_log * -0.7071f) + (b_lin_sharp_div_log *  0.0000f);
                    float chi_y = (r_lin_sharp_div_log * 0.4082f) + (g_lin_sharp_div_log *  0.4082f) + (b_lin_sharp_div_log * -0.8164f);

                    float e_t_x =  0.9326f;
                    float e_t_y = -0.3609f;

                    float p_th_00 = e_t_x * e_t_x;
                    float p_th_01 = e_t_x * e_t_y;
                    float p_th_10 = e_t_y * e_t_x;
                    float p_th_11 = e_t_y * e_t_y;

                    float x_th_x = (p_th_00 * chi_x) + (p_th_01 * chi_y);
                    float x_th_y = (p_th_10 * chi_x) + (p_th_11 * chi_y);

                    float r_chi = (x_th_x *  0.7071f) + (x_th_y *  0.4082f);
                    float g_chi = (x_th_x * -0.7071f) + (x_th_y *  0.4082f);
                    float b_chi = (x_th_x *  0.0000f) + (x_th_y * -0.8164f);

                    float r_chi_invariant = fast_expf(r_chi);
                    float g_chi_invariant = fast_expf(g_chi);
                    float b_chi_invariant = fast_expf(b_chi);

                    float chi_invariant_sum = r_chi_invariant + g_chi_invariant + b_chi_invariant;

                    float r_chi_invariant_m = 0.0f;
                    float g_chi_invariant_m = 0.0f;
                    float b_chi_invariant_m = 0.0f;

                    if (chi_invariant_sum > 0.0f) {
                        chi_invariant_sum = 1.0f / chi_invariant_sum;
                        r_chi_invariant_m = r_chi_invariant * chi_invariant_sum;
                        g_chi_invariant_m = g_chi_invariant * chi_invariant_sum;
                        b_chi_invariant_m = b_chi_invariant * chi_invariant_sum;
                    }

                    int r_chi_invariant_m_int = IM_MAX(IM_MIN(r_chi_invariant_m * 255.0f, COLOR_R8_MAX), COLOR_R8_MIN);
                    int g_chi_invariant_m_int = IM_MAX(IM_MIN(g_chi_invariant_m * 255.0f, COLOR_G8_MAX), COLOR_G8_MIN);
                    int b_chi_invariant_m_int = IM_MAX(IM_MIN(b_chi_invariant_m * 255.0f, COLOR_B8_MAX), COLOR_B8_MIN);

                    int rgb565 = COLOR_R8_G8_B8_TO_RGB565(r_chi_invariant_m_int, g_chi_invariant_m_int, b_chi_invariant_m_int);
#endif
                    IMAGE_PUT_RGB565_PIXEL_FAST(row_ptr, x, rgb565);
                }
            }

            break;
        }
        default: {
            break;
        }
    }
}