Skip to content

Commit 062e3c2

Browse files
committed
Saving indexed png fully functional
1 parent 0e84ca8 commit 062e3c2

File tree

5 files changed

+110
-57
lines changed

5 files changed

+110
-57
lines changed

types/FileIO.bmx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,13 @@ Type FileIO
5454

5555
Method SetSaveAsIndexed(indexedOrNot:Int)
5656
m_SaveAsIndexed = indexedOrNot
57+
Rem
5758
If m_SaveAsIndexed Then
5859
m_FileFilters = "Image Files:bmp"
5960
Else
6061
m_FileFilters = "Image Files:png"
6162
EndIf
63+
EndRem
6264
EndMethod
6365

6466
'////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -68,8 +70,8 @@ Type FileIO
6870
If CheckValidExportFileName(filename) Then
6971
Local saveSuccess:Int = True
7072
If m_SaveAsIndexed Then
71-
saveSuccess = m_IndexedImageWriter.WriteIndexedBitmapFromPixmap(pixmapToSave, filename)
72-
'saveSuccess = m_IndexedImageWriter.WriteIndexedPNGFromPixmap(pixmapToSave, filename)
73+
'saveSuccess = m_IndexedImageWriter.WriteIndexedBitmapFromPixmap(pixmapToSave, filename)
74+
saveSuccess = m_IndexedImageWriter.WriteIndexedPNGFromPixmap(pixmapToSave, filename)
7375
Else
7476
saveSuccess = SavePixmapPNG(pixmapToSave, filename)
7577
EndIf
@@ -107,8 +109,8 @@ Type FileIO
107109

108110
Local saveSuccess:Int = True
109111
If m_SaveAsIndexed Then
110-
saveSuccess = m_IndexedImageWriter.WriteIndexedBitmapFromPixmap(pixmapToSave[row, frame], fullFilename + ".bmp")
111-
'saveSuccess = m_IndexedImageWriter.WriteIndexedPNGFromPixmap(pixmapToSave[row, frame], fullFilename + ".png")
112+
'saveSuccess = m_IndexedImageWriter.WriteIndexedBitmapFromPixmap(pixmapToSave[row, frame], fullFilename + ".bmp")
113+
saveSuccess = m_IndexedImageWriter.WriteIndexedPNGFromPixmap(pixmapToSave[row, frame], fullFilename + ".png")
112114
Else
113115
saveSuccess = SavePixmapPNG(pixmapToSave[row, frame], fullFilename + ".png")
114116
EndIf

types/IndexedImageWriter.bmx

Lines changed: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
Import "Utility.bmx"
2-
Import "UtilityPNG.bmx"
2+
Import "IndexedPixmap.bmx"
33

44
'//// INDEXED IMAGE WRITER //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
55

@@ -246,40 +246,47 @@ EndRem
246246
'////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
247247

248248
Method WriteIndexedPNGFromPixmap:Int(sourcePixmap:TPixmap, filename:String, compression:Int = 5)
249-
Local outputStream:TStream = WriteStream(filename)
249+
If filename = Null Then
250+
Return False
251+
Else
252+
'Begin writing PNG file manually
253+
Local outputStream:TStream = WriteStream(filename)
250254

251-
Try
252-
Local pngPtr:Byte Ptr = png_create_write_struct("1.6.37", Null, Null, Null)
253-
Local pngInfoPtr:Byte Ptr = png_create_info_struct(pngPtr)
255+
Try
256+
Local pngPtr:Byte Ptr = png_create_write_struct("1.6.37", Null, Null, Null)
257+
Local pngInfoPtr:Byte Ptr = png_create_info_struct(pngPtr)
254258

255-
png_set_write_fn(pngPtr, outputStream, UtilityPNG.PNGWrite, UtilityPNG.PNGFlush)
259+
png_set_write_fn(pngPtr, outputStream, Utility.PNGWriteStream, Utility.PNGFlushStream)
256260

257-
png_set_compression_level(pngPtr, Utility.Clamp(compression, 0, 9))
258-
png_set_IHDR(pngPtr, pngInfoPtr, sourcePixmap.Width, sourcePixmap.Height, 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT)
261+
png_set_compression_level(pngPtr, Utility.Clamp(compression, 0, 9))
262+
png_set_IHDR(pngPtr, pngInfoPtr, sourcePixmap.Width, sourcePixmap.Height, 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT)
259263

260-
Local palettePtr:Byte Ptr = m_Palette
261-
png_set_PLTE(pngPtr, pngInfoPtr, palettePtr, 256);
264+
Local palettePtr:Byte Ptr = m_Palette
265+
png_set_PLTE(pngPtr, pngInfoPtr, palettePtr, 256);
262266

