int Color::getGreen() const { switch (getType()) { case Color::MaskType: return 0; case Color::RgbType: return m_value.rgb.g; case Color::HsvType: return Rgb(Hsv(m_value.hsv.h, double(m_value.hsv.s) / 100.0, double(m_value.hsv.v) / 100.0)).green(); case Color::GrayType: return m_value.gray; case Color::IndexType: { int i = m_value.index; ASSERT(i >= 0 && i < get_current_palette()->size()); return _rgba_getg(get_current_palette()->getEntry(i)); } } ASSERT(false); return -1; }
int Color::getGray() const { switch (getType()) { case Color::MaskType: return 0; case Color::RgbType: return 255 * Hsv(Rgb(m_value.rgb.r, m_value.rgb.g, m_value.rgb.b)).valueInt() / 100; case Color::HsvType: return 255 * m_value.hsv.v / 100; case Color::GrayType: return m_value.gray; case Color::IndexType: { int i = m_value.index; ASSERT(i >= 0 && i < get_current_palette()->size()); uint32_t c = get_current_palette()->getEntry(i); return 255 * Hsv(Rgb(_rgba_getr(c), _rgba_getg(c), _rgba_getb(c))).valueInt() / 100; } } ASSERT(false); return -1; }
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); } }
// static Color Color::fromImage(PixelFormat pixelFormat, int c) { Color color = Color::fromMask(); switch (pixelFormat) { case IMAGE_RGB: if (_rgba_geta(c) > 0) { color = Color::fromRgb(_rgba_getr(c), _rgba_getg(c), _rgba_getb(c)); } break; case IMAGE_GRAYSCALE: if (_graya_geta(c) > 0) { color = Color::fromGray(_graya_getv(c)); } break; case IMAGE_INDEXED: color = Color::fromIndex(c); break; } return color; }
void MedianFilter::applyToIndexed(FilterManager* filterMgr) { const Image* src = filterMgr->getSourceImage(); uint8_t* dst_address = (uint8_t*)filterMgr->getDestinationAddress(); const Palette* pal = filterMgr->getIndexedData()->getPalette(); const RgbMap* rgbmap = filterMgr->getIndexedData()->getRgbMap(); Target target = filterMgr->getTarget(); int color, r, g, b; GetPixelsDelegateIndexed delegate(pal, m_channel, target); 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<IndexedTraits>(src, x, y, m_width, m_height, m_width/2, m_height/2, m_tiledMode, delegate); if (target & TARGET_INDEX_CHANNEL) { std::sort(m_channel[0].begin(), m_channel[0].end()); *(dst_address++) = m_channel[0][m_ncolors/2]; } else { color = image_getpixel_fast<IndexedTraits>(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(pal->getEntry(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(pal->getEntry(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(pal->getEntry(color)); *(dst_address++) = rgbmap->mapColor(r, g, b); } } }
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 write_scanline(RgbTraits::address_t address, int w, uint8_t* buffer) { for (int x=0; x<w; ++x) { *(buffer++) = _rgba_getr(*address); *(buffer++) = _rgba_getg(*address); *(buffer++) = _rgba_getb(*address); *(buffer++) = _rgba_geta(*address); ++address; } }
static inline bool color_equal_32(uint32_t c1, uint32_t c2, int tolerance) { if (tolerance == 0) return (c1 == c2) || (_rgba_geta(c1) == 0 && _rgba_geta(c2) == 0); else { int r1 = _rgba_getr(c1); int g1 = _rgba_getg(c1); int b1 = _rgba_getb(c1); int a1 = _rgba_geta(c1); int r2 = _rgba_getr(c2); int g2 = _rgba_getg(c2); int b2 = _rgba_getb(c2); int a2 = _rgba_geta(c2); if (a1 == 0 && a2 == 0) return true; return ((ABS(r1-r2) <= tolerance) && (ABS(g1-g2) <= tolerance) && (ABS(b1-b2) <= tolerance) && (ABS(a1-a2) <= tolerance)); } }
void ReplaceColorFilter::applyToRgba(FilterManager* filterMgr) { const uint32_t* src_address = (uint32_t*)filterMgr->getSourceAddress(); uint32_t* dst_address = (uint32_t*)filterMgr->getDestinationAddress(); int w = filterMgr->getWidth(); int src_r, src_g, src_b, src_a; int dst_r, dst_g, dst_b, dst_a; int x, c; dst_r = _rgba_getr(m_from); dst_g = _rgba_getg(m_from); dst_b = _rgba_getb(m_from); dst_a = _rgba_geta(m_from); for (x=0; x<w; x++) { if (filterMgr->skipPixel()) { ++src_address; ++dst_address; continue; } c = *(src_address++); src_r = _rgba_getr(c); src_g = _rgba_getg(c); src_b = _rgba_getb(c); src_a = _rgba_geta(c); if ((ABS(src_r-dst_r) <= m_tolerance) && (ABS(src_g-dst_g) <= m_tolerance) && (ABS(src_b-dst_b) <= m_tolerance) && (ABS(src_a-dst_a) <= m_tolerance)) *(dst_address++) = m_to; else *(dst_address++) = c; } }
/* writes the original color chunk in FLI files for the entire palette "pal" */ static void ase_file_write_color2_chunk(FILE *f, Palette *pal) { int c, color; ase_file_write_start_chunk(f, ASE_FILE_CHUNK_FLI_COLOR2); fputw(1, f); // number of packets // First packet fputc(0, f); // skip 0 colors fputc(pal->size() == 256 ? 0: pal->size(), f); // number of colors for (c=0; c<pal->size(); c++) { color = pal->getEntry(c); fputc(_rgba_getr(color), f); fputc(_rgba_getg(color), f); fputc(_rgba_getb(color), f); } ase_file_write_close_chunk(f); }
void InvertColorFilter::applyToIndexed(FilterManager* filterMgr) { const uint8_t* src_address = (uint8_t*)filterMgr->getSourceAddress(); uint8_t* dst_address = (uint8_t*)filterMgr->getDestinationAddress(); const Palette* pal = filterMgr->getIndexedData()->getPalette(); const RgbMap* rgbmap = filterMgr->getIndexedData()->getRgbMap(); int w = filterMgr->getWidth(); Target target = filterMgr->getTarget(); int x, c, r, g, b; for (x=0; x<w; x++) { if (filterMgr->skipPixel()) { ++src_address; ++dst_address; continue; } c = *(src_address++); if (target & TARGET_INDEX_CHANNEL) c ^= 0xff; else { r = _rgba_getr(pal->getEntry(c)); g = _rgba_getg(pal->getEntry(c)); b = _rgba_getb(pal->getEntry(c)); if (target & TARGET_RED_CHANNEL ) r ^= 0xff; if (target & TARGET_GREEN_CHANNEL) g ^= 0xff; if (target & TARGET_BLUE_CHANNEL ) b ^= 0xff; c = rgbmap->mapColor(r, g, b); } *(dst_address++) = c; } }
/* saves an Animator Pro COL file */ bool save_col_file(const Palette *pal, const char *filename) { FILE *f = fopen(filename, "wb"); if (!f) return false; fputl(8+768, f); /* file size */ fputw(PROCOL_MAGIC_NUMBER, f); /* file format identifier */ fputw(0, f); /* version file */ uint32_t c; for (int i=0; i<256; i++) { c = pal->getEntry(i); fputc(_rgba_getr(c), f); fputc(_rgba_getg(c), f); fputc(_rgba_getb(c), f); if (ferror(f)) break; } fclose(f); return true; }
bool FliFormat::onSave(FileOp* fop) { Sprite* sprite = fop->document->getSprite(); unsigned char cmap[768]; unsigned char omap[768]; s_fli_header fli_header; int c, times; Image *bmp, *old; Palette *pal; /* prepare fli header */ fli_header.filesize = 0; fli_header.frames = 0; fli_header.width = sprite->getWidth(); fli_header.height = sprite->getHeight(); if ((fli_header.width == 320) && (fli_header.height == 200)) fli_header.magic = HEADER_FLI; else fli_header.magic = HEADER_FLC; fli_header.depth = 8; fli_header.flags = 3; fli_header.speed = get_time_precision(sprite); fli_header.created = 0; fli_header.updated = 0; fli_header.aspect_x = 1; fli_header.aspect_y = 1; fli_header.oframe1 = fli_header.oframe2 = 0; /* open the file to write in binary mode */ FileHandle f(fop->filename.c_str(), "wb"); fseek(f, 128, SEEK_SET); /* create the bitmaps */ bmp = Image::create(IMAGE_INDEXED, sprite->getWidth(), sprite->getHeight()); old = Image::create(IMAGE_INDEXED, sprite->getWidth(), sprite->getHeight()); if ((!bmp) || (!old)) { fop_error(fop, "Not enough memory for temporary bitmaps.\n"); if (bmp) image_free(bmp); if (old) image_free(old); return false; } /* write frame by frame */ for (FrameNumber frpos(0); frpos < sprite->getTotalFrames(); ++frpos) { /* get color map */ pal = sprite->getPalette(frpos); for (c=0; c<256; c++) { cmap[3*c ] = _rgba_getr(pal->getEntry(c)); cmap[3*c+1] = _rgba_getg(pal->getEntry(c)); cmap[3*c+2] = _rgba_getb(pal->getEntry(c)); } /* render the frame in the bitmap */ image_clear(bmp, 0); layer_render(sprite->getFolder(), bmp, 0, 0, frpos); /* how many times this frame should be written to get the same time that it has in the sprite */ times = sprite->getFrameDuration(frpos) / fli_header.speed; for (c=0; c<times; c++) { /* write this frame */ if (frpos == 0 && c == 0) fli_write_frame(f, &fli_header, NULL, NULL, (unsigned char *)bmp->dat, cmap, W_ALL); else fli_write_frame(f, &fli_header, (unsigned char *)old->dat, omap, (unsigned char *)bmp->dat, cmap, W_ALL); /* update the old image and color-map to the new ones to compare later */ image_copy(old, bmp, 0, 0); memcpy(omap, cmap, 768); } /* update progress */ fop_progress(fop, (float)(frpos.next()) / (float)(sprite->getTotalFrames())); } /* write the header and close the file */ fli_write_header(f, &fli_header); /* destroy the bitmaps */ image_free(bmp); image_free(old); return true; }
bool PaletteView::onProcessMessage(Message* msg) { switch (msg->type) { case JM_REQSIZE: request_size(&msg->reqsize.w, &msg->reqsize.h); return true; case JM_DRAW: { div_t d = div(Palette::MaxColors, m_columns); int cols = m_columns; int rows = d.quot + ((d.rem)? 1: 0); int x, y, u, v; int c, color; BITMAP *bmp; Palette* palette = get_current_palette(); int bordercolor = makecol(255, 255, 255); bmp = create_bitmap(jrect_w(this->rc), jrect_h(this->rc)); clear_to_color(bmp, makecol(0 , 0, 0)); y = this->border_width.t; c = 0; for (v=0; v<rows; v++) { x = this->border_width.l; for (u=0; u<cols; u++) { if (c >= palette->size()) break; if (bitmap_color_depth(ji_screen) == 8) color = c; else color = makecol_depth (bitmap_color_depth(ji_screen), _rgba_getr(palette->getEntry(c)), _rgba_getg(palette->getEntry(c)), _rgba_getb(palette->getEntry(c))); rectfill(bmp, x, y, x+m_boxsize-1, y+m_boxsize-1, color); if (m_selectedEntries[c]) { const int max = Palette::MaxColors; bool top = (c >= m_columns && c-m_columns >= 0 ? m_selectedEntries[c-m_columns]: false); bool bottom = (c < max-m_columns && c+m_columns < max ? m_selectedEntries[c+m_columns]: false); bool left = ((c%m_columns)>0 && c-1 >= 0 ? m_selectedEntries[c-1]: false); bool right = ((c%m_columns)<m_columns-1 && c+1 < max ? m_selectedEntries[c+1]: false); if (!top) hline(bmp, x-1, y-1, x+m_boxsize, bordercolor); if (!bottom) hline(bmp, x-1, y+m_boxsize, x+m_boxsize, bordercolor); if (!left) vline(bmp, x-1, y-1, y+m_boxsize, bordercolor); if (!right) vline(bmp, x+m_boxsize, y-1, y+m_boxsize, bordercolor); } x += m_boxsize+this->child_spacing; c++; } y += m_boxsize+this->child_spacing; } blit(bmp, ji_screen, 0, 0, this->rc->x1, this->rc->y1, bmp->w, bmp->h); destroy_bitmap(bmp); return true; } case JM_BUTTONPRESSED: captureMouse(); /* continue... */ case JM_MOTION: { JRect cpos = jwidget_get_child_rect(this); int req_w, req_h; request_size(&req_w, &req_h); int mouse_x = MID(cpos->x1, msg->mouse.x, cpos->x1+req_w-this->border_width.r-1); int mouse_y = MID(cpos->y1, msg->mouse.y, cpos->y1+req_h-this->border_width.b-1); jrect_free(cpos); Color color = getColorByPosition(mouse_x, mouse_y); if (color.getType() == Color::IndexType) { int idx = color.getIndex(); app_get_statusbar()->showColor(0, "", color, 255); if (hasCapture() && idx != m_currentEntry) { if (!(msg->any.shifts & KB_CTRL_FLAG)) clearSelection(); if (msg->any.shifts & KB_SHIFT_FLAG) selectRange(m_rangeAnchor, idx); else selectColor(idx); // Emit signals jwidget_emit_signal(this, SIGNAL_PALETTE_EDITOR_CHANGE); IndexChange(idx); } } if (hasCapture()) return true; break; } case JM_BUTTONRELEASED: releaseMouse(); return true; case JM_WHEEL: { View* view = View::getView(this); if (view) { gfx::Point scroll = view->getViewScroll(); scroll.y += (jmouse_z(1)-jmouse_z(0)) * 3 * m_boxsize; view->setViewScroll(scroll); } break; } case JM_MOUSELEAVE: app_get_statusbar()->clearText(); break; } return Widget::onProcessMessage(msg); }
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); } }
std::string Color::toHumanReadableString(PixelFormat pixelFormat, HumanReadableString humanReadable) const { std::stringstream result; if (humanReadable == LongHumanReadableString) { switch (getType()) { case Color::MaskType: result << "Mask"; break; case Color::RgbType: if (pixelFormat == IMAGE_GRAYSCALE) { result << "Gray " << getGray(); } else { result << "RGB " << m_value.rgb.r << " " << m_value.rgb.g << " " << m_value.rgb.b; if (pixelFormat == IMAGE_INDEXED) result << " Index " << color_utils::color_for_image(*this, pixelFormat); } break; case Color::HsvType: if (pixelFormat == IMAGE_GRAYSCALE) { result << "Gray " << getGray(); } else { result << "HSB " << m_value.hsv.h << "\xB0 " << m_value.hsv.s << " " << m_value.hsv.v; if (pixelFormat == IMAGE_INDEXED) result << " Index " << color_utils::color_for_image(*this, pixelFormat); } break; case Color::GrayType: result << "Gray " << m_value.gray; break; case Color::IndexType: { int i = m_value.index; if (i >= 0 && i < (int)get_current_palette()->size()) { uint32_t _c = get_current_palette()->getEntry(i); result << "Index " << i << " (RGB " << (int)_rgba_getr(_c) << " " << (int)_rgba_getg(_c) << " " << (int)_rgba_getb(_c) << ")"; } else { result << "Index " << i << " (out of range)"; } break; } default: ASSERT(false); break; } } else if (humanReadable == ShortHumanReadableString) { switch (getType()) { case Color::MaskType: result << "Mask"; break; case Color::RgbType: if (pixelFormat == IMAGE_GRAYSCALE) { result << "Gry-" << getGray(); } else { result << "#" << std::hex << std::setfill('0') << std::setw(2) << m_value.rgb.r << std::setw(2) << m_value.rgb.g << std::setw(2) << m_value.rgb.b; } break; case Color::HsvType: if (pixelFormat == IMAGE_GRAYSCALE) { result << "Gry-" << getGray(); } else { result << m_value.hsv.h << "\xB0" << m_value.hsv.s << "," << m_value.hsv.v; } break; case Color::GrayType: result << "Gry-" << m_value.gray; break; case Color::IndexType: result << "Idx-" << m_value.index; break; default: ASSERT(false); break; } } return result.str(); }
void ConvolutionMatrixFilter::applyToIndexed(FilterManager* filterMgr) { if (!m_matrix) return; const Image* src = filterMgr->getSourceImage(); uint8_t* dst_address = (uint8_t*)filterMgr->getDestinationAddress(); const Palette* pal = filterMgr->getIndexedData()->getPalette(); const RgbMap* rgbmap = filterMgr->getIndexedData()->getRgbMap(); Target target = filterMgr->getTarget(); uint8_t color; GetPixelsDelegateIndexed delegate(pal); 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<IndexedTraits>(src, x, y, m_matrix->getWidth(), m_matrix->getHeight(), m_matrix->getCenterX(), m_matrix->getCenterY(), m_tiledMode, delegate); color = image_getpixel_fast<IndexedTraits>(src, x, y); if (delegate.div == 0) { *(dst_address++) = color; continue; } if (target & TARGET_INDEX_CHANNEL) { delegate.index = delegate.index / m_matrix->getDiv() + m_matrix->getBias(); delegate.index = MID(0, delegate.index, 255); *(dst_address++) = delegate.index; } else { 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(pal->getEntry(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(pal->getEntry(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(pal->getEntry(color)); *(dst_address++) = rgbmap->mapColor(delegate.r, delegate.g, delegate.b); } } }
/** * 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; } } }
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 write_pixel(FILE* f, RgbTraits::pixel_t c) { fputc(_rgba_getr(c), f); fputc(_rgba_getg(c), f); fputc(_rgba_getb(c), f); fputc(_rgba_geta(c), f); }
bool JpegFormat::onSave(FileOp* fop) { struct jpeg_compress_struct cinfo; struct error_mgr jerr; Image *image = fop->seq.image; FILE *file; JSAMPARRAY buffer; JDIMENSION buffer_height; SharedPtr<JpegOptions> jpeg_options = fop->seq.format_options; int c; // Open the file for write in it. file = fopen(fop->filename.c_str(), "wb"); if (!file) { fop_error(fop, "Error creating file.\n"); return false; } // Allocate and initialize JPEG compression object. jerr.fop = fop; cinfo.err = jpeg_std_error(&jerr.head); jpeg_create_compress(&cinfo); // SPECIFY data destination file. jpeg_stdio_dest(&cinfo, file); // SET parameters for compression. cinfo.image_width = image->w; cinfo.image_height = image->h; if (image->imgtype == IMAGE_GRAYSCALE) { cinfo.input_components = 1; cinfo.in_color_space = JCS_GRAYSCALE; } else { cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; } jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, (int)MID(0, 100.0f * jpeg_options->quality, 100), true); cinfo.dct_method = JDCT_ISLOW; cinfo.smoothing_factor = 0; // START compressor. jpeg_start_compress(&cinfo, true); // CREATE the buffer. buffer_height = 1; buffer = (JSAMPARRAY)base_malloc(sizeof(JSAMPROW) * buffer_height); if (!buffer) { fop_error(fop, "Not enough memory for the buffer.\n"); jpeg_destroy_compress(&cinfo); fclose(file); return false; } for (c=0; c<(int)buffer_height; c++) { buffer[c] = (JSAMPROW)base_malloc(sizeof(JSAMPLE) * cinfo.image_width * cinfo.num_components); if (!buffer[c]) { fop_error(fop, "Not enough memory for buffer scanlines.\n"); for (c--; c>=0; c--) base_free(buffer[c]); base_free(buffer); jpeg_destroy_compress(&cinfo); fclose(file); return false; } } // Write each scan line. while (cinfo.next_scanline < cinfo.image_height) { // RGB if (image->imgtype == IMAGE_RGB) { uint32_t* src_address; uint8_t* dst_address; int x, y; for (y=0; y<(int)buffer_height; y++) { src_address = ((uint32_t**)image->line)[cinfo.next_scanline+y]; dst_address = ((uint8_t**)buffer)[y]; for (x=0; x<image->w; x++) { c = *(src_address++); *(dst_address++) = _rgba_getr(c); *(dst_address++) = _rgba_getg(c); *(dst_address++) = _rgba_getb(c); } } } // Grayscale. else { uint16_t* src_address; uint8_t* dst_address; int x, y; for (y=0; y<(int)buffer_height; y++) { src_address = ((uint16_t**)image->line)[cinfo.next_scanline+y]; dst_address = ((uint8_t**)buffer)[y]; for (x=0; x<image->w; x++) *(dst_address++) = _graya_getv(*(src_address++)); } } jpeg_write_scanlines(&cinfo, buffer, buffer_height); fop_progress(fop, (float)(cinfo.next_scanline+1) / (float)(cinfo.image_height)); } // Destroy all data. for (c=0; c<(int)buffer_height; c++) base_free(buffer[c]); base_free(buffer); // Finish compression. jpeg_finish_compress(&cinfo); // Release JPEG compression object. jpeg_destroy_compress(&cinfo); // We can close the output file. fclose(file); // All fine. return true; }