Add support for 8-bit png files with alpha channel

This commit is contained in:
David Capello 2015-06-30 18:08:14 -03:00
parent 6796e9f9be
commit 8f62baedb3
3 changed files with 48 additions and 34 deletions

View File

@ -776,6 +776,25 @@ void fop_sequence_get_color(FileOp *fop, int index, int *r, int *g, int *b)
*b = rgba_getb(c); *b = rgba_getb(c);
} }
void fop_sequence_set_alpha(FileOp* fop, int index, int a)
{
int c = fop->seq.palette->getEntry(index);
int r = rgba_getr(c);
int g = rgba_getg(c);
int b = rgba_getb(c);
fop->seq.palette->setEntry(index, rgba(r, g, b, a));
}
void fop_sequence_get_alpha(FileOp* fop, int index, int* a)
{
ASSERT(index >= 0);
if (index >= 0 && index < fop->seq.palette->size())
*a = rgba_geta(fop->seq.palette->getEntry(index));
else
*a = 0;
}
Image* fop_sequence_image(FileOp* fop, PixelFormat pixelFormat, int w, int h) Image* fop_sequence_image(FileOp* fop, PixelFormat pixelFormat, int w, int h)
{ {
Sprite* sprite; Sprite* sprite;

View File

@ -135,6 +135,8 @@ namespace app {
void fop_sequence_set_format_options(FileOp* fop, const base::SharedPtr<FormatOptions>& format_options); void fop_sequence_set_format_options(FileOp* fop, const base::SharedPtr<FormatOptions>& format_options);
void fop_sequence_set_color(FileOp* fop, int index, int r, int g, int b); void fop_sequence_set_color(FileOp* fop, int index, int r, int g, int b);
void fop_sequence_get_color(FileOp* fop, int index, int *r, int *g, int *b); void fop_sequence_get_color(FileOp* fop, int index, int *r, int *g, int *b);
void fop_sequence_set_alpha(FileOp* fop, int index, int a);
void fop_sequence_get_alpha(FileOp* fop, int index, int* a);
Image* fop_sequence_image(FileOp* fi, PixelFormat pixelFormat, int w, int h); Image* fop_sequence_image(FileOp* fi, PixelFormat pixelFormat, int w, int h);
void fop_error(FileOp* fop, const char *error, ...); void fop_error(FileOp* fop, const char *error, ...);

View File

@ -39,7 +39,8 @@ class PngFormat : public FileFormat {
FILE_SUPPORT_GRAY | FILE_SUPPORT_GRAY |
FILE_SUPPORT_GRAYA | FILE_SUPPORT_GRAYA |
FILE_SUPPORT_INDEXED | FILE_SUPPORT_INDEXED |
FILE_SUPPORT_SEQUENCES; FILE_SUPPORT_SEQUENCES |
FILE_SUPPORT_PALETTE_WITH_ALPHA;
} }
bool onLoad(FileOp* fop) override; bool onLoad(FileOp* fop) override;
@ -184,10 +185,6 @@ bool PngFormat::onLoad(FileOp* fop)
return false; return false;
} }
// Transparent palette entries
std::vector<uint8_t> pal_alphas(256, 255);
int mask_entry = -1;
// Read the palette // Read the palette
if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_PALETTE && if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_PALETTE &&
png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette)) { png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette)) {
@ -206,17 +203,19 @@ bool PngFormat::onLoad(FileOp* fop)
// Read alpha values for palette entries // Read alpha values for palette entries
png_bytep trans = NULL; // Transparent palette entries png_bytep trans = NULL; // Transparent palette entries
int num_trans = 0; int num_trans = 0;
int mask_entry = -1;
png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL); png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL);
for (int i = 0; i < num_trans; ++i) { for (int i = 0; i < num_trans; ++i) {
pal_alphas[i] = trans[i]; fop_sequence_set_alpha(fop, i, trans[i]);
if (pal_alphas[i] < 128) { if (trans[i] < 255) {
fop->seq.has_alpha = true; // Is a transparent sprite fop->seq.has_alpha = true; // Is a transparent sprite
if (trans[i] == 0) {
if (mask_entry < 0) if (mask_entry < 0)
mask_entry = i; mask_entry = i;
}
} }
} }
@ -225,8 +224,6 @@ bool PngFormat::onLoad(FileOp* fop)
fop->document->sprite()->setTransparentColor(mask_entry); fop->document->sprite()->setTransparentColor(mask_entry);
} }
mask_entry = fop->document->sprite()->transparentColor();
/* Allocate the memory to hold the image using the fields of info_ptr. */ /* Allocate the memory to hold the image using the fields of info_ptr. */
/* The easiest way to read the image: */ /* The easiest way to read the image: */
@ -290,18 +287,10 @@ bool PngFormat::onLoad(FileOp* fop)
else if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_PALETTE) { else if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_PALETTE) {
uint8_t* src_address = row_pointer; uint8_t* src_address = row_pointer;
uint8_t* dst_address = (uint8_t*)image->getPixelAddress(0, y); uint8_t* dst_address = (uint8_t*)image->getPixelAddress(0, y);
unsigned int x, c; unsigned int x;
for (x=0; x<width; x++) { for (x=0; x<width; x++)
c = *(src_address++); *(dst_address++) = *(src_address++);
if (pal_alphas[c] < 128) {
*(dst_address++) = mask_entry;
}
else {
*(dst_address++) = c;
}
}
} }
fop_progress(fop, fop_progress(fop,
@ -415,20 +404,24 @@ bool PngFormat::onSave(FileOp* fop)
png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH); png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH);
// If the sprite does not have a (visible) background layer, we // If the sprite does not have a (visible) background layer, we
// include the alpha information of palette entries to indicate // put alpha=0 to the transparent color.
// which is the transparent color. int mask_entry = -1;
if (fop->document->sprite()->backgroundLayer() == NULL || if (fop->document->sprite()->backgroundLayer() == NULL ||
!fop->document->sprite()->backgroundLayer()->isVisible()) { !fop->document->sprite()->backgroundLayer()->isVisible()) {
int mask_entry = fop->document->sprite()->transparentColor(); mask_entry = fop->document->sprite()->transparentColor();
int num_trans = mask_entry+1;
png_bytep trans = (png_bytep)png_malloc(png_ptr, num_trans);
for (c = 0; c < num_trans; ++c)
trans[c] = (c == mask_entry ? 0: 255);
png_set_tRNS(png_ptr, info_ptr, trans, num_trans, NULL);
png_free(png_ptr, trans);
} }
int num_trans = PNG_MAX_PALETTE_LENGTH;
png_bytep trans = (png_bytep)png_malloc(png_ptr, num_trans);
for (c=0; c<num_trans; ++c) {
int alpha = 255;
fop_sequence_get_alpha(fop, c, &alpha);
trans[c] = (c == mask_entry ? 0: alpha);
}
png_set_tRNS(png_ptr, info_ptr, trans, num_trans, NULL);
png_free(png_ptr, trans);
} }
/* Write the file header information. */ /* Write the file header information. */