263-
'sourcePixmap = sourcePixmap.Convert(PF_I8)
264-
For Local pixelY:Int = 0 Until sourcePixmap.Height
265-
For Local pixelX:Int = 0 Until sourcePixmap.Width
266-
WritePixel(sourcePixmap, pixelX, pixelY, ConvertColorToClosestIndex(ReadPixel(sourcePixmap, pixelX, pixelY)))
267+
Local convertingPixmap:IndexedPixmap = New IndexedPixmap(sourcePixmap.Width, sourcePixmap.Height)
268+
For Local pixelY:Int = 0 Until sourcePixmap.Height
269+
For Local pixelX:Int = 0 Until sourcePixmap.Width
270+
convertingPixmap.WritePixel(pixelX, pixelY, ConvertColorToClosestIndex(ReadPixel(sourcePixmap, pixelX, pixelY)))
271+
Next
267272
Next
268-
Next
269273

270-
Local rows:Byte Ptr[sourcePixmap.Height]
271-
For Local i = 0 Until sourcePixmap.Height
272-
rows[i] = sourcePixmap.PixelPtr(0, i)
273-
Next
274-
png_set_rows(pngPtr, pngInfoPtr, rows)
274+
Local rows:Byte Ptr[sourcePixmap.Height]
275+
For Local i = 0 Until sourcePixmap.Height
276+
rows[i] = convertingPixmap.PixelPtr(0, i)
277+
Next
278+
png_set_rows(pngPtr, pngInfoPtr, rows)
275279

276-
png_write_png(pngPtr, pngInfoPtr, 0, Null)
277-
png_destroy_write_struct(Varptr pngPtr, Varptr pngInfoPtr, Null)
280+
png_write_png(pngPtr, pngInfoPtr, 0, Null)
281+
png_destroy_write_struct(Varptr pngPtr, Varptr pngInfoPtr, Null)
278282

279-
CloseStream(outputStream)
280-
Return True
281-
Catch error:String
282-
If error <> "PNG ERROR" Throw error
283-
EndTry
283+
CloseStream(outputStream)
284+
Return True
285+
Catch error:String
286+
If error <> "PNG ERROR" Then
287+
Throw error
288+
EndIf
289+
EndTry
290+
EndIf
284291
EndMethod
285292
EndType

types/IndexedPixmap.bmx

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
'//// INDEXED PIXMAP ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2+
3+
'Since TPixmap does not support RGB332 format gotta set up this custom one
4+
'Otherwise indexed PNG output is spaghetti because bad byte alignment (with RGB888/RGBA8888) or incorrect indexing (with I8)
5+
Type IndexedPixmap
6+
Field m_Pixels:Byte Ptr
7+
Field m_Width:Int
8+
Field m_Height:Int
9+
Field m_Capacity:Size_T
10+
11+
'////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
12+
13+
Method New(width:Int, height:Int)
14+
Local capacity:Size_T = width * height
15+
m_Pixels = MemAlloc(capacity)
16+
m_Width = width
17+
m_Height = height
18+
m_Capacity = capacity
19+
EndMethod
20+
21+
'////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
22+
23+
Method Delete()
24+
If m_Capacity >= 0 Then
25+
MemFree(m_Pixels)
26+
EndIf
27+
EndMethod
28+
29+
'////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
30+
31+
Method PixelPtr:Byte Ptr(x:Int, y:Int)
32+
Return m_Pixels + (y * m_Width) + (x * BytesPerPixel[PF_I8])
33+
EndMethod
34+
35+
'////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
36+
37+
Method ReadPixel(x:Int, y:Int)
38+
Assert x >= 0 And x < m_Width And y >= 0 And y < m_Height Else "Pixmap coordinates out of bounds!"
39+
Local pixel:Byte Ptr = PixelPtr(x, y)
40+
Return pixel[0]
41+
EndMethod
42+
43+
'////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
44+
45+
Method WritePixel(x:Int, y:Int, index:Byte)
46+
Assert x >= 0 And x < m_Width And y>=0 And y < m_Height Else "Pixmap coordinates out of bounds!"
47+
Local pixel:Byte Ptr = PixelPtr(x, y)
48+
pixel[0] = index
49+
EndMethod
50+
EndType

types/Utility.bmx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
'//// EXTERNAL FUNCTIONS ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2+
3+
Extern
4+
Function png_set_PLTE(png_ptr:Byte Ptr, info_ptr:Byte Ptr, palette:Byte Ptr, num_palette:Int) = "bmx_png_set_PLTE"
5+
EndExtern
6+
17
'//// UTILITY FUNCTIONS /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
28

39
Type Utility
@@ -87,4 +93,18 @@ Type Utility
8793
EndSelect
8894
Return outputPixmap
8995
EndFunction
96+
97+
'////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
98+
99+
Function PNGWriteStream(pngPtr:Byte Ptr, buf:Byte Ptr, size:Int)
100+
Local outputStream:TStream = TStream(png_get_io_ptr(pngPtr))
101+
Return outputStream.WriteBytes(buf, size)
102+
EndFunction
103+
104+
'////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
105+
106+
Function PNGFlushStream(pngPtr:Byte Ptr)
107+
Local outputStream:TStream = TStream(png_get_io_ptr(pngPtr))
108+
FlushStream(outputStream)
109+
EndFunction
90110
EndType

types/UtilityPNG.bmx

Lines changed: 0 additions & 26 deletions
This file was deleted.

0 commit comments

Comments
 (0)