|
| 1 | +Import BRL.Bank |
| 2 | + |
1 | 3 | '//// INDEXED IMAGE WRITER //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
2 | 4 |
|
3 | 5 | Type IndexedImageWriter
|
4 | 6 | Field m_PalR:Byte[256]
|
5 | 7 | Field m_PalG:Byte[256]
|
6 | 8 | Field m_PalB:Byte[256]
|
7 | 9 |
|
| 10 | + Field m_CRCTable:Int[256] |
| 11 | + |
8 | 12 | '////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
9 | 13 |
|
10 | 14 | Method New()
|
11 | 15 | LoadDefaultPalette()
|
| 16 | + |
| 17 | + 'Initialize CRC table |
| 18 | + For Local i:Int = 0 To 255 |
| 19 | + Local value:Int = i |
| 20 | + For Local j:Int = 0 To 7 |
| 21 | + If (value & $1) Then |
| 22 | + value = (value Shr 1) ~ $EDB88320 '~ for XOR |
| 23 | + Else |
| 24 | + value = (value Shr 1) |
| 25 | + EndIf |
| 26 | + Next |
| 27 | + m_CRCTable[i] = value |
| 28 | + Next |
| 29 | + EndMethod |
| 30 | + |
| 31 | +'//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| 32 | + |
| 33 | + Method GenerateCRC32FromBank:Int(bank:TBank) |
| 34 | + Local crcResult:Int = $FFFFFFFF |
| 35 | + For Local i:Int = 0 Until BankSize(bank) |
| 36 | + crcResult = (crcResult Shr 8) ~ m_CRCTable[PeekByte(bank, i) ~ (crcResult & $FF)] |
| 37 | + Next |
| 38 | + Return ~crcResult '~ for bitwise complement |
12 | 39 | EndMethod
|
13 | 40 |
|
14 | 41 | '////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
@@ -126,10 +153,82 @@ Type IndexedImageWriter
|
126 | 153 | Return False
|
127 | 154 | Else
|
128 | 155 | Local pngWidth:Int = sourcePixmap.Width
|
| 156 | + Local pngWidthM4:Int = ((pngWidth + 3) / 4) * 4 'pngWidth adjusted to be divisible by 4. Written file is spaghetti if not adjusted! |
129 | 157 | Local pngHeight:Int = sourcePixmap.Height
|
| 158 | + Local pngSizeTotal:Int = pngWidthM4 * pngHeight 'dimensions (with adjusted width) |
| 159 | + Local pngSizeTotalM4:Int = ((pngSizeTotal + 3) / 4) * 4 'bmpSizeTotal adjusted to be divisible by 4. Written file is spaghetti if not adjusted! |
130 | 160 |
|
131 | 161 | 'Begin writing PNG file manually
|
132 |
| - Local outputStream:TStream = BigEndianStream(WriteFile(filename)) 'PNG file data is stored in network byte order (big-endian, most-significant byte first) |
| 162 | + Local outputStream:TStream = BigEndianStream(WriteFile(filename)) 'PNG file data is stored in network byte order (big-endian) |
| 163 | + |
| 164 | + 'PNG file header |
| 165 | + WriteByte(outputStream, 137) 'Has the high bit set to detect transmission systems that do not support 8-bit data and to reduce the chance that a text file is mistakenly interpreted as a PNG, or vice versa. 89 (hex) (1 byte) |
| 166 | + WriteByte(outputStream, 80) 'File ID (in ASCII, the letters PNG). 50 4E 47 (hex) (3 bytes) |
| 167 | + WriteByte(outputStream, 78) |
| 168 | + WriteByte(outputStream, 71) |
| 169 | + WriteShort(outputStream, 3338) 'A DOS-style line ending (CRLF) to detect DOS-Unix line ending conversion of the data. 0D 0A (hex) (2 bytes) |
| 170 | + WriteByte(outputStream, 26) 'A byte that stops display of the file under DOS when the command type has been used—the end-of-file character. 1A (hex) (1 byte) |
| 171 | + WriteByte(outputStream, 10) 'A Unix-style line ending (LF) to detect Unix-DOS line ending conversion. 0A (hex) (1 byte) |
| 172 | + |
| 173 | + 'IHDR chunk (file properties) |
| 174 | + WriteInt(outputStream, 13) 'Chunk Length (4 bytes) - 13 bytes for IHDR |
| 175 | + WriteInt(outputStream, 1229472850) 'Chunk Type (4 bytes) - 1229472850 (decimal) or 49 48 44 52 (hex) or IHDR (ascii) |
| 176 | + |
| 177 | + WriteInt(outputStream, pngWidth) 'Image Width (4 bytes) |
| 178 | + WriteInt(outputStream, pngHeight) 'Image Height (4 bytes) |
| 179 | + WriteByte(outputStream, 4) 'Bit Depth (1 byte) - BYTES per pixel not BITS per pixel |
| 180 | + WriteByte(outputStream, 3) 'Color Type (1 byte) - 3 for indexed color |
| 181 | + WriteByte(outputStream, 0) 'Compression Method (1 byte) |
| 182 | + WriteByte(outputStream, 0) 'Filter Method (1 byte) |
| 183 | + WriteByte(outputStream, 0) 'Interlace Method (1 byte) - 0 for no interlace |
| 184 | + |
| 185 | + Rem |
| 186 | + Figure out how to generate correct CRC |
| 187 | + EndRem |
| 188 | + WriteInt(outputStream, 0) 'CRC-32 checksum (4 bytes) |
| 189 | + |
| 190 | + 'PLTE chunk (color table) |
| 191 | + WriteInt(outputStream, 768) 'Chunk Length (4 bytes) - 4 bytes (ARGB) times the amount of colors in the palette = 1024 bytes |
| 192 | + WriteInt(outputStream, 1347179589) 'Chunk Type (4 bytes) - 1347179589 (decimal) or 50 4C 54 45 (hex) or PLTE (ascii) |
| 193 | + |
| 194 | + For Local index:Int = 0 To 255 |
| 195 | + WriteByte(outputStream, m_PalB[index]) 'Blue (1 byte) |
| 196 | + WriteByte(outputStream, m_PalG[index]) 'Green (1 byte) |
| 197 | + WriteByte(outputStream, m_PalR[index]) 'Red (1 byte) |
| 198 | + Next |
| 199 | + |
| 200 | + Rem |
| 201 | + Figure out how to generate correct CRC |
| 202 | + EndRem |
| 203 | + WriteInt(outputStream, 0) 'CRC-32 checksum (4 bytes) |
| 204 | + |
| 205 | + 'IDAT chunk (pixel array) |
| 206 | + WriteInt(outputStream, pngSizeTotal) 'Chunk Length (4 bytes) - width times height of the image + padding |
| 207 | + WriteInt(outputStream, 1229209940) 'Chunk Type (4 bytes) - 1229209940 (decimal) or 49 44 41 54 (hex) or IDAT (ascii) |
| 208 | + |
| 209 | + For Local pixelY:Int = pngHeight - 1 To 0 Step -1 |
| 210 | + For Local pixelX:Int = 0 Until pngWidth |
| 211 | + If pixelX < pngWidth Then |
| 212 | + WriteByte(outputStream, ConvertColorToClosestIndex(ReadPixel(sourcePixmap, pixelX, pixelY))) |
| 213 | + 'Else |
| 214 | + ' WriteByte(outputStream, 0) 'Line padding |
| 215 | + EndIf |
| 216 | + Next |
| 217 | + Next |
| 218 | + |
| 219 | + Rem |
| 220 | + Figure out how to generate correct CRC |
| 221 | + EndRem |
| 222 | + WriteInt(outputStream, 0) 'CRC-32 checksum (4 bytes) |
| 223 | + |
| 224 | + 'IEND chunk (EOF) |
| 225 | + WriteInt(outputStream, 0) 'Chunk Length (4 bytes) - 0 for IEND |
| 226 | + WriteInt(outputStream, 1229278788) 'Chunk Type (4 bytes) - 1229278788 (decimal) or 49 45 4E 44 (hex) or IEND (ascii) |
| 227 | + |
| 228 | + Rem |
| 229 | + Figure out how to generate correct CRC |
| 230 | + EndRem |
| 231 | + WriteInt(outputStream, 0) 'CRC-32 checksum (4 bytes) |
133 | 232 |
|
134 | 233 | CloseStream(outputStream)
|
135 | 234 | Return True
|
|
0 commit comments