[Module] Animated PNG (all OS)

Applications, Games, Tools, User libs and useful stuff coded in PureBasic
User avatar
Thorsten1867
Addict
Addict
Posts: 1366
Joined: Wed Aug 24, 2005 4:02 pm
Location: Germany

Re: [Module] Animated PNG (all OS)

Post by Thorsten1867 »

Update: create own APNGs
  • PNG::Create(ImageNum.i, File.s, Loops.i=0, Delay.i=0, Flags.i=#False)
  • PNG::AddFrame(ImageNum.i, FrameNum.i, X.i=0, Y.i=0, Width.i=0, Height.i=0, Delay.i=0, Dispos_OP.i=0, Blend_OP.i=0, Index.i=#PB_Default)
  • PNG::Close(ImageNum.i)
Translated with http://www.DeepL.com/Translator

Download of PureBasic - Modules
Download of PureBasic - Programs

[Windows 11 x64] [PB V5.7x]
User avatar
chi
Addict
Addict
Posts: 1034
Joined: Sat May 05, 2007 5:31 pm
Location: Linz, Austria

Re: [Module] Animated PNG (all OS)

Post by chi »

Thorsten1867 wrote:Bugfixes: Problems with indexed PNGs and complex APNGs (e.g. #APNG_Dispos_OP_Previous) fixed.
Thank you :D
Et cetera is my worst enemy
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5357
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Re: [Module] Animated PNG (all OS)

Post by Kwai chang caine »

Works nice here, thanks for sharing 8)
ImageThe happiness is a road...
Not a destination
User avatar
Thorsten1867
Addict
Addict
Posts: 1366
Joined: Wed Aug 24, 2005 4:02 pm
Location: Germany

Re: [Module] Animated PNG (all OS)

Post by Thorsten1867 »

Bugfixes: GenerateFrames()
Translated with http://www.DeepL.com/Translator

Download of PureBasic - Modules
Download of PureBasic - Programs

[Windows 11 x64] [PB V5.7x]
User avatar
Thorsten1867
Addict
Addict
Posts: 1366
Joined: Wed Aug 24, 2005 4:02 pm
Location: Germany

Re: [Module] Animated PNG (all OS)

Post by Thorsten1867 »

Bugfix: GenerateFrames() without scaling
Translated with http://www.DeepL.com/Translator

Download of PureBasic - Modules
Download of PureBasic - Programs

[Windows 11 x64] [PB V5.7x]
User avatar
Andre
PureBasic Team
PureBasic Team
Posts: 2071
Joined: Fri Apr 25, 2003 6:14 pm
Location: Germany (Saxony, Deutscheinsiedel)
Contact:

Re: [Module] Animated PNG (all OS)

Post by Andre »

The following is the result of a collaboration between GFX_Wizzard_BF author and 'Thorsten1867', creating "Sprite sheets" made from APNG images:
walbus wrote:Save as 'Create_Sprite_CSS_Sheet_from_APNG.pb' ('UseAPNGModule.pbi' include is needed)

SpriteSheets_BF support 24 bit, 32 bit and alpha channel so there is no loss.
Depending on the template, the use of JPEG-based SpriteSheets_BF and Sprites_BF can save up to 80% in size, but this really depends on the template and can be very different.
SpriteSheets_BF can of course also be created as PNG.

All sprite data are stored in the sprite sheets, including delays, invisible color and color distance.
This data can be read in and used automatically.

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
Bye,
...André
(PureBasicTeam::Docs & Support - PureArea.net | Order:: PureBasic | PureVisionXP)
Post Reply