mirror of https://github.com/aseprite/aseprite.git
Merge 3efd0014e8
into 2ba051b59b
This commit is contained in:
commit
21b327ee74
|
@ -1050,7 +1050,47 @@ public:
|
||||||
m_fop->newBlend(),
|
m_fop->newBlend(),
|
||||||
RgbMapAlgorithm::OCTREE, // TODO configurable?
|
RgbMapAlgorithm::OCTREE, // TODO configurable?
|
||||||
false); // Do not add the transparent color yet
|
false); // Do not add the transparent color yet
|
||||||
|
m_transparentIndex = 0;
|
||||||
|
m_globalColormapPalette = newPalette;
|
||||||
|
m_globalColormap = createColorMap(&m_globalColormapPalette);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The following "if" block is intended to address cases where
|
||||||
|
// the Color Mode of the animation is RGB and can be represented by
|
||||||
|
// an absolute palette because it contains fewer than 256 colors
|
||||||
|
// throughout the entire animation. In this way the memory space
|
||||||
|
// used to generate the GIF is much more efficient, since local
|
||||||
|
// palettes don't need to be inserted in each frame. It also
|
||||||
|
// fixes a display issue with GIF files (generated by
|
||||||
|
// Aseprite 1.3.13) on Discord when the GIF parameters were:
|
||||||
|
// - disposal = DO_NOT_DISPOSE = 1
|
||||||
|
// - Local palettes exist.
|
||||||
|
if (m_spec.colorMode() == ColorMode::RGB || m_spec.colorMode() == ColorMode::GRAYSCALE) {
|
||||||
|
Palette newPalette(0, 512);
|
||||||
|
render::create_palette_from_sprite(m_sprite,
|
||||||
|
0,
|
||||||
|
totalFrames() - 1,
|
||||||
|
false,
|
||||||
|
&newPalette,
|
||||||
|
nullptr,
|
||||||
|
m_fop->newBlend(),
|
||||||
|
RgbMapAlgorithm::OCTREE,
|
||||||
|
false); // No effect on OctreeMap.
|
||||||
|
// Case: palette with (256 colors + mask color) == 257 but
|
||||||
|
// the mask color isn't used in the sprite.
|
||||||
|
if (newPalette.size() == 257 && !m_sprite->isColorUsed(0)) {
|
||||||
|
// Forcing GIF with background
|
||||||
|
m_transparentIndex = -1;
|
||||||
|
m_hasBackground = true;
|
||||||
|
// Discard the mask color (palette entry = 0)
|
||||||
|
for (int i = 0; i < 256; i++)
|
||||||
|
newPalette.setEntry(i, newPalette.getEntry(i + 1));
|
||||||
|
newPalette.resize(256);
|
||||||
|
m_globalColormapPalette = newPalette;
|
||||||
|
m_globalColormap = createColorMap(&m_globalColormapPalette);
|
||||||
|
}
|
||||||
|
else if (newPalette.size() <= 256) {
|
||||||
m_transparentIndex = 0;
|
m_transparentIndex = 0;
|
||||||
m_globalColormapPalette = newPalette;
|
m_globalColormapPalette = newPalette;
|
||||||
m_globalColormap = createColorMap(&m_globalColormapPalette);
|
m_globalColormap = createColorMap(&m_globalColormapPalette);
|
||||||
|
@ -1388,15 +1428,18 @@ private:
|
||||||
|
|
||||||
if (!m_preservePaletteOrder) {
|
if (!m_preservePaletteOrder) {
|
||||||
const LockImageBits<RgbTraits> srcBits(m_deltaImage.get());
|
const LockImageBits<RgbTraits> srcBits(m_deltaImage.get());
|
||||||
|
const LockImageBits<RgbTraits> preBits(m_previousImage, frameBounds);
|
||||||
LockImageBits<IndexedTraits> dstBits(frameImage.get());
|
LockImageBits<IndexedTraits> dstBits(frameImage.get());
|
||||||
|
|
||||||
auto srcIt = srcBits.begin();
|
auto srcIt = srcBits.begin();
|
||||||
auto dstIt = dstBits.begin();
|
auto dstIt = dstBits.begin();
|
||||||
|
auto preIt = preBits.begin();
|
||||||
|
|
||||||
for (int y = 0; y < frameBounds.h; ++y) {
|
for (int y = 0; y < frameBounds.h; ++y) {
|
||||||
for (int x = 0; x < frameBounds.w; ++x, ++srcIt, ++dstIt) {
|
for (int x = 0; x < frameBounds.w; ++x, ++srcIt, ++dstIt, ++preIt) {
|
||||||
ASSERT(srcIt != srcBits.end());
|
ASSERT(srcIt != srcBits.end());
|
||||||
ASSERT(dstIt != dstBits.end());
|
ASSERT(dstIt != dstBits.end());
|
||||||
|
ASSERT(preIt != preBits.end());
|
||||||
|
|
||||||
color_t color = *srcIt;
|
color_t color = *srcIt;
|
||||||
int i;
|
int i;
|
||||||
|
@ -1410,9 +1453,19 @@ private:
|
||||||
if (i < 0)
|
if (i < 0)
|
||||||
i = octree.mapColor(color | rgba_a_mask); // alpha=255
|
i = octree.mapColor(color | rgba_a_mask); // alpha=255
|
||||||
}
|
}
|
||||||
|
// If the alpha in a pixel from m_deltaImage is < 128, the
|
||||||
|
// pixel is assumed to be 0. Then it should draw the pixel
|
||||||
|
// according defined m_transparentIndex or disposal method
|
||||||
else {
|
else {
|
||||||
if (m_transparentIndex >= 0)
|
if (m_transparentIndex >= 0)
|
||||||
i = m_transparentIndex;
|
i = m_transparentIndex;
|
||||||
|
else if (disposal == DisposalMethod::DO_NOT_DISPOSE) {
|
||||||
|
i = framePalette.findExactMatch(rgba_getr(*preIt),
|
||||||
|
rgba_getg(*preIt),
|
||||||
|
rgba_getb(*preIt),
|
||||||
|
255,
|
||||||
|
-1);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
i = m_bgIndex;
|
i = m_bgIndex;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Aseprite Document Library
|
// Aseprite Document Library
|
||||||
// Copyright (c) 2018-2023 Igara Studio S.A.
|
// Copyright (c) 2018-2025 Igara Studio S.A.
|
||||||
// Copyright (c) 2001-2016 David Capello
|
// Copyright (c) 2001-2016 David Capello
|
||||||
//
|
//
|
||||||
// This file is released under the terms of the MIT license.
|
// This file is released under the terms of the MIT license.
|
||||||
|
@ -352,6 +352,18 @@ bool is_plain_image_templ(const Image* img, const color_t color)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename ImageTraits>
|
||||||
|
bool is_color_used_templ(const Image* img, const doc::color_t color)
|
||||||
|
{
|
||||||
|
const LockImageBits<ImageTraits> bits(img);
|
||||||
|
auto it = bits.begin(), end = bits.end();
|
||||||
|
for (; it != end; ++it) {
|
||||||
|
if (*it == color)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename ImageTraits>
|
template<typename ImageTraits>
|
||||||
int count_diff_between_images_templ(const Image* i1, const Image* i2)
|
int count_diff_between_images_templ(const Image* i1, const Image* i2)
|
||||||
{
|
{
|
||||||
|
@ -464,6 +476,16 @@ bool is_plain_image(const Image* img, color_t c)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_color_used(const Image* img, color_t c)
|
||||||
|
{
|
||||||
|
ASSERT(img->pixelFormat() == IMAGE_RGB || img->pixelFormat() == IMAGE_GRAYSCALE);
|
||||||
|
switch (img->pixelFormat()) {
|
||||||
|
case IMAGE_RGB: return is_color_used_templ<RgbTraits>(img, c);
|
||||||
|
case IMAGE_GRAYSCALE: return is_color_used_templ<GrayscaleTraits>(img, c);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool is_empty_image(const Image* img)
|
bool is_empty_image(const Image* img)
|
||||||
{
|
{
|
||||||
color_t c = 0; // alpha = 0
|
color_t c = 0; // alpha = 0
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Aseprite Document Library
|
// Aseprite Document Library
|
||||||
// Copyright (c) 2018-2023 Igara Studio S.A.
|
// Copyright (c) 2018-2025 Igara Studio S.A.
|
||||||
// Copyright (c) 2001-2016 David Capello
|
// Copyright (c) 2001-2016 David Capello
|
||||||
//
|
//
|
||||||
// This file is released under the terms of the MIT license.
|
// This file is released under the terms of the MIT license.
|
||||||
|
@ -65,6 +65,7 @@ void fill_ellipse(Image* image,
|
||||||
color_t color);
|
color_t color);
|
||||||
|
|
||||||
bool is_plain_image(const Image* img, color_t c);
|
bool is_plain_image(const Image* img, color_t c);
|
||||||
|
bool is_color_used(const Image* img, color_t c);
|
||||||
bool is_empty_image(const Image* img);
|
bool is_empty_image(const Image* img);
|
||||||
|
|
||||||
int count_diff_between_images(const Image* i1, const Image* i2);
|
int count_diff_between_images(const Image* i1, const Image* i2);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Aseprite Document Library
|
// Aseprite Document Library
|
||||||
// Copyright (C) 2018-2024 Igara Studio S.A.
|
// Copyright (C) 2018-2025 Igara Studio S.A.
|
||||||
// Copyright (C) 2001-2018 David Capello
|
// Copyright (C) 2001-2018 David Capello
|
||||||
//
|
//
|
||||||
// This file is released under the terms of the MIT license.
|
// This file is released under the terms of the MIT license.
|
||||||
|
@ -223,6 +223,18 @@ bool Sprite::isOpaque() const
|
||||||
return (bg && bg->isVisible());
|
return (bg && bg->isVisible());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Sprite::isColorUsed(const doc::color_t c) const
|
||||||
|
{
|
||||||
|
ASSERT(pixelFormat() == IMAGE_RGB || pixelFormat() == IMAGE_GRAYSCALE);
|
||||||
|
for (Cel* cel : cels()) {
|
||||||
|
if (cel && cel->image()) {
|
||||||
|
if (is_color_used(cel->image(), c))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool Sprite::needAlpha() const
|
bool Sprite::needAlpha() const
|
||||||
{
|
{
|
||||||
switch (pixelFormat()) {
|
switch (pixelFormat()) {
|
||||||
|
|
|
@ -110,6 +110,9 @@ public:
|
||||||
// Returns true if the sprite has a background layer and it's visible
|
// Returns true if the sprite has a background layer and it's visible
|
||||||
bool isOpaque() const;
|
bool isOpaque() const;
|
||||||
|
|
||||||
|
// Returns true if the sprite is using a pixel with color c
|
||||||
|
bool isColorUsed(const doc::color_t c) const;
|
||||||
|
|
||||||
// Returns true if the rendered images will contain alpha values less
|
// Returns true if the rendered images will contain alpha values less
|
||||||
// than 255. Only RGBA and Grayscale images without background needs
|
// than 255. Only RGBA and Grayscale images without background needs
|
||||||
// alpha channel in the render.
|
// alpha channel in the render.
|
||||||
|
|
Loading…
Reference in New Issue