Code: Select all
; Create a SpriteSheet_BF from a APNG image
; For GFX_Wizzard_BF or other, with included frame data and external sheet-info file
; Author W. Albus and Thorsten Hoeppner (Thorsten1867) - This code is free
; The APNG module for Purebasic from Thorsten1867 is needed
; https://www.purebasic.fr/english/viewtopic.php?f=27&t=75172
; - Or search simple on Google for it
; Recommended : Look ever for the newest APNG module version
XIncludeFile "UseAPNGModule.pbi"
DeclareModule CreateCSSSheet_from_APNG_BF
Declare CreateCSSSheet_from_APNG_BF(Path_Source$, Scale.f = 1, Get_Only_Sheet_ID = #False)
EndDeclareModule
Module CreateCSSSheet_from_APNG_BF
EnableExplicit
Macro Common_Write_Frame_Data ; Change on this macro absolutely nothing
WriteStringN(File, " Frames #" + RSet(Str(Frames), 8, "0 "), #PB_Ascii)
WriteStringN(File, " Frame width #" + RSet(Str(aPNG_Width), 8, "0 "), #PB_Ascii)
WriteStringN(File, " Frame height #" + RSet(Str(aPNG_Height), 8, "0 "), #PB_Ascii)
WriteStringN(File, " Sheet width #" + RSet(Str(Sheet_Width), 8, "0 "), #PB_Ascii)
WriteStringN(File, " Sheet height #" + RSet(Str(Sheet_Height), 8, "0 "), #PB_Ascii)
WriteStringN(File, " Frames in a row #" + RSet(Str(Frames_in_a_Row), 8, "0 "), #PB_Ascii)
WriteStringN(File, " Invisible color #" + "00000000" + " $000000", #PB_Ascii)
WriteStringN(File, " Color distance #" + "00000000" + " $000000", #PB_Ascii)
For i=0 To Frames -1
SetImageFrame(aPNG_ID, i)
Frame_Delay = GetImageFrameDelay(aPNG_ID)
Result = WriteStringN(File, " Frame / delay :" + RSet(Str(i + 1), 8, "0 ") +
" *" + RSet(Str(Frame_Delay), 8, "0"), #PB_Ascii)
Next i
EndMacro
Procedure CreateCSSSheet_from_APNG_BF(Path_Source$, Scale.f = 1, Get_Only_Sheet_ID = #False)
Define.i aPNG_ID, aPNG_Width, aPNG_Height
Define.i Frames, Frames_X, Frames_Y, Frames_in_a_Row, Frame_Delay
Define.i Sheet_ID, Sheet_Width, Sheet_Height
Define.i i, add_height_0, add_height_1, X, Y, cHeight, Result, File, File_Length
Define.s Path_Destination$
If Path_Source$ = ""
ProcedureReturn 0
EndIf
If UCase(GetExtensionPart(Path_Source$)) <> "PNG"
ProcedureReturn -1
EndIf
aPNG_ID = PNG::Load(#PB_Any, Path_Source$)
If IsImage(aPNG_ID) ;{ Create sheet from apng
aPNG_ID = PNG::GenerateFrames(aPNG_ID, Scale)
PNG::Free(aPNG_ID) ; The original image frames from APNG are no longer required
aPNG_Width = ImageWidth(aPNG_ID)
aPNG_Height = ImageHeight(aPNG_ID)
Frames = ImageFrameCount(aPNG_ID)
If Frames > 1
If aPNG_Height > aPNG_Width
Frames_X = Sqr(Frames) + 1
Else
Frames_X = Sqr(Frames)
EndIf
If Not Frames_X : Frames_X = 1 : EndIf
Frames_Y = Frames / Frames_X + 1
Sheet_Width = Frames_X * aPNG_Width
Sheet_Height = Frames_Y * aPNG_Height
For i = 0 To Frames - 1 ;{ Calculations
add_height_1 = add_height_0 : X + aPNG_Width
If X => Sheet_Width
X = 0
add_height_0 + aPNG_Height
EndIf ;}
Next
sheet_height = add_height_1 + aPNG_Height
Frames_in_a_Row = Sheet_Width / aPNG_Width
Sheet_ID = CreateImage(#PB_Any, Sheet_Width, Sheet_Height, 32, #PB_Image_Transparent)
If IsImage(Sheet_ID)
X = 0 : Y = 0
If StartDrawing(ImageOutput(Sheet_ID)) ;{ Draw sheet image
For i = 0 To Frames - 1
SetImageFrame(aPNG_ID, i)
DrawingMode(#PB_2DDrawing_AlphaBlend)
DrawImage(ImageID(aPNG_ID), X, Y)
X + aPNG_Width
If X = > Sheet_Width
X = 0
Y + aPNG_Height
EndIf
Next
StopDrawing()
EndIf ;}
If Get_Only_Sheet_ID : ProcedureReturn Sheet_ID : EndIf
Path_Destination$ = GetPathPart(Path_Source$) +
GetFilePart(Path_Source$, #PB_FileSystem_NoExtension) +
"_SpriteSheet_BF.png"
If Path_Destination$
SaveImage(Sheet_ID, Path_Destination$, #PB_ImagePlugin_PNG)
EndIf
FreeImage(Sheet_ID)
Else
ProcedureReturn -2
EndIf
Else
ProcedureReturn -3
EndIf
Else
ProcedureReturn -4
EndIf ;}
; This are pre defined import functions for use this code directly
; - inside the GFX_Wizzard_BF main module to import a APNG image as SpriteSheet_BF
; SetGIFandCSS_Frames_BF(Frames)
; SetGIFandCSS_Frame_width_BF(aPNG_Width)
; SetGIFandCSS_Frame_height_BF(aPNG_Height)
; SetCSS_width_BF(sheet_width)
; SetCSS_height_BF(Sheet_Height)
; SetFrames_in_a_row_BF(Frames_in_a_Row)
; SetGIFandCSS_color_distance_BF(0)
; SetGIFandCSS_invisible_color_BF(0)
; For i = 0 To Frames -1
; SetImageFrame(aPNG_ID, i)
; Frame_Delay = GetImageFrameDelay(aPNG_ID)
; SetGIFandCSS_delay_array_BF(i, Frame_Delay)
; Next i
; ProcedureReturn Sheet_ID
If Path_Destination$
File = CreateFile(#PB_Any, GetPathPart(Path_Destination$) +
GetFilePart(Path_Destination$, #PB_FileSystem_NoExtension) +
"_sheet_info_BF.txt")
If File ;{ Write sheet info file
Common_Write_Frame_Data
CloseFile(File)
Else
ProcedureReturn -5
EndIf ;}
If FileSize(Path_Destination$) > 0 ;{ Append file to the image
File = OpenFile(#PB_Any, Path_Destination$)
If File
File_Length = Lof(File)
FileSeek(File, File_length)
Common_Write_Frame_Data
Result = WriteQuad(File, Loc(File) - File_length)
CloseFile(File)
EndIf
If Result = 8 : ProcedureReturn #True : EndIf
EndIf ;}
EndIf
ProcedureReturn -6
EndProcedure
EndModule
;- ======== Module - Example ========
CompilerIf #PB_Compiler_IsMainFile
UsePNGImageDecoder()
UseModule CreateCSSSheet_from_APNG_BF
EnableExplicit
Define Get_Only_Sheet_ID = #False ; Get only the Sheet_ID for displaying
; - the created sheet without creating a file
Define scale.f = 1.0 ; Scaling factor
Define Path_Source$ = OpenFileRequester("Select a APNG picture", "", "", 0)
Define Sheet_ID = CreateCSSSheet_from_APNG_BF(Path_Source$, scale, get_only_Sheet_ID)
If (get_only_sheet_ID And Not IsImage(sheet_ID)) Or sheet_ID < 1
If sheet_ID = -1 Or sheet_ID = -3
MessageRequester("Hint", "Not a multiframe APNG image" + #LF$ + #LF$ + Str(sheet_ID))
ElseIf sheet_ID < 0
MessageRequester("Hint", "Function fail" + #LF$ + #LF$ + Str(sheet_ID))
EndIf
End
EndIf
If get_only_Sheet_ID
Define window_ID = OpenWindow(#PB_Any, 0, 0, 1200, 700,
"APNG based SpriteSheet_BF generating for GFX_Wizzard_BF and other",
#PB_Window_SystemMenu | #PB_Window_ScreenCentered)
Define canvas_ID = CanvasGadget(#PB_Any, 0, 0, 1200, 700)
ResizeImage(sheet_ID, 1200, 700)
If StartDrawing(CanvasOutput(canvas_ID))
DrawingMode(#PB_2DDrawing_AlphaBlend)
DrawImage(ImageID(Sheet_ID), 0, 0)
StopDrawing()
EndIf
Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf
CompilerEndIf