// Aseprite Document Library // Copyright (c) 2001-2017 David Capello // // This file is released under the terms of the MIT license. // Read LICENSE.txt for more information. #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "doc/palette.h" #include "base/base.h" #include "doc/image.h" #include "doc/remap.h" #include #include namespace doc { using namespace gfx; Palette::Palette(frame_t frame, int ncolors) : Object(ObjectType::Palette) { ASSERT(ncolors >= 0); m_frame = frame; m_colors.resize(ncolors, doc::rgba(0, 0, 0, 255)); m_modifications = 0; } Palette::Palette(const Palette& palette) : Object(palette) , m_comment(palette.m_comment) { m_frame = palette.m_frame; m_colors = palette.m_colors; m_modifications = 0; } Palette::Palette(const Palette& palette, const Remap& remap) : Object(palette) , m_comment(palette.m_comment) { m_frame = palette.m_frame; resize(palette.size()); for (int i=0; isetEntry(c, rgba(c, c, c, 255)); return graypal; } void Palette::resize(int ncolors) { ASSERT(ncolors >= 0); m_colors.resize(ncolors, doc::rgba(0, 0, 0, 255)); ++m_modifications; } void Palette::addEntry(color_t color) { resize(size()+1); setEntry(size()-1, color); } bool Palette::hasAlpha() const { for (int i=0; i<(int)m_colors.size(); ++i) if (rgba_geta(getEntry(i)) < 255) return true; return false; } void Palette::setFrame(frame_t frame) { ASSERT(frame >= 0); m_frame = frame; } void Palette::setEntry(int i, color_t color) { ASSERT(i >= 0 && i < size()); m_colors[i] = color; ++m_modifications; } void Palette::copyColorsTo(Palette* dst) const { dst->m_colors = m_colors; ++dst->m_modifications; } int Palette::countDiff(const Palette* other, int* from, int* to) const { int c, diff = 0; int min = MIN(this->m_colors.size(), other->m_colors.size()); int max = MAX(this->m_colors.size(), other->m_colors.size()); if (from) *from = -1; if (to) *to = -1; // Compare palettes for (c=0; cm_colors[c] != other->m_colors[c]) { if (from && *from < 0) *from = c; if (to) *to = c; ++diff; } } if (max != min) { diff += max - min; if (from && *from < 0) *from = min; if (to) *to = max-1; } return diff; } bool Palette::isBlack() const { for (std::size_t c=0; c= 0 && from < size()); ASSERT(to >= 0 && to < size()); if (from > to) std::swap(from, to); n = to - from; if (n < 2) return; r1 = rgba_getr(getEntry(from)); g1 = rgba_getg(getEntry(from)); b1 = rgba_getb(getEntry(from)); a1 = rgba_geta(getEntry(from)); r2 = rgba_getr(getEntry(to)); g2 = rgba_getg(getEntry(to)); b2 = rgba_getb(getEntry(to)); a2 = rgba_geta(getEntry(to)); for (i=from+1; i col_diff; static uint32_t* col_diff_g; static uint32_t* col_diff_r; static uint32_t* col_diff_b; static uint32_t* col_diff_a; static void initBestfit() { col_diff.resize(4*128, 0); col_diff_g = &col_diff[128*0]; col_diff_r = &col_diff[128*1]; col_diff_b = &col_diff[128*2]; col_diff_a = &col_diff[128*3]; for (int i=1; i<64; ++i) { int k = i * i; col_diff_g[i] = col_diff_g[128-i] = k * 59 * 59; col_diff_r[i] = col_diff_r[128-i] = k * 30 * 30; col_diff_b[i] = col_diff_b[128-i] = k * 11 * 11; col_diff_a[i] = col_diff_a[128-i] = k * 8 * 8; } } int Palette::findBestfit(int r, int g, int b, int a, int mask_index) const { ASSERT(r >= 0 && r <= 255); ASSERT(g >= 0 && g <= 255); ASSERT(b >= 0 && b <= 255); ASSERT(a >= 0 && a <= 255); if (col_diff.empty()) initBestfit(); r >>= 3; g >>= 3; b >>= 3; a >>= 3; // Mask index is like alpha = 0, so we can use it as transparent color. if (a == 0 && mask_index >= 0) return mask_index; int bestfit = 0; int lowest = std::numeric_limits::max(); int size = MIN(256, m_colors.size()); for (int i=0; i>3) - g) & 127]; if (coldiff < lowest) { coldiff += col_diff_r[(((rgba_getr(rgb)>>3) - r) & 127)]; if (coldiff < lowest) { coldiff += col_diff_b[(((rgba_getb(rgb)>>3) - b) & 127)]; if (coldiff < lowest) { coldiff += col_diff_a[(((rgba_geta(rgb)>>3) - a) & 127)]; if (coldiff < lowest && i != mask_index) { if (coldiff == 0) return i; bestfit = i; lowest = coldiff; } } } } } return bestfit; } void Palette::applyRemap(const Remap& remap) { Palette original(*this); for (int i=0; i= int(m_names.size())) m_names.resize(i+1); m_names[i] = name; } const std::string& Palette::getEntryName(const int i) const { if (i >= 0 && i < int(m_names.size())) return m_names[i]; else { static std::string emptyString; return emptyString; } } } // namespace doc