1// Aseprite FLIC Library
2// Copyright (c) 2015 David Capello
3//
4// This file is released under the terms of the MIT license.
5// Read LICENSE.txt for more information.
6
7#ifndef FLIC_FLIC_H_INCLUDED
8#define FLIC_FLIC_H_INCLUDED
9#pragma once
10
11#include <stdint.h>
12
13#include <cassert>
14#include <cstdio>
15#include <vector>
16
17namespace flic {
18
19 struct Color {
20 uint8_t r, g, b;
21
22 Color() : r(0), g(0), b(0) {
23 }
24
25 Color(uint8_t r, uint8_t g, uint8_t b) : r(r), g(g), b(b) {
26 }
27
28 bool operator==(const Color& o) const {
29 return r == o.r && g == o.g && b == o.b;
30 }
31
32 bool operator!=(const Color& o) const {
33 return !operator==(o);
34 }
35 };
36
37 struct Header {
38 int frames;
39 int width;
40 int height;
41 int speed;
42 };
43
44 class Colormap {
45 public:
46 static const int SIZE = 256;
47
48 Colormap() {
49 }
50
51 int size() const {
52 return SIZE;
53 }
54
55 const Color& operator[](int i) const {
56 assert(i >= 0 && i < SIZE);
57 return m_color[i];
58 }
59
60 Color& operator[](int i) {
61 assert(i >= 0 && i < SIZE);
62 return m_color[i];
63 }
64
65 bool operator==(const Colormap& o) const {
66 for (int i=0; i<SIZE; ++i) {
67 if (m_color[i] != o[i])
68 return false;
69 }
70 return true;
71 }
72
73 bool operator!=(const Colormap& o) const {
74 return !operator==(o);
75 }
76
77 private:
78 Color m_color[SIZE];
79 };
80
81 struct Frame {
82 uint8_t* pixels;
83 uint32_t rowstride;
84 Colormap colormap;
85 };
86
87 class FileInterface {
88 public:
89 virtual ~FileInterface() { }
90
91 // Returns true if we can read/write bytes from/into the file
92 virtual bool ok() const = 0;
93
94 // Current position in the file
95 virtual size_t tell() = 0;
96
97 // Jump to the given position in the file
98 virtual void seek(size_t absPos) = 0;
99
100 // Returns the next byte in the file or 0 if ok() = false
101 virtual uint8_t read8() = 0;
102
103 // Writes one byte in the file (or do nothing if ok() = false)
104 virtual void write8(uint8_t value) = 0;
105 };
106
107 class StdioFileInterface : public flic::FileInterface {
108 public:
109 StdioFileInterface(FILE* file);
110 bool ok() const override;
111 size_t tell() override;
112 void seek(size_t absPos) override;
113 uint8_t read8() override;
114 void write8(uint8_t value) override;
115
116 private:
117 FILE* m_file;
118 bool m_ok;
119 };
120
121 class Decoder {
122 public:
123 Decoder(FileInterface* file);
124 bool readHeader(Header& header);
125 bool readFrame(Frame& frame);
126
127 private:
128 void readChunk(Frame& frame);
129 void readBlackChunk(Frame& frame);
130 void readCopyChunk(Frame& frame);
131 void readColorChunk(Frame& frame, bool oldColorChunk);
132 void readBrunChunk(Frame& frame);
133 void readLcChunk(Frame& frame);
134 void readDeltaChunk(Frame& frame);
135 uint16_t read16();
136 uint32_t read32();
137
138 FileInterface* m_file;
139 int m_width, m_height;
140 int m_frameCount;
141 int m_offsetFrame1;
142 int m_offsetFrame2;
143 };
144
145 class Encoder {
146 public:
147 Encoder(FileInterface* file);
148 ~Encoder();
149
150 void writeHeader(const Header& header);
151 void writeFrame(const Frame& frame);
152
153 // Must be called at the end with the first frame. It's required
154 // by Animator Pro to loop the animation from the last frame to
155 // the first one.
156 void writeRingFrame(const Frame& frame);
157
158 private:
159 void writeColorChunk(const Frame& frame);
160 void writeBrunChunk(const Frame& frame);
161 void writeBrunLineChunk(const Frame& frame, int y);
162 void writeLcChunk(const Frame& frame);
163 void writeLcLineChunk(const Frame& frame, int y);
164 void write16(uint16_t value);
165 void write32(uint32_t value);
166
167 FileInterface* m_file;
168 int m_width, m_height;
169 Colormap m_prevColormap;
170 std::vector<uint8_t> m_prevFrameData;
171 int m_frameCount;
172 int m_offsetFrame1;
173 int m_offsetFrame2;
174 };
175
176} // namespace flic
177
178#endif
179