1 /*****************************************************************************/
5 /* GEOS compacted bitmap backend for the sp65 sprite and bitmap utility */
9 /* (C) 2012, Ullrich von Bassewitz */
10 /* Roemerstrasse 52 */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
15 /* This software is provided 'as-is', without any expressed or implied */
16 /* warranty. In no event will the authors be held liable for any damages */
17 /* arising from the use of this software. */
19 /* Permission is granted to anyone to use this software for any purpose, */
20 /* including commercial applications, and to alter it and redistribute it */
21 /* freely, subject to the following restrictions: */
23 /* 1. The origin of this software must not be misrepresented; you must not */
24 /* claim that you wrote the original software. If you use this software */
25 /* in a product, an acknowledgment in the product documentation would be */
26 /* appreciated but is not required. */
27 /* 2. Altered source versions must be plainly marked as such, and must not */
28 /* be misrepresented as being the original software. */
29 /* 3. This notice may not be removed or altered from any source */
32 /*****************************************************************************/
44 #include "geosbitmap.h"
48 /*****************************************************************************/
50 /*****************************************************************************/
54 #define UNIQUE_MAX 91U /* Maximum number of unique bytes */
55 #define REPEAT_MAX 127U /* Maximum number of repeated bytes */
59 /* Structure used for RLE compression */
61 unsigned char* Buf; /* Pointer to pixel buffer */
62 unsigned Remaining; /* Remaining bytes in buffer */
63 unsigned char LastVal; /* Last value seen */
64 unsigned Count; /* Number of occurrences for LastVal */
65 StrBuf* D; /* Buffer for compressed data */
66 StrBuf UniqueData; /* Temp buffer for unique data */
71 /*****************************************************************************/
73 /*****************************************************************************/
77 static void StoreByte (struct RLE* RLE)
78 /* Store a unique byte or a run of repeated bytes. If count is zero, the
79 * function will flush the internal buffers, so that all data is in RLE->D.
84 if (RLE->Count == 1 || RLE->Count == 2) {
85 /* A run of two identical bytes is treated as two unique bytes, since
86 * this will usually merge with the following run.
88 SB_AppendChar (&RLE->UniqueData, RLE->LastVal);
89 if (RLE->Count == 2) {
90 SB_AppendChar (&RLE->UniqueData, RLE->LastVal);
93 /* Clear the repeat counter */
98 /* Run of repeated bytes. First flush the temp buffer for unique
101 const char* Buf = SB_GetConstBuf (&RLE->UniqueData);
102 unsigned Count = SB_GetLen (&RLE->UniqueData);
105 /* Determine the count for this sequence */
106 unsigned Chunk = Count;
107 if (Chunk > UNIQUE_MAX) {
111 /* Output the unique op */
112 SB_AppendChar (RLE->D, 0x80 + (unsigned char) Chunk);
113 SB_AppendBuf (RLE->D, Buf, Chunk);
115 /* Bump the counters */
120 /* Clear the unique byte buffer */
121 SB_Clear (&RLE->UniqueData);
123 /* Now output the repeat sequence */
126 /* Determine the count for this sequence */
127 unsigned Chunk = RLE->Count;
128 if (Chunk > REPEAT_MAX) {
131 /* Output the repeat op */
132 SB_AppendChar (RLE->D, (unsigned char) Chunk);
133 SB_AppendChar (RLE->D, RLE->LastVal);
135 /* Bump the counters */
143 StrBuf* GenGeosBitmap (const Bitmap* B, const Collection* A attribute ((unused)))
144 /* Generate binary output in GEOS compacted bitmap format for the bitmap B.
145 * The output is stored in a string buffer (which is actually a dynamic char
146 * array) and returned.
157 /* Output the image properties */
158 Print (stdout, 1, "Image is %ux%u with %u colors%s\n",
159 GetBitmapWidth (B), GetBitmapHeight (B), GetBitmapColors (B),
160 BitmapIsIndexed (B)? " (indexed)" : "");
162 /* Check the bitmap properties */
163 if (!BitmapIsIndexed (B) || GetBitmapColors (B) > 2) {
164 Error ("Bitmaps converted to GEOS compacted bitmap must be "
165 "indexed with two colors");
168 /* Calculate the width of one line in bytes */
169 LineWidth = (GetBitmapWidth (B) + 7U) / 8U;
171 /* Allocate a buffer for the raw image */
172 Buf = xmalloc (LineWidth * GetBitmapHeight (B));
174 /* Convert the bitmap into a raw image */
176 for (Y = 0; Y < GetBitmapHeight (B); ++Y) {
177 for (X = 0; X < GetBitmapWidth (B); ) {
180 if ((unsigned)Bits > GetBitmapWidth (B) - X) {
181 Bits = (GetBitmapWidth (B) - X);
183 while (--Bits >= 0) {
184 V |= (GetPixel (B, X++, Y).Index & 0x01) << Bits;
190 /* Create the output buffer and resize it to something reasonable */
194 /* Compact the image. We're currently using only REPEAT and UNIQUE opcodes.
195 * BIGCOUNT is rather difficult to apply.
198 RLE.Remaining = LineWidth * GetBitmapHeight (B) - 1;
199 RLE.LastVal = *RLE.Buf++;
202 RLE.UniqueData = EmptyStrBuf;
203 while (RLE.Remaining--) {
205 if (RLE.LastVal == *RLE.Buf) {
210 RLE.LastVal = *RLE.Buf++;
215 /* If something remains, store it */
220 /* Flush the unique byte buffer */
223 /* Release the unique byte buffer */
224 SB_Done (&RLE.UniqueData);
226 /* Free the raw image buffer */
229 /* Return the converted bitmap */