/* rle_tga_read32: * Helper for reading 32 bit RLE data from TGA files. */ static void rle_tga_read32 (uint32_t* address, int w, FILE *f) { unsigned char value[4]; int count; int c = 0; do { count = fgetc(f); if (count & 0x80) { count = (count & 0x7F) + 1; c += count; fread(value, 1, 4, f); while (count--) *(address++) = _rgba(value[2], value[1], value[0], value[3]); } else { count++; c += count; while (count--) { fread(value, 1, 4, f); *(address++) = _rgba(value[2], value[1], value[0], value[3]); } } } while (c < w); }
static Palette *ase_file_read_color2_chunk(FILE *f, Sprite *sprite, int frame) { int i, c, r, g, b, packets, skip, size; Palette* pal = new Palette(*sprite->getPalette(frame)); pal->setFrame(frame); packets = fgetw(f); // Number of packets skip = 0; // Read all packets for (i=0; i<packets; i++) { skip += fgetc(f); size = fgetc(f); if (!size) size = 256; for (c=skip; c<skip+size; c++) { r = fgetc(f); g = fgetc(f); b = fgetc(f); pal->setEntry(c, _rgba(r, g, b, 255)); } } return pal; }
RgbTraits::pixel_t read_pixel(FILE* f) { r = fgetc(f); g = fgetc(f); b = fgetc(f); a = fgetc(f); return _rgba(r, g, b, a); }
void InvertColorFilter::applyToRgba(FilterManager* filterMgr) { const uint32_t* src_address = (uint32_t*)filterMgr->getSourceAddress(); uint32_t* dst_address = (uint32_t*)filterMgr->getDestinationAddress(); int w = filterMgr->getWidth(); Target target = filterMgr->getTarget(); int x, c, r, g, b, a; for (x=0; x<w; x++) { if (filterMgr->skipPixel()) { ++src_address; ++dst_address; continue; } c = *(src_address++); r = _rgba_getr(c); g = _rgba_getg(c); b = _rgba_getb(c); a = _rgba_geta(c); if (target & TARGET_RED_CHANNEL) r ^= 0xff; if (target & TARGET_GREEN_CHANNEL) g ^= 0xff; if (target & TARGET_BLUE_CHANNEL) b ^= 0xff; if (target & TARGET_ALPHA_CHANNEL) a ^= 0xff; *(dst_address++) = _rgba(r, g, b, a); } }
void MedianFilter::applyToRgba(FilterManager* filterMgr) { const Image* src = filterMgr->getSourceImage(); uint32_t* dst_address = (uint32_t*)filterMgr->getDestinationAddress(); Target target = filterMgr->getTarget(); int color; int r, g, b, a; GetPixelsDelegateRgba 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<RgbTraits>(src, x, y, m_width, m_height, m_width/2, m_height/2, m_tiledMode, delegate); color = image_getpixel_fast<RgbTraits>(src, x, y); if (target & TARGET_RED_CHANNEL) { std::sort(m_channel[0].begin(), m_channel[0].end()); r = m_channel[0][m_ncolors/2]; } else r = _rgba_getr(color); if (target & TARGET_GREEN_CHANNEL) { std::sort(m_channel[1].begin(), m_channel[1].end()); g = m_channel[1][m_ncolors/2]; } else g = _rgba_getg(color); if (target & TARGET_BLUE_CHANNEL) { std::sort(m_channel[2].begin(), m_channel[2].end()); b = m_channel[2][m_ncolors/2]; } else b = _rgba_getb(color); if (target & TARGET_ALPHA_CHANNEL) { std::sort(m_channel[3].begin(), m_channel[3].end()); a = m_channel[3][m_ncolors/2]; } else a = _rgba_geta(color); *(dst_address++) = _rgba(r, g, b, a); } }
void read_scanline(RgbTraits::address_t address, int w, uint8_t* buffer) { for (int x=0; x<w; ++x) { r = *(buffer++); g = *(buffer++); b = *(buffer++); a = *(buffer++); *(address++) = _rgba(r, g, b, a); } }
inline void operator()(RgbTraits::address_t& scanline_address, RgbTraits::address_t& dst_address, GrayscaleTraits::address_t& src_address, int opacity) { if (*src_address != m_mask_color) { int v = _graya_getv(*src_address); *scanline_address = (*m_blend_color)(*dst_address, _rgba(v, v, v, _graya_geta(*src_address)), opacity); } else *scanline_address = *dst_address; }
Sprite::Sprite(PixelFormat format, int width, int height, int ncolors) : GfxObj(GFXOBJ_SPRITE) , m_format(format) , m_width(width) , m_height(height) , m_frames(1) { ASSERT(width > 0 && height > 0); m_frlens.push_back(100); // First frame with 100 msecs of duration m_stock = new Stock(format); m_folder = new LayerFolder(this); // Generate palette Palette pal(FrameNumber(0), ncolors); switch (format) { // For colored images case IMAGE_RGB: case IMAGE_INDEXED: pal.resize(ncolors); break; // For black and white images case IMAGE_GRAYSCALE: case IMAGE_BITMAP: for (int c=0; c<ncolors; c++) { int g = 255 * c / (ncolors-1); g = MID(0, g, 255); pal.setEntry(c, _rgba(g, g, g, 255)); } break; } // Initial RGB map m_rgbMap = NULL; // The transparent color for indexed images is 0 by default m_transparentColor = 0; setPalette(&pal, true); }
/** * 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; } } }
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; } } } }
void ConvolutionMatrixFilter::applyToRgba(FilterManager* filterMgr) { if (!m_matrix) return; const Image* src = filterMgr->getSourceImage(); uint32_t* dst_address = (uint32_t*)filterMgr->getDestinationAddress(); Target target = filterMgr->getTarget(); uint32_t color; GetPixelsDelegateRgba 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<RgbTraits>(src, x, y, m_matrix->getWidth(), m_matrix->getHeight(), m_matrix->getCenterX(), m_matrix->getCenterY(), m_tiledMode, delegate); color = image_getpixel_fast<RgbTraits>(src, x, y); if (delegate.div == 0) { *(dst_address++) = color; continue; } if (target & TARGET_RED_CHANNEL) { delegate.r = delegate.r / delegate.div + m_matrix->getBias(); delegate.r = MID(0, delegate.r, 255); } else delegate.r = _rgba_getr(color); if (target & TARGET_GREEN_CHANNEL) { delegate.g = delegate.g / delegate.div + m_matrix->getBias(); delegate.g = MID(0, delegate.g, 255); } else delegate.g = _rgba_getg(color); if (target & TARGET_BLUE_CHANNEL) { delegate.b = delegate.b / delegate.div + m_matrix->getBias(); delegate.b = MID(0, delegate.b, 255); } else delegate.b = _rgba_getb(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 = _rgba_geta(color); *(dst_address++) = _rgba(delegate.r, delegate.g, delegate.b, delegate.a); } }
/* loads a COL file (Animator and Animator Pro format) */ Palette *load_col_file(const char *filename) { #if (MAKE_VERSION(4, 2, 1) >= MAKE_VERSION(ALLEGRO_VERSION, \ ALLEGRO_SUB_VERSION, \ ALLEGRO_WIP_VERSION)) int size = file_size(filename); #else int size = file_size_ex(filename); #endif int pro = (size == 768)? false: true; /* is Animator Pro format? */ div_t d = div(size-8, 3); Palette *pal = NULL; int c, r, g, b; FILE *f; if (!(size) || (pro && d.rem)) /* invalid format */ return NULL; f = fopen(filename, "rb"); if (!f) return NULL; /* Animator format */ if (!pro) { pal = new Palette(FrameNumber(0), 256); for (c=0; c<256; c++) { r = fgetc(f); g = fgetc(f); b = fgetc(f); if (ferror(f)) break; pal->setEntry(c, _rgba(_rgb_scale_6[MID(0, r, 63)], _rgb_scale_6[MID(0, g, 63)], _rgb_scale_6[MID(0, b, 63)], 255)); } } /* Animator Pro format */ else { int magic, version; fgetl(f); /* skip file size */ magic = fgetw(f); /* file format identifier */ version = fgetw(f); /* version file */ /* unknown format */ if (magic != PROCOL_MAGIC_NUMBER || version != 0) { fclose(f); return NULL; } pal = new Palette(FrameNumber(0), MIN(d.quot, 256)); for (c=0; c<pal->size(); c++) { r = fgetc(f); g = fgetc(f); b = fgetc(f); if (ferror(f)) break; pal->setEntry(c, _rgba(MID(0, r, 255), MID(0, g, 255), MID(0, b, 255), 255)); } } fclose(f); return pal; }