Fix interoperability problem with layer opacity between v1.0 and v1.1

Saving a file with v1.1, loading it with v1.0, and then loading it back
with v1.1 was generating a layer with flag 32 enabled ("layer has opacity
bit") and opacity = 0 (the opacity was overwritten by v1.0, but the flag
was persisted).

Now the "layers have opacity" bit is saved in the file header. This
flag can be used because v1.0 saves it with value = 0.
This commit is contained in:
David Capello 2015-07-07 12:58:05 -03:00
parent 98297de464
commit 65045c0e2c
2 changed files with 44 additions and 34 deletions

View File

@ -43,7 +43,7 @@ images with zlib. Color palettes are in FLI color chunks (it could be
type=11 or type=4). For color depths more than 8bpp, palettes are
optional. See fli.txt for details.
To read the sprite, just do this:
To read the sprite:
* Read the ASE header (section 3)
* For each frame do (how many frames? the ASE header has that
information):
@ -70,7 +70,8 @@ WORD Color depth (bits per pixel)
32 bpp = RGBA
16 bpp = Grayscale
8 bpp = Indexed
DWORD Flags (must be 0)
DWORD Flags:
1 = Layer opacity has valid value
WORD Speed (milliseconds between frame, like in FLC files)
DEPRECATED: You should use the frame duration
field from each frame header
@ -111,6 +112,10 @@ Then each chunk format is:
Old palette chunk (0x0004)
----------------------------------------
Ignore this chunk if you find the new palette chunk (0x2019) Aseprite
v1.1 saves both chunks 0x0004 and 0x2019 just for backward
compatibility.
WORD Number of packets
+ For each packet
BYTE Number of palette entries to skip from the last packet (start from 0)
@ -124,6 +129,8 @@ Old palette chunk (0x0004)
Old palette chunk (0x0011)
----------------------------------------
Ignore this chunk if you find the new palette chunk (0x2019)
WORD Number of packets
+ For each packet
BYTE Number of palette entries to skip from the last packet (start from 0)
@ -146,7 +153,6 @@ Layer Chunk (0x2004)
4 = Lock movement
8 = Background
16 = Prefer linked cels
32 = Has a valid opacity value
WORD Layer type (0=normal (image) layer, 1=layer set)
WORD Layer child level (see NOTE.1)
WORD Default layer width in pixels (ignored)

View File

