void InvertColorFilter::applyToGrayscale(FilterManager* filterMgr) { const uint16_t* src_address = (uint16_t*)filterMgr->getSourceAddress(); uint16_t* dst_address = (uint16_t*)filterMgr->getDestinationAddress(); int w = filterMgr->getWidth(); Target target = filterMgr->getTarget(); int x, c, k, a; for (x=0; x<w; x++) { if (filterMgr->skipPixel()) { ++src_address; ++dst_address; continue; } c = *(src_address++); k = _graya_getv(c); a = _graya_geta(c); if (target & TARGET_GRAY_CHANNEL) k ^= 0xff; if (target & TARGET_ALPHA_CHANNEL) a ^= 0xff; *(dst_address++) = _graya(k, a); } }
void read_scanline(GrayscaleTraits::address_t address, int w, uint8_t* buffer) { for (int x=0; x<w; ++x) { k = *(buffer++); a = *(buffer++); *(address++) = _graya(k, a); } }
void ConvolutionMatrixFilter::applyToGrayscale(FilterManager* filterMgr) { if (!m_matrix) return; const Image* src = filterMgr->getSourceImage(); uint16_t* dst_address = (uint16_t*)filterMgr->getDestinationAddress(); Target target = filterMgr->getTarget(); uint16_t color; GetPixelsDelegateGrayscale delegate; int x = filterMgr->getX(); int x2 = x+filterMgr->getWidth(); int y = filterMgr->getY(); for (; x<x2; ++x) { // Avoid the non-selected region if (filterMgr->skipPixel()) { ++dst_address; continue; } delegate.reset(m_matrix); get_neighboring_pixels<GrayscaleTraits>(src, x, y, m_matrix->getWidth(), m_matrix->getHeight(), m_matrix->getCenterX(), m_matrix->getCenterY(), m_tiledMode, delegate); color = image_getpixel_fast<GrayscaleTraits>(src, x, y); if (delegate.div == 0) { *(dst_address++) = color; continue; } if (target & TARGET_GRAY_CHANNEL) { delegate.v = delegate.v / delegate.div + m_matrix->getBias(); delegate.v = MID(0, delegate.v, 255); } else delegate.v = _graya_getv(color); if (target & TARGET_ALPHA_CHANNEL) { delegate.a = delegate.a / m_matrix->getDiv() + m_matrix->getBias(); delegate.a = MID(0, delegate.a, 255); } else delegate.a = _graya_geta(color); *(dst_address++) = _graya(delegate.v, delegate.a); } }
void MedianFilter::applyToGrayscale(FilterManager* filterMgr) { const Image* src = filterMgr->getSourceImage(); uint16_t* dst_address = (uint16_t*)filterMgr->getDestinationAddress(); Target target = filterMgr->getTarget(); int color, k, a; GetPixelsDelegateGrayscale delegate(m_channel); int x = filterMgr->getX(); int x2 = x+filterMgr->getWidth(); int y = filterMgr->getY(); for (; x<x2; ++x) { // Avoid the non-selected region if (filterMgr->skipPixel()) { ++dst_address; continue; } delegate.reset(); get_neighboring_pixels<GrayscaleTraits>(src, x, y, m_width, m_height, m_width/2, m_height/2, m_tiledMode, delegate); color = image_getpixel_fast<GrayscaleTraits>(src, x, y); if (target & TARGET_GRAY_CHANNEL) { std::sort(m_channel[0].begin(), m_channel[0].end()); k = m_channel[0][m_ncolors/2]; } else k = _graya_getv(color); if (target & TARGET_ALPHA_CHANNEL) { std::sort(m_channel[1].begin(), m_channel[1].end()); a = m_channel[1][m_ncolors/2]; } else a = _graya_geta(color); *(dst_address++) = _graya(k, a); } }
/** * Resizes the source image @a src to the destination image @a dst. * * @warning If you are using the RESIZE_METHOD_BILINEAR, it is * recommended to use @ref image_fixup_transparent_colors function * over the source image @a src before using this routine. */ void image_resize(const Image* src, Image* dst, ResizeMethod method, const Palette* pal, const RgbMap* rgbmap) { switch (method) { // TODO optimize this case RESIZE_METHOD_NEAREST_NEIGHBOR: { uint32_t color; double u, v, du, dv; int x, y; u = v = 0.0; du = src->w * 1.0 / dst->w; dv = src->h * 1.0 / dst->h; for (y=0; y<dst->h; ++y) { for (x=0; x<dst->w; ++x) { color = src->getpixel(MID(0, u, src->w-1), MID(0, v, src->h-1)); dst->putpixel(x, y, color); u += du; } u = 0.0; v += dv; } break; } // TODO optimize this case RESIZE_METHOD_BILINEAR: { uint32_t color[4], dst_color = 0; double u, v, du, dv; int u_floor, u_floor2; int v_floor, v_floor2; int x, y; u = v = 0.0; du = (src->w-1) * 1.0 / (dst->w-1); dv = (src->h-1) * 1.0 / (dst->h-1); for (y=0; y<dst->h; ++y) { for (x=0; x<dst->w; ++x) { u_floor = floor(u); v_floor = floor(v); if (u_floor > src->w-1) { u_floor = src->w-1; u_floor2 = src->w-1; } else if (u_floor == src->w-1) u_floor2 = u_floor; else u_floor2 = u_floor+1; if (v_floor > src->h-1) { v_floor = src->h-1; v_floor2 = src->h-1; } else if (v_floor == src->h-1) v_floor2 = v_floor; else v_floor2 = v_floor+1; // get the four colors color[0] = src->getpixel(u_floor, v_floor); color[1] = src->getpixel(u_floor2, v_floor); color[2] = src->getpixel(u_floor, v_floor2); color[3] = src->getpixel(u_floor2, v_floor2); // calculate the interpolated color double u1 = u - u_floor; double v1 = v - v_floor; double u2 = 1 - u1; double v2 = 1 - v1; switch (dst->getPixelFormat()) { case IMAGE_RGB: { int r = ((_rgba_getr(color[0])*u2 + _rgba_getr(color[1])*u1)*v2 + (_rgba_getr(color[2])*u2 + _rgba_getr(color[3])*u1)*v1); int g = ((_rgba_getg(color[0])*u2 + _rgba_getg(color[1])*u1)*v2 + (_rgba_getg(color[2])*u2 + _rgba_getg(color[3])*u1)*v1); int b = ((_rgba_getb(color[0])*u2 + _rgba_getb(color[1])*u1)*v2 + (_rgba_getb(color[2])*u2 + _rgba_getb(color[3])*u1)*v1); int a = ((_rgba_geta(color[0])*u2 + _rgba_geta(color[1])*u1)*v2 + (_rgba_geta(color[2])*u2 + _rgba_geta(color[3])*u1)*v1); dst_color = _rgba(r, g, b, a); break; } case IMAGE_GRAYSCALE: { int v = ((_graya_getv(color[0])*u2 + _graya_getv(color[1])*u1)*v2 + (_graya_getv(color[2])*u2 + _graya_getv(color[3])*u1)*v1); int a = ((_graya_geta(color[0])*u2 + _graya_geta(color[1])*u1)*v2 + (_graya_geta(color[2])*u2 + _graya_geta(color[3])*u1)*v1); dst_color = _graya(v, a); break; } case IMAGE_INDEXED: { int r = ((_rgba_getr(pal->getEntry(color[0]))*u2 + _rgba_getr(pal->getEntry(color[1]))*u1)*v2 + (_rgba_getr(pal->getEntry(color[2]))*u2 + _rgba_getr(pal->getEntry(color[3]))*u1)*v1); int g = ((_rgba_getg(pal->getEntry(color[0]))*u2 + _rgba_getg(pal->getEntry(color[1]))*u1)*v2 + (_rgba_getg(pal->getEntry(color[2]))*u2 + _rgba_getg(pal->getEntry(color[3]))*u1)*v1); int b = ((_rgba_getb(pal->getEntry(color[0]))*u2 + _rgba_getb(pal->getEntry(color[1]))*u1)*v2 + (_rgba_getb(pal->getEntry(color[2]))*u2 + _rgba_getb(pal->getEntry(color[3]))*u1)*v1); int a = (((color[0] == 0 ? 0: 255)*u2 + (color[1] == 0 ? 0: 255)*u1)*v2 + ((color[2] == 0 ? 0: 255)*u2 + (color[3] == 0 ? 0: 255)*u1)*v1); dst_color = a > 127 ? rgbmap->mapColor(r, g, b): 0; break; } case IMAGE_BITMAP: { int g = ((255*color[0]*u2 + 255*color[1]*u1)*v2 + (255*color[2]*u2 + 255*color[3]*u1)*v1); dst_color = g > 127 ? 1: 0; break; } } dst->putpixel(x, y, dst_color); u += du; } u = 0.0; v += dv; } break; } } }
/** * This routine does not modify the image to the human eye, but * internally tries to fixup all colors that are completelly * transparent (alpha = 0) with the average of its 4-neighbors. */ void image_fixup_transparent_colors(Image* image) { int x, y, u, v; switch (image->getPixelFormat()) { case IMAGE_RGB: { uint32_t c; int r, g, b, count; for (y=0; y<image->h; ++y) { for (x=0; x<image->w; ++x) { c = image_getpixel_fast<RgbTraits>(image, x, y); // if this is a completelly-transparent pixel... if (_rgba_geta(c) == 0) { count = 0; r = g = b = 0; for (v=y-1; v<=y+1; ++v) { for (u=x-1; u<=x+1; ++u) { if ((u >= 0) && (v >= 0) && (u < image->w) && (v < image->h)) { c = image_getpixel_fast<RgbTraits>(image, u, v); if (_rgba_geta(c) > 0) { r += _rgba_getr(c); g += _rgba_getg(c); b += _rgba_getb(c); ++count; } } } } if (count > 0) { r /= count; g /= count; b /= count; image_putpixel_fast<RgbTraits>(image, x, y, _rgba(r, g, b, 0)); } } } } break; } case IMAGE_GRAYSCALE: { uint16_t c; int k, count; for (y=0; y<image->h; ++y) { for (x=0; x<image->w; ++x) { c = image_getpixel_fast<GrayscaleTraits>(image, x, y); // if this is a completelly-transparent pixel... if (_graya_geta(c) == 0) { count = 0; k = 0; for (v=y-1; v<=y+1; ++v) { for (u=x-1; u<=x+1; ++u) { if ((u >= 0) && (v >= 0) && (u < image->w) && (v < image->h)) { c = image_getpixel_fast<GrayscaleTraits>(image, u, v); if (_graya_geta(c) > 0) { k += _graya_getv(c); ++count; } } } } if (count > 0) { k /= count; image_putpixel_fast<GrayscaleTraits>(image, x, y, _graya(k, 0)); } } } } break; } } }
GrayscaleTraits::pixel_t read_pixel(FILE* f) { k = fgetc(f); a = fgetc(f); return _graya(k, a); }
bool JpegFormat::onLoad(FileOp* fop) { struct jpeg_decompress_struct cinfo; struct error_mgr jerr; Image *image; FILE *file; JDIMENSION num_scanlines; JSAMPARRAY buffer; JDIMENSION buffer_height; int c; file = fopen(fop->filename.c_str(), "rb"); if (!file) return false; // Initialize the JPEG decompression object with error handling. jerr.fop = fop; cinfo.err = jpeg_std_error(&jerr.head); jerr.head.error_exit = error_exit; jerr.head.output_message = output_message; // Establish the setjmp return context for error_exit to use. if (setjmp(jerr.setjmp_buffer)) { jpeg_destroy_decompress(&cinfo); fclose(file); return false; } jpeg_create_decompress(&cinfo); // Specify data source for decompression. jpeg_stdio_src(&cinfo, file); // Read file header, set default decompression parameters. jpeg_read_header(&cinfo, true); if (cinfo.jpeg_color_space == JCS_GRAYSCALE) cinfo.out_color_space = JCS_GRAYSCALE; else cinfo.out_color_space = JCS_RGB; // Start decompressor. jpeg_start_decompress(&cinfo); // Create the image. image = fop_sequence_image(fop, (cinfo.out_color_space == JCS_RGB ? IMAGE_RGB: IMAGE_GRAYSCALE), cinfo.output_width, cinfo.output_height); if (!image) { jpeg_destroy_decompress(&cinfo); fclose(file); return false; } // Create the buffer. buffer_height = cinfo.rec_outbuf_height; buffer = (JSAMPARRAY)base_malloc(sizeof(JSAMPROW) * buffer_height); if (!buffer) { jpeg_destroy_decompress(&cinfo); fclose(file); return false; } for (c=0; c<(int)buffer_height; c++) { buffer[c] = (JSAMPROW)base_malloc(sizeof(JSAMPLE) * cinfo.output_width * cinfo.output_components); if (!buffer[c]) { for (c--; c>=0; c--) base_free(buffer[c]); base_free(buffer); jpeg_destroy_decompress(&cinfo); fclose(file); return false; } } // Generate a grayscale palette if is necessary. if (image->imgtype == IMAGE_GRAYSCALE) for (c=0; c<256; c++) fop_sequence_set_color(fop, c, c, c, c); // Read each scan line. while (cinfo.output_scanline < cinfo.output_height) { // TODO /* if (plugin_want_close()) */ /* break; */ num_scanlines = jpeg_read_scanlines(&cinfo, buffer, buffer_height); /* RGB */ if (image->imgtype == IMAGE_RGB) { uint8_t* src_address; uint32_t* dst_address; int x, y, r, g, b; for (y=0; y<(int)num_scanlines; y++) { src_address = ((uint8_t**)buffer)[y]; dst_address = ((uint32_t**)image->line)[cinfo.output_scanline-1+y]; for (x=0; x<image->w; x++) { r = *(src_address++); g = *(src_address++); b = *(src_address++); *(dst_address++) = _rgba(r, g, b, 255); } } } /* Grayscale */ else { uint8_t* src_address; uint16_t* dst_address; int x, y; for (y=0; y<(int)num_scanlines; y++) { src_address = ((uint8_t**)buffer)[y]; dst_address = ((uint16_t**)image->line)[cinfo.output_scanline-1+y]; for (x=0; x<image->w; x++) *(dst_address++) = _graya(*(src_address++), 255); } } fop_progress(fop, (float)(cinfo.output_scanline+1) / (float)(cinfo.output_height)); if (fop_is_stop(fop)) break; } /* destroy all data */ for (c=0; c<(int)buffer_height; c++) base_free(buffer[c]); base_free(buffer); jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo); fclose(file); return true; }
static void thumbnail_render(BITMAP* bmp, const Image* image, bool has_alpha, const Palette* palette) { register int c, x, y; int w, h, x1, y1; double sx, sy, scale; ASSERT(image != NULL); sx = (double)image->w / (double)bmp->w; sy = (double)image->h / (double)bmp->h; scale = MAX(sx, sy); w = image->w / scale; h = image->h / scale; w = MIN(bmp->w, w); h = MIN(bmp->h, h); x1 = bmp->w/2 - w/2; y1 = bmp->h/2 - h/2; x1 = MAX(0, x1); y1 = MAX(0, y1); /* with alpha blending */ if (has_alpha) { register int c2; rectgrid(bmp, 0, 0, bmp->w-1, bmp->h-1, bmp->w/4, bmp->h/4); switch (image->getPixelFormat()) { case IMAGE_RGB: for (y=0; y<h; y++) for (x=0; x<w; x++) { c = image_getpixel(image, x*scale, y*scale); c2 = getpixel(bmp, x1+x, y1+y); c = _rgba_blend_normal(_rgba(getr(c2), getg(c2), getb(c2), 255), c, 255); putpixel(bmp, x1+x, y1+y, makecol(_rgba_getr(c), _rgba_getg(c), _rgba_getb(c))); } break; case IMAGE_GRAYSCALE: for (y=0; y<h; y++) for (x=0; x<w; x++) { c = image_getpixel(image, x*scale, y*scale); c2 = getpixel(bmp, x1+x, y1+y); c = _graya_blend_normal(_graya(getr(c2), 255), c, 255); putpixel(bmp, x1+x, y1+y, makecol(_graya_getv(c), _graya_getv(c), _graya_getv(c))); } break; case IMAGE_INDEXED: { for (y=0; y<h; y++) for (x=0; x<w; x++) { c = image_getpixel(image, x*scale, y*scale); if (c != 0) { ASSERT(c >= 0 && c < palette->size()); c = palette->getEntry(MID(0, c, palette->size()-1)); putpixel(bmp, x1+x, y1+y, makecol(_rgba_getr(c), _rgba_getg(c), _rgba_getb(c))); } } break; } } } /* without alpha blending */ else { clear_to_color(bmp, makecol(128, 128, 128)); switch (image->getPixelFormat()) { case IMAGE_RGB: for (y=0; y<h; y++) for (x=0; x<w; x++) { c = image_getpixel(image, x*scale, y*scale); putpixel(bmp, x1+x, y1+y, makecol(_rgba_getr(c), _rgba_getg(c), _rgba_getb(c))); } break; case IMAGE_GRAYSCALE: for (y=0; y<h; y++) for (x=0; x<w; x++) { c = image_getpixel(image, x*scale, y*scale); putpixel(bmp, x1+x, y1+y, makecol(_graya_getv(c), _graya_getv(c), _graya_getv(c))); } break; case IMAGE_INDEXED: { for (y=0; y<h; y++) for (x=0; x<w; x++) { c = image_getpixel(image, x*scale, y*scale); ASSERT(c >= 0 && c < palette->size()); c = palette->getEntry(MID(0, c, palette->size()-1)); putpixel(bmp, x1+x, y1+y, makecol(_rgba_getr(c), _rgba_getg(c), _rgba_getb(c))); } break; } } } }