static int bochs_init(struct pci_slot_dev *pci_dev) { int ret; struct fb_info *info; size_t mmap_len; assert(pci_dev != NULL); info = fb_alloc(); if (info == NULL) { return -ENOMEM; } memcpy(&info->fix, &bochs_fix_screeninfo, sizeof info->fix); fill_var(&info->var); info->ops = &bochs_ops; info->screen_base = (void *)(pci_dev->bar[0] & ~0xf); /* FIXME */ mmap_len = binalign_bound(VBE_DISPI_MAX_XRES * VBE_DISPI_MAX_YRES * VBE_DISPI_MAX_BPP / 8, PAGE_SIZE()); if (MAP_FAILED == mmap_device_memory(info->screen_base, mmap_len, PROT_READ|PROT_WRITE|PROT_NOCACHE, MAP_FIXED, (unsigned long) info->screen_base)) { return -EIO; } ret = fb_register(info); if (ret != 0) { fb_release(info); return ret; } return 0; }
void imlib_replace(image_t *img, const char *path, image_t *other, int scalar, bool hmirror, bool vflip, bool transpose, image_t *mask) { bool in_place = img->data == other->data; image_t temp; if (in_place) { memcpy(&temp, other, sizeof(image_t)); temp.data = fb_alloc(image_size(&temp)); memcpy(temp.data, other->data, image_size(&temp)); other = &temp; } imlib_replace_line_op_state_t state; state.hmirror = hmirror; state.vflip = vflip; state.mask = mask; state.transpose = transpose; imlib_image_operation(img, path, other, scalar, imlib_replace_line_op, &state); if (in_place) { fb_free(); } if (transpose) { int w = img->w; int h = img->h; img->w = h; img->h = w; } }
void umm_init_x( size_t size ) { uint32_t UMM_MALLOC_CFG_HEAP_SIZE = (size / sizeof(size_t)) * sizeof(size_t); if (UMM_MALLOC_CFG_HEAP_SIZE < (sizeof(umm_block) * 128)) fb_alloc_fail(); if (UMM_MALLOC_CFG_HEAP_SIZE > (sizeof(umm_block) * 32768)) UMM_MALLOC_CFG_HEAP_SIZE = sizeof(umm_block) * 32768; void *UMM_MALLOC_CFG_HEAP_ADDR = fb_alloc(UMM_MALLOC_CFG_HEAP_SIZE); /* init heap pointer and size, and memset it to 0 */ umm_heap = (umm_block *)UMM_MALLOC_CFG_HEAP_ADDR; umm_numblocks = (UMM_MALLOC_CFG_HEAP_SIZE / sizeof(umm_block)); memset(umm_heap, 0x00, UMM_MALLOC_CFG_HEAP_SIZE); /* setup initial blank heap structure */ { /* index of the 0th `umm_block` */ const unsigned short int block_0th = 0; /* index of the 1st `umm_block` */ const unsigned short int block_1th = 1; /* index of the latest `umm_block` */ const unsigned short int block_last = UMM_NUMBLOCKS - 1; /* setup the 0th `umm_block`, which just points to the 1st */ UMM_NBLOCK(block_0th) = block_1th; UMM_NFREE(block_0th) = block_1th; UMM_PFREE(block_0th) = block_1th; /* * Now, we need to set the whole heap space as a huge free block. We should * not touch the 0th `umm_block`, since it's special: the 0th `umm_block` * is the head of the free block list. It's a part of the heap invariant. * * See the detailed explanation at the beginning of the file. */ /* * 1th `umm_block` has pointers: * * - next `umm_block`: the latest one * - prev `umm_block`: the 0th * * Plus, it's a free `umm_block`, so we need to apply `UMM_FREELIST_MASK` * * And it's the last free block, so the next free block is 0. */ UMM_NBLOCK(block_1th) = block_last | UMM_FREELIST_MASK; UMM_NFREE(block_1th) = 0; UMM_PBLOCK(block_1th) = block_0th; UMM_PFREE(block_1th) = block_0th; /* * latest `umm_block` has pointers: * * - next `umm_block`: 0 (meaning, there are no more `umm_blocks`) * - prev `umm_block`: the 1st * * It's not a free block, so we don't touch NFREE / PFREE at all. */ UMM_NBLOCK(block_last) = 0; UMM_PBLOCK(block_last) = block_1th; } }
static int cirrus_init(struct pci_slot_dev *pci_dev) { int ret; struct fb_info *info; assert(pci_dev != NULL); info = fb_alloc(); if (info == NULL) { return -ENOMEM; } memcpy(&info->fix, &cl_fix_screeninfo, sizeof(info->fix)); memcpy(&info->var, &cl_default_var_screeninfo, sizeof(info->var)); info->ops = &cl_ops; info->screen_base = (void *)(pci_dev->bar[0] & PCI_BASE_ADDR_IO_MASK); ret = fb_register(info); if (ret != 0) { fb_release(info); return ret; } return 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; } } }
static mp_obj_t py_lcd_display(uint n_args, const mp_obj_t *args, mp_map_t *kw_args) { image_t *arg_img = py_image_cobj(args[0]); PY_ASSERT_TRUE_MSG(IM_IS_MUTABLE(arg_img), "Image format is not supported."); rectangle_t rect; py_helper_keyword_rectangle_roi(arg_img, n_args, args, 1, kw_args, &rect); // Fit X. int l_pad = 0, r_pad = 0; if (rect.w > width) { int adjust = rect.w - width; rect.w -= adjust; rect.x += adjust / 2; } else if (rect.w < width) { int adjust = width - rect.w; l_pad = adjust / 2; r_pad = (adjust + 1) / 2; } // Fit Y. int t_pad = 0, b_pad = 0; if (rect.h > height) { int adjust = rect.h - height; rect.h -= adjust; rect.y += adjust / 2; } else if (rect.h < height) { int adjust = height - rect.h; t_pad = adjust / 2; b_pad = (adjust + 1) / 2; } switch (type) { case LCD_NONE: return mp_const_none; case LCD_SHIELD: lcd_write_command_byte(0x2C); uint8_t *zero = fb_alloc0(width*2); uint16_t *line = fb_alloc(width*2); for (int i=0; i<t_pad; i++) { lcd_write_data(width*2, zero); } for (int i=0; i<rect.h; i++) { if (l_pad) { lcd_write_data(l_pad*2, zero); // l_pad < width } if (IM_IS_GS(arg_img)) { for (int j=0; j<rect.w; j++) { uint8_t pixel = IM_GET_GS_PIXEL(arg_img, (rect.x + j), (rect.y + i)); line[j] = IM_RGB565(IM_R825(pixel),IM_G826(pixel),IM_B825(pixel)); } lcd_write_data(rect.w*2, (uint8_t *) line); } else { lcd_write_data(rect.w*2, (uint8_t *) (((uint16_t *) arg_img->pixels) + ((rect.y + i) * arg_img->w) + rect.x)); } if (r_pad) { lcd_write_data(r_pad*2, zero); // r_pad < width } } for (int i=0; i<b_pad; i++) { lcd_write_data(width*2, zero); } fb_free(); fb_free(); return mp_const_none; } return mp_const_none; }
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 } }
// returns null pointer without error if size==0 void *fb_alloc0(uint32_t size) { void *mem = fb_alloc(size); memset(mem, 0, size); return mem; }
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; } } }
// returns null pointer without error if passed size==0 void *fb_alloc0(uint32_t size) { void *mem = fb_alloc(size); memset(mem, 0, size); // does nothing if size is zero. return mem; }