@ -21,28 +21,31 @@
#include <stdio.h>
#define ASE_FILE_MAGIC 0xA5E0
#define ASE_FILE_FRAME_MAGIC 0xF1FA
#define ASE_FILE_MAGIC 0xA5E0
#define ASE_FILE_FRAME_MAGIC 0xF1FA
#define ASE_FILE_CHUNK_FLI_COLOR2 4
#define ASE_FILE_CHUNK_FLI_COLOR 11
#define ASE_FILE_CHUNK_LAYER 0x2004
#define ASE_FILE_CHUNK_CEL 0x2005
#define ASE_FILE_CHUNK_MASK 0x2016
#define ASE_FILE_CHUNK_PATH 0x2017
#define ASE_FILE_CHUNK_FRAME_TAGS 0x2018
#define ASE_FILE_CHUNK_PALETTE 0x2019
#define ASE_FILE_FLAG_LAYER_WITH_OPACITY 1
#define ASE_FILE_RAW_CEL 0
#define ASE_FILE_LINK_CEL 1
#define ASE_FILE_COMPRESSED_CEL 2
#define ASE_FILE_CHUNK_FLI_COLOR2 4
#define ASE_FILE_CHUNK_FLI_COLOR 11
#define ASE_FILE_CHUNK_LAYER 0x2004
#define ASE_FILE_CHUNK_CEL 0x2005
#define ASE_FILE_CHUNK_MASK 0x2016
#define ASE_FILE_CHUNK_PATH 0x2017
#define ASE_FILE_CHUNK_FRAME_TAGS 0x2018
#define ASE_FILE_CHUNK_PALETTE 0x2019
#define ASE_FILE_RAW_CEL 0
#define ASE_FILE_LINK_CEL 1
#define ASE_FILE_COMPRESSED_CEL 2
#define ASE_LAYER_FLAG_VISIBLE 1
#define ASE_LAYER_FLAG_EDITABLE 2
#define ASE_LAYER_FLAG_LOCK_MOVEMENT 4
#define ASE_LAYER_FLAG_BACKGROUND 8
#define ASE_LAYER_FLAG_PREFER_LINKED_CELS 16
#define ASE_LAYER_FLAG_HAS_OPACITY 32
#define ASE_PALETTE_FLAG_HAS_NAME 1
namespace app {
@ -103,7 +106,7 @@ static Palette* ase_file_read_color2_chunk(FILE* f, Palette* prevPal, frame_t fr
static Palette* ase_file_read_palette_chunk(FILE* f, Palette* prevPal, frame_t frame);
static void ase_file_write_color2_chunk(FILE* f, ASE_FrameHeader* frame_header, Palette* pal);
static void ase_file_write_palette_chunk(FILE* f, ASE_FrameHeader* frame_header, Palette* pal, int from, int to);
static Layer* ase_file_read_layer_chunk(FILE* f, Sprite* sprite, Layer** previous_layer, int* current_level);
static Layer* ase_file_read_layer_chunk(FILE* f, ASE_Header* header, Sprite* sprite, Layer** previous_layer, int* current_level);
static void ase_file_write_layer_chunk(FILE* f, ASE_FrameHeader* frame_header, Layer* layer);
static Cel* ase_file_read_cel_chunk(FILE* f, Sprite* sprite, frame_t frame, PixelFormat pixelFormat, FileOp* fop, ASE_Header* header, size_t chunk_end);
static void ase_file_write_cel_chunk(FILE* f, ASE_FrameHeader* frame_header, Cel* cel, LayerImage* layer, Sprite* sprite);
@ -188,13 +191,13 @@ bool AseFormat::onLoad(FileOp* fop)
Layer* last_layer = sprite->folder();
int current_level = -1;
/* read frame by frame to end-of-file */
// Read frame by frame to end-of-file
for (frame_t frame(0); frame<sprite->totalFrames(); ++frame) {
/* start frame position */
// Start frame position
int frame_pos = ftell(f);
fop_progress(fop, (float)frame_pos / (float)header.size);
/* read frame header */
// Read frame header
ASE_FrameHeader frame_header;
ase_file_read_frame_header(f, &frame_header);
@ -243,7 +246,7 @@ bool AseFormat::onLoad(FileOp* fop)
case ASE_FILE_CHUNK_LAYER: {
/* fop_error(fop, "Layer chunk\n"); */
ase_file_read_layer_chunk(f, sprite,
ase_file_read_layer_chunk(f, &header, sprite,
&last_layer,
&current_level);
break;
@ -285,15 +288,15 @@ bool AseFormat::onLoad(FileOp* fop)
break;
}
/* skip chunk size */
// Skip chunk size
fseek(f, chunk_pos+chunk_size, SEEK_SET);
}
}
/* skip frame size */
// Skip frame size
fseek(f, frame_pos+frame_header.size, SEEK_SET);
/* just one frame? */
// Just one frame?
if (fop->oneframe)
break;
@ -439,7 +442,7 @@ static void ase_file_prepare_header(FILE* f, ASE_Header* header, const Sprite* s
header->depth = (sprite->pixelFormat() == IMAGE_RGB ? 32:
sprite->pixelFormat() == IMAGE_GRAYSCALE ? 16:
sprite->pixelFormat() == IMAGE_INDEXED ? 8: 0);
header->flags = 0;
header->flags = ASE_FILE_FLAG_LAYER_WITH_OPACITY;
header->speed = sprite->frameDuration(frame_t(0));
header->next = 0;
header->frit = 0;
@ -688,7 +691,7 @@ static Palette* ase_file_read_palette_chunk(FILE* f, Palette* prevPal, frame_t f
pal->setEntry(c, rgba(r, g, b, a));
// Skip name
if (flags & 1) {
if (flags & ASE_PALETTE_FLAG_HAS_NAME) {
std::string name = ase_file_read_string(f);
// Ignore color entry name
}
@ -734,7 +737,7 @@ static void ase_file_write_palette_chunk(FILE* f, ASE_FrameHeader* frame_header,
}
}
static Layer* ase_file_read_layer_chunk(FILE* f, Sprite* sprite, Layer** previous_layer, int* current_level)
static Layer* ase_file_read_layer_chunk(FILE* f, ASE_Header* header, Sprite* sprite, Layer** previous_layer, int* current_level)
{
std::string name;
Layer* layer = NULL;
@ -757,10 +760,12 @@ static Layer* ase_file_read_layer_chunk(FILE* f, Sprite* sprite, Layer** previou
// Image layer
if (layer_type == 0) {
layer = new LayerImage(sprite);
static_cast<LayerImage*>(layer)->setBlendMode((BlendMode)blendmode);
if (flags & ASE_LAYER_FLAG_HAS_OPACITY) {
flags ^= ASE_LAYER_FLAG_HAS_OPACITY;
static_cast<LayerImage*>(layer)->setOpacity(opacity);
// Only transparent layers can have blend mode and opacity
if (!(flags & ASE_LAYER_FLAG_BACKGROUND)) {
static_cast<LayerImage*>(layer)->setBlendMode((BlendMode)blendmode);
if (header->flags & ASE_FILE_FLAG_LAYER_WITH_OPACITY)
static_cast<LayerImage*>(layer)->setOpacity(opacity);
}
}
// Layer set
@ -795,8 +800,7 @@ static void ase_file_write_layer_chunk(FILE* f, ASE_FrameHeader* frame_header, L
ChunkWriter chunk(f, frame_header, ASE_FILE_CHUNK_LAYER);
// Flags
fputw(static_cast<int>(layer->flags()) |
(layer->isImage() ? ASE_LAYER_FLAG_HAS_OPACITY: 0), f);
fputw(static_cast<int>(layer->flags()), f);
// Layer type
fputw(layer->isImage() ? 0: (layer->isFolder() ? 1: -1), f);