/* 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 ); }
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 ); }
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; } } }
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; }
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; } } }
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 ); }
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; } }
/* 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 ); }
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, ®); 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, ®); 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))) {
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, ®); ret |= cambus_writeb(sensor->slv_addr, BANK_SEL, reg | BANK_SEL_SENSOR); ret |= cambus_readb(sensor->slv_addr, COM8, ®); 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))) {
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; } } }
/* 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; }
/* 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 ); }
// 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); }
/* 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; } }
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); }
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; } } }
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; } } }
/* 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; } }
/* 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 ); }
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 } }
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 ); }
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; } } }