int Color::getBlue() const { switch (getType()) { case Color::MaskType: return 0; case Color::RgbType: return m_value.rgb.b; case Color::HsvType: return Rgb(Hsv(m_value.hsv.h, double(m_value.hsv.s) / 100.0, double(m_value.hsv.v) / 100.0)).blue(); 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_getb(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; }
doc::Remap* ColorShades::createShadeRemap(bool left) { base::UniquePtr<doc::Remap> remap; Shade colors = getShade(); // We need two or more colors to create a shading remap. In // other case, the ShadingInkProcessing will use the full // color palette. if (colors.size() > 1) { remap.reset(new doc::Remap(get_current_palette()->size())); for (int i=0; i<remap->size(); ++i) remap->map(i, i); if (left) { for (int i=1; i<int(colors.size()); ++i) remap->map(colors[i].getIndex(), colors[i-1].getIndex()); } else { for (int i=0; i<int(colors.size())-1; ++i) remap->map(colors[i].getIndex(), colors[i+1].getIndex()); } } return remap.release(); }
void ChangeColorCommand::onExecute(Context* context) { ColorBar* colorbar = ColorBar::instance(); app::Color color = m_background ? colorbar->getBgColor(): colorbar->getFgColor(); switch (m_change) { case None: // do nothing break; case IncrementIndex: if (color.getType() == app::Color::IndexType) { int index = color.getIndex(); if (index < get_current_palette()->size()-1) color = app::Color::fromIndex(index+1); } else color = app::Color::fromIndex(0); break; case DecrementIndex: if (color.getType() == app::Color::IndexType) { int index = color.getIndex(); if (index > 0) color = app::Color::fromIndex(index-1); } else color = app::Color::fromIndex(0); break; } if (m_background) colorbar->setBgColor(color); else colorbar->setFgColor(color); }
int color_utils::color_for_allegro(const app::Color& color, int depth) { int c = -1; switch (color.getType()) { case app::Color::MaskType: c = get_mask_for_bitmap(depth); break; case app::Color::RgbType: case app::Color::HsvType: c = makeacol_depth(depth, color.getRed(), color.getGreen(), color.getBlue(), 255); break; case app::Color::GrayType: c = color.getGray(); if (depth != 8) c = makeacol_depth(depth, c, c, c, 255); break; case app::Color::IndexType: c = color.getIndex(); if (depth != 8) { ASSERT(c >= 0 && c < (int)get_current_palette()->size()); uint32_t _c = get_current_palette()->getEntry(c); c = makeacol_depth(depth, rgba_getr(_c), rgba_getg(_c), rgba_getb(_c), 255); } break; } return c; }
int ColorShades::size() const { int colors = 0; for (const auto& color : m_shade) { if ((color.getIndex() >= 0 && color.getIndex() < get_current_palette()->size()) || (m_click == ClickWholeShade)) { ++colors; } } return colors; }
// Returns false only if the color is a index and it is outside the // valid range (outside the maximum number of colors in the current // palette) bool Color::isValid() const { switch (getType()) { case Color::IndexType: { int i = m_value.index; return (i >= 0 && i < get_current_palette()->size()); } } return true; }
ui::Color color_utils::color_for_ui(const app::Color& color) { ui::Color c = ui::ColorNone; switch (color.getType()) { case app::Color::MaskType: c = ui::ColorNone; break; case app::Color::RgbType: case app::Color::HsvType: c = ui::rgba(color.getRed(), color.getGreen(), color.getBlue(), 255); break; case app::Color::GrayType: c = ui::rgba(color.getGray(), color.getGray(), color.getGray(), 255); break; case app::Color::IndexType: { int i = color.getIndex(); ASSERT(i >= 0 && i < (int)get_current_palette()->size()); uint32_t _c = get_current_palette()->getEntry(i); c = ui::rgba(rgba_getr(_c), rgba_getg(_c), rgba_getb(_c), 255); break; } } return c; }
void ColorSelector::findBestfitIndex(const Color& color) { // Find bestfit palette entry int r = color.getRed(); int g = color.getGreen(); int b = color.getBlue(); // Search for the closest color to the RGB values int i = get_current_palette()->findBestfit(r, g, b); if (i >= 0 && i < 256) { m_colorPalette.clearSelection(); m_colorPalette.selectColor(i); } }
Shade ColorShades::getShade() const { Shade colors; for (const auto& color : m_shade) { if ((color.getIndex() >= 0 && color.getIndex() < get_current_palette()->size()) || (m_click == ClickWholeShade)) { colors.push_back(color); } else if (m_click == ClickEntries) colors.push_back(color); } return colors; }
Color PaletteView::getColorByPosition(int target_x, int target_y) { Palette* palette = get_current_palette(); JRect cpos = jwidget_get_child_rect(this); div_t d = div(Palette::MaxColors, m_columns); int cols = m_columns; int rows = d.quot + ((d.rem)? 1: 0); int req_w, req_h; int x, y, u, v; int c; request_size(&req_w, &req_h); y = cpos->y1; c = 0; for (v=0; v<rows; v++) { x = cpos->x1; for (u=0; u<cols; u++) { if (c >= palette->size()) break; if ((target_x >= x) && (target_x <= x+m_boxsize) && (target_y >= y) && (target_y <= y+m_boxsize)) return Color::fromIndex(c); x += m_boxsize+this->child_spacing; c++; } y += m_boxsize+this->child_spacing; } jrect_free(cpos); return Color::fromMask(); }
void ColorQuantizationCommand::onExecute(Context* context) { try { ContextWriter writer(UIContext::instance(), 500); Sprite* sprite = writer.sprite(); frame_t frame = writer.frame(); if (sprite) { PalettePicks entries; ColorBar::instance()->getPaletteView()->getSelectedEntries(entries); entries.pickAllIfNeeded(); int n = entries.picks(); Palette palette(frame, n); render::create_palette_from_rgb(sprite, frame, &palette); Palette newPalette(*get_current_palette()); int i = 0, j = 0; for (bool state : entries) { if (state) newPalette.setEntry(i, palette.getEntry(j++)); ++i; } Transaction transaction(writer.context(), "Color Quantization", ModifyDocument); transaction.execute(new cmd::SetPalette(sprite, frame, &newPalette)); transaction.commit(); set_current_palette(&newPalette, false); ui::Manager::getDefault()->invalidate(); } } catch (base::Exception& e) { Console::showException(e); } }
raster::color_t color_utils::color_for_image(const app::Color& color, PixelFormat format) { if (color.getType() == app::Color::MaskType) return 0; raster::color_t c = -1; switch (format) { case IMAGE_RGB: c = rgba(color.getRed(), color.getGreen(), color.getBlue(), 255); break; case IMAGE_GRAYSCALE: c = graya(color.getGray(), 255); break; case IMAGE_INDEXED: if (color.getType() == app::Color::IndexType) c = color.getIndex(); else c = get_current_palette()->findBestfit(color.getRed(), color.getGreen(), color.getBlue()); break; } return c; }
void ColorQuantizationCommand::onExecute(Context* context) { try { app::gen::PaletteFromSprite window; PalettePicks entries; Sprite* sprite; frame_t frame; Palette* curPalette; { ContextReader reader(context); Site site = context->activeSite(); sprite = site.sprite(); frame = site.frame(); curPalette = sprite->palette(frame); window.newPalette()->setSelected(true); window.alphaChannel()->setSelected( App::instance()->preferences().quantization.withAlpha()); window.ncolors()->setText("256"); ColorBar::instance()->getPaletteView()->getSelectedEntries(entries); if (entries.picks() > 1) { window.currentRange()->setTextf( "%s, %d color(s)", window.currentRange()->text().c_str(), entries.picks()); } else window.currentRange()->setEnabled(false); window.currentPalette()->setTextf( "%s, %d color(s)", window.currentPalette()->text().c_str(), curPalette->size()); } window.openWindowInForeground(); if (window.closer() != window.ok()) return; bool withAlpha = window.alphaChannel()->isSelected(); App::instance()->preferences().quantization.withAlpha(withAlpha); bool createPal = false; if (window.newPalette()->isSelected()) { int n = window.ncolors()->textInt(); n = MAX(1, n); entries = PalettePicks(n); entries.all(); createPal = true; } else if (window.currentPalette()->isSelected()) { entries.all(); } if (entries.picks() == 0) return; Palette tmpPalette(frame, entries.picks()); ColorQuantizationJob job(sprite, withAlpha, &tmpPalette); job.startJob(); job.waitJob(); if (job.isCanceled()) return; base::UniquePtr<Palette> newPalette( new Palette(createPal ? tmpPalette: *get_current_palette())); if (createPal) { entries = PalettePicks(newPalette->size()); entries.all(); } int i = 0, j = 0; for (bool state : entries) { if (state) newPalette->setEntry(i, tmpPalette.getEntry(j++)); ++i; } if (*curPalette != *newPalette) { ContextWriter writer(UIContext::instance(), 500); Transaction transaction(writer.context(), "Color Quantization", ModifyDocument); transaction.execute(new cmd::SetPalette(sprite, frame, newPalette.get())); transaction.commit(); set_current_palette(newPalette.get(), false); ui::Manager::getDefault()->invalidate(); } } catch (base::Exception& e) { Console::showException(e); } }
void AddColorCommand::onExecute(Context* ctx) { app::Color appColor; switch (m_source) { case Source::Fg: appColor = ColorBar::instance()->getFgColor(); break; case Source::Bg: appColor = ColorBar::instance()->getBgColor(); break; case Source::Color: appColor = m_color; break; } try { Palette* newPalette = get_current_palette(); // System current pal color_t color = doc::rgba( appColor.getRed(), appColor.getGreen(), appColor.getBlue(), appColor.getAlpha()); int index = newPalette->findExactMatch( appColor.getRed(), appColor.getGreen(), appColor.getBlue(), appColor.getAlpha(), -1); // It should be -1, because the user has pressed the warning // button that is available only when the color isn't in the // palette. ASSERT(index < 0); if (index >= 0) return; ContextWriter writer(ctx, 500); Doc* document(writer.document()); Sprite* sprite = writer.sprite(); if (!document || !sprite) { ASSERT(false); return; } newPalette->addEntry(color); index = newPalette->size()-1; if (document) { frame_t frame = writer.frame(); Tx tx(writer.context(), friendlyName(), ModifyDocument); tx(new cmd::SetPalette(sprite, frame, newPalette)); tx.commit(); } set_current_palette(newPalette, true); ui::Manager::getDefault()->invalidate(); } catch (base::Exception& e) { Console::showException(e); } }
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(); }
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 ColorQuantizationCommand::onExecute(Context* context) { try { app::gen::PaletteFromSprite window; PalettePicks entries; Sprite* sprite; frame_t frame; Palette* curPalette; { ContextReader reader(context); Site site = context->activeSite(); sprite = site.sprite(); frame = site.frame(); curPalette = sprite->palette(frame); window.newPalette()->setSelected(true); window.alphaChannel()->setSelected( App::instance()->preferences().quantization.withAlpha()); window.ncolors()->setText("256"); ColorBar::instance()->getPaletteView()->getSelectedEntries(entries); if (entries.picks() > 1) { window.currentRange()->setTextf( "%s, %d color(s)", window.currentRange()->text().c_str(), entries.picks()); } else window.currentRange()->setEnabled(false); window.currentPalette()->setTextf( "%s, %d color(s)", window.currentPalette()->text().c_str(), curPalette->size()); } window.openWindowInForeground(); if (window.closer() != window.ok()) return; bool withAlpha = window.alphaChannel()->isSelected(); App::instance()->preferences().quantization.withAlpha(withAlpha); bool createPal = false; if (window.newPalette()->isSelected()) { int n = window.ncolors()->textInt(); n = MAX(1, n); entries = PalettePicks(n); entries.all(); createPal = true; } else if (window.currentPalette()->isSelected()) { entries.all(); } if (entries.picks() == 0) return; Palette tmpPalette(frame, entries.picks()); ContextReader reader(context); SpriteJob job(reader, "Color Quantization"); const bool newBlend = Preferences::instance().experimental.newBlend(); job.startJobWithCallback( [sprite, withAlpha, &tmpPalette, &job, newBlend]{ render::create_palette_from_sprite( sprite, 0, sprite->lastFrame(), withAlpha, &tmpPalette, &job, newBlend); // SpriteJob is a render::TaskDelegate }); job.waitJob(); if (job.isCanceled()) return; std::unique_ptr<Palette> newPalette( new Palette(createPal ? tmpPalette: *get_current_palette())); if (createPal) { entries = PalettePicks(newPalette->size()); entries.all(); } int i = 0, j = 0; for (bool state : entries) { if (state) newPalette->setEntry(i, tmpPalette.getEntry(j++)); ++i; } if (*curPalette != *newPalette) job.tx()(new cmd::SetPalette(sprite, frame, newPalette.get())); set_current_palette(newPalette.get(), false); ui::Manager::getDefault()->invalidate(); } catch (const base::Exception& e) { Console::showException(e); } }
/** * Shows the "New Sprite" dialog. */ void NewFileCommand::onExecute(Context* context) { Preferences& pref = Preferences::instance(); int ncolors = get_default_palette()->size(); char buf[1024]; app::Color bg_table[] = { app::Color::fromMask(), app::Color::fromRgb(255, 255, 255), app::Color::fromRgb(0, 0, 0), }; // Load the window widget app::gen::NewSprite window; // Default values: Indexed, 320x240, Background color PixelFormat format = pref.newFile.colorMode(); // Invalid format in config file. if (format != IMAGE_RGB && format != IMAGE_INDEXED && format != IMAGE_GRAYSCALE) { format = IMAGE_INDEXED; } int w = pref.newFile.width(); int h = pref.newFile.height(); int bg = pref.newFile.backgroundColor(); bg = MID(0, bg, 2); // If the clipboard contains an image, we can show the size of the // clipboard as default image size. gfx::Size clipboardSize; if (clipboard::get_image_size(clipboardSize)) { w = clipboardSize.w; h = clipboardSize.h; } window.width()->setTextf("%d", MAX(1, w)); window.height()->setTextf("%d", MAX(1, h)); // Select image-type window.colorMode()->setSelectedItem(format); // Select background color window.bgColor()->setSelectedItem(bg); // Advance options bool advanced = pref.newFile.advanced(); window.advancedCheck()->setSelected(advanced); window.advancedCheck()->Click.connect( base::Bind<void>( [&]{ gfx::Rect bounds = window.bounds(); window.advanced()->setVisible(window.advancedCheck()->isSelected()); window.setBounds(gfx::Rect(window.bounds().origin(), window.sizeHint())); window.layout(); window.manager()->invalidateRect(bounds); })); window.advanced()->setVisible(advanced); if (advanced) window.pixelRatio()->setValue(pref.newFile.pixelRatio()); else window.pixelRatio()->setValue("1:1"); // Open the window window.openWindowInForeground(); if (window.closer() == window.okButton()) { bool ok = false; // Get the options format = (doc::PixelFormat)window.colorMode()->selectedItem(); w = window.width()->textInt(); h = window.height()->textInt(); bg = window.bgColor()->selectedItem(); static_assert(IMAGE_RGB == 0, "RGB pixel format should be 0"); static_assert(IMAGE_INDEXED == 2, "Indexed pixel format should be 2"); format = MID(IMAGE_RGB, format, IMAGE_INDEXED); w = MID(1, w, DOC_SPRITE_MAX_WIDTH); h = MID(1, h, DOC_SPRITE_MAX_HEIGHT); bg = MID(0, bg, 2); // Select the color app::Color color = app::Color::fromMask(); if (bg >= 0 && bg <= 3) { color = bg_table[bg]; ok = true; } if (ok) { // Save the configuration pref.newFile.width(w); pref.newFile.height(h); pref.newFile.colorMode(format); pref.newFile.backgroundColor(bg); pref.newFile.advanced(window.advancedCheck()->isSelected()); pref.newFile.pixelRatio(window.pixelRatio()->getValue()); // Create the new sprite ASSERT(format == IMAGE_RGB || format == IMAGE_GRAYSCALE || format == IMAGE_INDEXED); ASSERT(w > 0 && h > 0); std::unique_ptr<Sprite> sprite(Sprite::createBasicSprite(format, w, h, ncolors)); if (window.advancedCheck()->isSelected()) { sprite->setPixelRatio( base::convert_to<PixelRatio>(window.pixelRatio()->getValue())); } if (sprite->pixelFormat() != IMAGE_GRAYSCALE) get_default_palette()->copyColorsTo(sprite->palette(frame_t(0))); // If the background color isn't transparent, we have to // convert the `Layer 1' in a `Background' if (color.getType() != app::Color::MaskType) { Layer* layer = sprite->root()->firstLayer(); if (layer && layer->isImage()) { LayerImage* layerImage = static_cast<LayerImage*>(layer); layerImage->configureAsBackground(); Image* image = layerImage->cel(frame_t(0))->image(); // TODO Replace this adding a new parameter to color utils Palette oldPal = *get_current_palette(); set_current_palette(get_default_palette(), false); doc::clear_image(image, color_utils::color_for_target(color, ColorTarget( ColorTarget::BackgroundLayer, sprite->pixelFormat(), sprite->transparentColor()))); set_current_palette(&oldPal, false); } } // Show the sprite to the user std::unique_ptr<Doc> doc(new Doc(sprite.get())); sprite.release(); sprintf(buf, "Sprite-%04d", ++_sprite_counter); doc->setFilename(buf); doc->setContext(context); doc.release(); } } }