For example you can give it world.png, and it generates world.win.pbimg, world.lnx.pbimg, and world.osx.pbimg.
Each .pbimg file is slightly converted so that it should appear exactly as if you had dumped it from that OS. (RGB vs BGR, reverse row order, and 24/32 bit are the differences - see very end of this post). Each .pbimg file simply has a 16-byte metadata header followed by the raw image data.
This way we have:
- a very simple, portable image format (not a public format as such, just for PB)
- that works across all three OS, yet only requires image conversions from one
- doesn't require a codec
- doesn't require any OS API like gdk
- supports 24+32bit (gives us another option for showing transparent images)
- hardly requires any supporting code (essentially just a CopyMemory) - no 'decoding'
- allows for a single format across all three (dont need ICO for Windows, ICNS for Mac, PNG for Linux etc)
- easily supports any compression algorithm we want so it can still compete with PNG/JPG/GIF, but I've left that out for now.
Then we can simply CompilerIf-IncludeBinary the right .pbimg depending on OS, example usage:
Code: Select all
Structure PBIMG_Hdr ;Size=16 bytes, followed immediately by raw image data.
Width.l ;Width (pixels)
Height.l ;Height (pixels). Total image bytes after the header = dwHeight * dwPitch
Pitch.l ;DrawingBufferPitch() (bytes per row)
PixFmt.w ;DrawingBufferPixelFormat()
Depth.a ;24 or 32
Packer.a ;0=Original data, otherwise #PB_PackerPlugin_BriefLZ, #PB_PackerPlugin_Lzma, or #PB_PackerPlugin_Zip
EndStructure
Procedure LoadPBImg(ImgGadget, *PBImg.PBIMG_Hdr)
hImg = CreateImage(#PB_Any, *PBImg\Width, *PBImg\Height, *PBImg\Depth)
If hImg And StartDrawing(ImageOutput(hImg))
CopyMemory(*PBImg+SizeOf(PBIMG_Hdr), DrawingBuffer(), *PBImg\Height * *PBImg\Pitch)
StopDrawing()
SetGadgetState(ImgGadget, ImageID(hImg))
EndIf
EndProcedure
#Image1=1
If OpenWindow(0, 0, 0, 200, 200, "PBImage", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
ImageGadget(#Image1, 0, 0, 200, 200, 0)
LoadPBImg(#Image1, ?Image1)
EndIf
Repeat: Until WaitWindowEvent() = #PB_Event_CloseWindow
DataSection
Image1:
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
IncludeBinary(#PB_Compiler_Home + "/examples/sources/Data/world.png.win.pbimg")
CompilerElseIf #PB_Compiler_OS = #PB_OS_MacOS
IncludeBinary(#PB_Compiler_Home + "/examples/sources/Data/world.png.osx.pbimg")
CompilerElseIf #PB_Compiler_OS = #PB_OS_Linux
IncludeBinary(#PB_Compiler_Home + "/examples/sources/Data/world.png.lnx.pbimg")
CompilerEndIf
EndDataSection
Code: Select all
EnableExplicit
Structure PBIMG_Hdr ;Size=16 bytes, followed immediately by raw image data.
Width.l ;Width (pixels)
Height.l ;Height (pixels). Total image bytes after the header = dwHeight * dwPitch
Pitch.l ;DrawingBufferPitch() (bytes per row)
PixFmt.w ;DrawingBufferPixelFormat()
Depth.a ;24 or 32
Packer.a ;(COMING SOON) 0=Original data, or #PB_PackerPlugin_BriefLZ, #PB_PackerPlugin_Lzma, or #PB_PackerPlugin_Zip
EndStructure
Structure RGB
r.a
g.a
b.a
EndStructure
Procedure FlipImageRows(hImg) ;Applies or unapplies #PB_PixelFormat_ReversedY
Protected *pbuf, *psrc, *ptmp, *pdst, width, height, i
If StartDrawing(ImageOutput(hImg))
*pbuf = DrawingBuffer()
width = DrawingBufferPitch()
height = ImageHeight(hImg)
*psrc = *pbuf
*ptmp = AllocateMemory(width*height)
If *ptmp
*pdst = *ptmp + (width*height)-width
For i = 0 To height-1
CopyMemory(*psrc, *pdst, width)
*pdst-width
*psrc+width
Next i
CopyMemory(*ptmp, *pbuf, width*height)
FreeMemory(*ptmp)
EndIf
StopDrawing()
EndIf
EndProcedure
Procedure.i ConvertImageDepth(hImg, newfmt)
Protected width,height, hImgNew
width = ImageWidth(hImg)
height = ImageHeight(hImg)
hImgNew = CreateImage(#PB_Any, width, height, newfmt)
If hImgNew = 0: ProcedureReturn 0: EndIf
If StartDrawing(ImageOutput(hImgNew)) = 0
FreeImage(hImgNew)
ProcedureReturn 0
EndIf
DrawingMode(#PB_2DDrawing_Default)
DrawImage(ImageID(hImg),0,0,width,height)
StopDrawing()
FreeImage(hImg)
ProcedureReturn hImgNew
EndProcedure
Procedure FlipEndianRGB(hImg)
Protected *pbuf, width,height,pitch, x,y, depthstep, *nextRGB.RGB
If StartDrawing(ImageOutput(hImg))
*pbuf = DrawingBuffer()
pitch = DrawingBufferPitch()
width = ImageWidth(hImg)
height = ImageHeight(hImg)
If ImageDepth(hImg) = 24: depthstep = 3: Else: depthstep = 4: EndIf
For y = 0 To height-1
*nextRGB.RGB = *pbuf + (y * pitch)
For x = 0 To width-1
Swap *nextRGB\b, *nextRGB\r
*nextRGB + depthstep
Next x
Next y
StopDrawing()
EndIf
EndProcedure
Procedure SavePBImg(hImg, fmt, filename.s)
Protected PBImg.PBIMG_Hdr, hFile, bytes, *buf
If StartDrawing(ImageOutput(hImg))
PBImg\Width = ImageWidth(hImg)
PBImg\Height = ImageHeight(hImg)
PBImg\Pitch = DrawingBufferPitch()
PBImg\PixFmt = fmt
PBImg\Depth = ImageDepth(hImg)
PBImg\Packer = 0
bytes = PBImg\Pitch * PBImg\Height
*buf = AllocateMemory(bytes + SizeOf(PBIMG_Hdr))
If *buf
CopyMemory(DrawingBuffer(), *buf+SizeOf(PBIMG_Hdr), bytes)
CopyMemory(@PBImg, *buf, SizeOf(PBIMG_Hdr))
hFile = CreateFile(#PB_Any, filename)
WriteData(hFile, *buf, MemorySize(*buf))
CloseFile(hFile)
EndIf
EndIf
StopDrawing()
EndProcedure
Procedure ConvertImageToRaw(imgfile.s)
Protected *buf, hImg = LoadImage(#PB_Any, imgfile)
If hImg = 0
MessageRequester("Error","Couldnt load file " + imgfile)
ProcedureReturn 0
EndIf
Select ImageDepth(hImg)
Case 24:
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
SavePBImg(hImg, #PB_PixelFormat_24Bits_BGR + #PB_PixelFormat_ReversedY, imgfile+".win.pbimg")
FlipEndianRGB(hImg)
FlipImageRows(hImg)
SavePBImg(hImg, #PB_PixelFormat_24Bits_RGB, imgfile+".lnx.pbimg")
hImg = ConvertImageDepth(hImg,32)
SavePBImg(hImg, #PB_PixelFormat_32Bits_RGB, imgfile+".osx.pbimg")
CompilerElseIf #PB_Compiler_OS = #PB_OS_MacOS
SavePBImg(hImg, #PB_PixelFormat_32Bits_RGB, imgfile+".osx.pbimg")
hImg = ConvertImageDepth(hImg,24)
SavePBImg(hImg, #PB_PixelFormat_24Bits_RGB, imgfile+".lnx.pbimg")
FlipEndianRGB(hImg)
FlipImageRows(hImg)
SavePBImg(hImg, #PB_PixelFormat_24Bits_BGR + #PB_PixelFormat_ReversedY, imgfile+".win.pbimg")
CompilerElseIf #PB_Compiler_OS = #PB_OS_Linux
SavePBImg(hImg, #PB_PixelFormat_24Bits_RGB, imgfile+".lnx.pbimg")
FlipEndianRGB(hImg)
FlipImageRows(hImg)
SavePBImg(hImg, #PB_PixelFormat_24Bits_BGR + #PB_PixelFormat_ReversedY, imgfile+".win.pbimg")
FlipEndianRGB(hImg)
FlipImageRows(hImg)
hImg = ConvertImageDepth(hImg,32)
SavePBImg(hImg, #PB_PixelFormat_32Bits_RGB, imgfile+".osx.pbimg")
CompilerEndIf
Case 32:
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
SavePBImg(hImg, #PB_PixelFormat_32Bits_BGR + #PB_PixelFormat_ReversedY, imgfile+".win.pbimg")
FlipEndianRGB(hImg)
FlipImageRows(hImg)
SavePBImg(hImg, #PB_PixelFormat_32Bits_RGB, imgfile+".lnxosx.pbimg")
CompilerElseIf #PB_Compiler_OS = #PB_OS_MacOS Or #PB_Compiler_OS = #PB_OS_Linux
SavePBImg(hImg, #PB_PixelFormat_32Bits_RGB, imgfile+".lnxosx.pbimg")
FlipEndianRGB(hImg)
FlipImageRows(hImg)
SavePBImg(hImg, #PB_PixelFormat_32Bits_BGR + #PB_PixelFormat_ReversedY, imgfile+".win.pbimg")
CompilerEndIf
EndSelect
If StartDrawing(ImageOutput(hImg))
Else
MessageRequester("Error","StartDrawing failed")
EndIf
EndProcedure
;---
UsePNGImageDecoder(): UseJPEGImageDecoder(): UseJPEG2000ImageDecoder(): UseTGAImageDecoder(): UseTIFFImageDecoder()
Define TargetImage.s = #PB_Compiler_Home + "/examples/sources/Data/world.png" ;Image to convert to .pbimg's
ConvertImageToRaw(TargetImage)
MessageRequester("OK","Converted")
Code: Select all
; Win-24 (BGR): $8010 = #PB_PixelFormat_24Bits_BGR + #PB_PixelFormat_ReversedY
; Win-32 (BGRA): $8040 = #PB_PixelFormat_32Bits_BGR + #PB_PixelFormat_ReversedY
; Lnx-24 (RGB): $8 = #PB_PixelFormat_24Bits_RGB
; Lnx-32 (RGBA): $20 = #PB_PixelFormat_32Bits_RGB ;shared
; OSX-24 (RGBA): $20 = #PB_PixelFormat_32Bits_RGB ;shared
; OSX-32 (RGBA): $20 = #PB_PixelFormat_32Bits_RGB ;shared