ImagePlugin Module (Cross platform multi format de-/encoder)
Posted: Thu Sep 01, 2016 6:18 am
ImagePlugin Module (Cross platform multi format de-/encoder)
This module adds support of multiple image formats to CatchImage, LoadImage, EncodeImage and SaveImage.
In general the Depth argument to specify the color depth is ignored.
v1.52 contains a fix for setting jpeg quality on PB x86 for Windows.
Platform specifics
Windows
Special requirements : MemoryStream module ( http://www.purebasic.fr/english/viewtop ... =5&t=66487 ), gdiplus.lib
Supported decode formats : JPEG, GIF, TIFF, PNG
Supported encode formats : BMP, JPEG, GIF, TIFF, PNG
Mac
Supported decode formats : JPEG, GIF, TIFF, PNG, JPEG2000
Supported encode formats : BMP, JPEG, GIF, TIFF, PNG
Linux
Supported decode formats : JPEG, GIF, TIFF, PNG
Supported encode formats : BMP, JPEG, TIFF, PNG
Image format specifics
JPEG
Encoding quality can be set from 1 - 100.
SaveImage(0, "output.jpg", #SystemImagePlugin, #SystemImagePlugin_JPEG | 70)
GIF
Encoded image might be dithered.
Encoding is not supported by default on Linux.
TIFF
Optional Depth argument for EncodeImage and SaveImage is supported on Windows.
This module adds support of multiple image formats to CatchImage, LoadImage, EncodeImage and SaveImage.
In general the Depth argument to specify the color depth is ignored.
v1.52 contains a fix for setting jpeg quality on PB x86 for Windows.
Platform specifics
Windows
Special requirements : MemoryStream module ( http://www.purebasic.fr/english/viewtop ... =5&t=66487 ), gdiplus.lib
Supported decode formats : JPEG, GIF, TIFF, PNG
Supported encode formats : BMP, JPEG, GIF, TIFF, PNG
Mac
Supported decode formats : JPEG, GIF, TIFF, PNG, JPEG2000
Supported encode formats : BMP, JPEG, GIF, TIFF, PNG
Linux
Supported decode formats : JPEG, GIF, TIFF, PNG
Supported encode formats : BMP, JPEG, TIFF, PNG
Image format specifics
JPEG
Encoding quality can be set from 1 - 100.
SaveImage(0, "output.jpg", #SystemImagePlugin, #SystemImagePlugin_JPEG | 70)
GIF
Encoded image might be dithered.
Encoding is not supported by default on Linux.
TIFF
Optional Depth argument for EncodeImage and SaveImage is supported on Windows.
Code: Select all
;================================================;
; Module : ImagePlugin (Cross platform) ;
; Author : Wilbert ;
; Date : Sep 9, 2016 ;
; Version : 1.52 ;
; ;
; Implemented : ModuleImagePluginStop() ;
; UseSystemImageDecoder() ;
; UseSystemImageEncoder() ;
; ;
; *Additional requirements for Windows: ;
; MemoryStreamModule.pbi, gdiplus.lib ;
;================================================;
;- Module declaration
DeclareModule ImagePlugin
#SystemImagePlugin = $737953
#SystemImagePlugin_BMP = $100000
#SystemImagePlugin_JPEG = $300100
#SystemImagePlugin_GIF = $200200
#SystemImagePlugin_TIFF_LZW = $052500
#SystemImagePlugin_TIFF_None = $016500
#SystemImagePlugin_PNG = $400600
Declare ModuleImagePluginStop()
Declare.i UseSystemImageDecoder()
Declare.i UseSystemImageEncoder()
EndDeclareModule
;- Module implementation
CompilerIf #PB_Compiler_OS = #PB_OS_Windows And Not Defined(MemoryStream, #PB_Module)
; http://www.purebasic.fr/english/viewtopic.php?f=5&t=66487
IncludeFile "MemoryStreamModule.pbi"
CompilerEndIf
Module ImagePlugin
EnableExplicit
DisableDebugger
;- Structures (all OS)
Structure PB_ImageDecoder Align #PB_Structure_AlignC
*Check
*Decode
*Cleanup
ID.l
EndStructure
Structure PB_ImageDecoderGlobals Align #PB_Structure_AlignC
*Decoder.PB_ImageDecoder
*Filename
*File
*Buffer
Length.l
Mode.l
Width.l
Height.l
Depth.l
Flags.l
Data.i[8]
OriginalDepth.l
EndStructure
Structure PB_ImageEncoder Align #PB_Structure_AlignC
ID.l
*Encode24
*Encode32
EndStructure
;- Imports (all OS)
IsImage(0) ; make sure ImagePlugin library is available so imports won't fail
CompilerIf #PB_Compiler_OS = #PB_OS_Windows And #PB_Compiler_Processor = #PB_Processor_x86
Import ""
PB_ImageDecoder_Register(*ImageDecoder.PB_ImageDecoder) As "_PB_ImageDecoder_Register@4"
PB_ImageEncoder_Register(*ImageEncoder.PB_ImageEncoder) As "_PB_ImageEncoder_Register@4"
EndImport
CompilerElse
ImportC "" ; ImportC can be used on all OS for PB x64
PB_ImageDecoder_Register(*ImageDecoder.PB_ImageDecoder)
PB_ImageEncoder_Register(*ImageEncoder.PB_ImageEncoder)
EndImport
CompilerEndIf
; Private procedures (all OS)
Procedure.i JPEGQuality(EncoderFlags.l)
Protected Value.l = EncoderFlags & $FF
If Value = 0
Value = 80
ElseIf Value > 100
Value = 100
EndIf
ProcedureReturn Value
EndProcedure
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
;{ >>> WINDOWS <<<
;- Structures (Windows)
Structure GdiplusStartupInput_
GdiPlusVersion.i
*DebugEventCallback
SuppressBackgroundThread.l
SuppressExternalCodecs.l
EndStructure
Structure BitmapData_
Width.l
Height.l
Stride.l
PixelFormat.l
*Scan0
*Reserved
EndStructure
Structure EncoderParameter_
Guid.q[2]
NumberOfValues.l
Type.l
*Value
EndStructure
Structure EncoderParameters_
Count.i
Parameter.EncoderParameter_[2]
EndStructure
;- Imports (Windows)
Import "gdiplus.lib"
GdipBitmapLockBits(bitmap, *rect, flags, format, *lockedBitmapData)
GdipBitmapUnlockBits(bitmap, *lockedBitmapData)
GdipCreateBitmapFromFile(filename.p-unicode, *bitmap)
GdipCreateBitmapFromScan0(width, height, stride, format, *scan0, *bitmap)
GdipCreateBitmapFromStream(stream, *bitmap)
GdipDeleteGraphics(graphics)
GdipDisposeImage(image)
GdipDrawImageI(graphics, image, x, y)
GdipGetImageHeight(image, *height)
GdipGetImagePixelFormat(image, *format)
GdipGetImageWidth(image, *width)
GdipGetImageGraphicsContext(image, *graphics)
GdipSaveImageToFile(image, filename.p-unicode, *clsidEncoder, *encoderParams)
GdipSaveImageToStream(image, stream, *clsidEncoder, *encoderParams)
GdiplusShutdown(token)
GdiplusStartup(*token, *input, *output)
EndImport
;- Macros (Windows)
CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
Macro rax : eax : EndMacro
Macro rbx : ebx : EndMacro
Macro rcx : ecx : EndMacro
Macro rdx : edx : EndMacro
CompilerEndIf
;- Global variables (Windows)
Global Input.GdiplusStartupInput_, Token.i
;- Private procedures (Windows)
Procedure _PNGSizeCheck_(*MemoryAddress, MaxSize.l)
EnableASM
mov rdx, [p.p_MemoryAddress]
!mov eax, [p.v_MaxSize]
push rbx
!lea ebx, [eax - 8]
!xor eax, eax
cmp dword [rdx], 0x474e5089
!jne .l1
cmp dword [rdx + 4], 0x0a1a0a0d
!jne .l1
!mov eax, 8
!.l0:
mov ecx, [rdx + rax]
!bswap ecx
lea rax, [rax + rcx + 12]
!cmp eax, ebx
!ja .l1
cmp dword [rdx + rax + 4], 0x444e4549
!jne .l0
!add eax, 12
!.l1:
pop rbx
DisableASM
ProcedureReturn
EndProcedure
Procedure.i _Start_()
If Token = 0
Input\GdiPlusVersion = 1
GdiplusStartup(@Token, @Input, #Null)
EndIf
ProcedureReturn Token
EndProcedure
Procedure _Cleanup_(*Globals.PB_ImageDecoderGlobals)
If *Globals\Data[0]
GdipDisposeImage(*Globals\Data[0]) : *Globals\Data[0] = #Null
EndIf
EndProcedure
Procedure.i _Check_(*Globals.PB_ImageDecoderGlobals)
Protected Size.l, Stream.IStream
If Token
If *Globals\Mode = 0
; File Mode
GdipCreateBitmapFromFile(PeekS(*Globals\FileName), @*Globals\Data[0])
Else
; Memory Mode
Size = _PNGSizeCheck_(*Globals\Buffer, *Globals\Length)
If Size And Size < *Globals\Length
*Globals\Length = Size
EndIf
Stream = MemoryStream::CreateMemoryStream(MemoryStream::#MemoryStream_ReadOnly, *Globals\Buffer, *Globals\Length)
GdipCreateBitmapFromStream(Stream, @*Globals\Data[0])
Stream\Release()
EndIf
If *Globals\Data[0]
GdipGetImageWidth(*Globals\Data[0], @*Globals\Width)
GdipGetImageHeight(*Globals\Data[0], @*Globals\Height)
GdipGetImagePixelFormat(*Globals\Data[0], @*Globals\OriginalDepth)
*Globals\OriginalDepth = *Globals\OriginalDepth >> 8 & $FF
*Globals\Depth = 32
ProcedureReturn #True
EndIf
EndIf
ProcedureReturn #False
EndProcedure
Procedure.i _Decode_(*Globals.PB_ImageDecoderGlobals, *Buffer, Pitch.l, Flags.l)
Protected Rect.Rect, BitmapData.BitmapData_
Rect\right = *Globals\Width
Rect\bottom = *Globals\Height
BitmapData\Width = *Globals\Width
BitmapData\Height = *Globals\Height
If Flags & 2 ; ReverseY ?
BitmapData\Stride = -Pitch
BitmapData\Scan0 = *Buffer + (*Globals\Height - 1) * Pitch
Else
BitmapData\Stride = Pitch
BitmapData\Scan0 = *Buffer
EndIf
BitmapData\PixelFormat = $26200A
GdipBitmapLockBits(*Globals\Data[0], @Rect, 5, $26200A, @BitmapData)
GdipBitmapUnlockBits(*Globals\Data[0], @BitmapData)
_Cleanup_(*Globals)
ProcedureReturn #True
EndProcedure
Procedure.i _Encode_(PixelFormat, *Filename, *Buffer, Width.l, Height.l, LinePitch.l, Flags.l, EncoderFlags.l, RequestedDepth.l)
Protected.i Result, Bitmap, ImageType, TBuffer, TBitmap, Graphics, Value, Size.q, Stream.IStream
Protected Parameters.EncoderParameters_, *Parameters = @Parameters
Protected Dim CLSID.q(1)
If Token
If Flags & 2
GdipCreateBitmapFromScan0(Width, Height, -LinePitch, PixelFormat, *Buffer + (Height - 1) * LinePitch, @Bitmap)
Else
GdipCreateBitmapFromScan0(Width, Height, LinePitch, PixelFormat, *Buffer, @Bitmap)
EndIf
If Bitmap
ImageType = EncoderFlags >> 8 & 7
If PixelFormat = $26200A And ImageType < 2
; Try to flatten alpha channel for BMP and JPEG
TBuffer = AllocateMemory(Width << 2 * Height, #PB_Memory_NoClear)
If TBuffer
FillMemory(TBuffer, Width << 2 * Height, $FFFFFFFF, #PB_Long)
If GdipCreateBitmapFromScan0(Width, Height, Width << 2, PixelFormat, TBuffer, @TBitmap) = 0
If GdipGetImageGraphicsContext(TBitmap, @Graphics) = 0
GdipDrawImageI(Graphics, Bitmap, 0, 0)
GdipDeleteGraphics(Graphics)
GdipDisposeImage(Bitmap) : Bitmap = TBitmap
EndIf
EndIf
EndIf
EndIf
Select ImageType
Case 1 ; JPEG
Value = JPEGQuality(EncoderFlags)
Parameters\Count = 1
Parameters\Parameter[0]\Guid[0] = $452DFA4A1D5BE4B5
Parameters\Parameter[0]\Guid[1] = $EBE70551B35DDD9C
Parameters\Parameter[0]\NumberOfValues = 1
Parameters\Parameter[0]\Type = 4
Parameters\Parameter[0]\Value = @Value
Case 5 ; TIFF
Value = EncoderFlags >> 12 & 7
Parameters\Count = 2
Parameters\Parameter[0]\Guid[0] = $44EECCD4E09D739D
Parameters\Parameter[0]\Guid[1] = $58FCE48BBF3FBA8E
Parameters\Parameter[0]\NumberOfValues = 1
Parameters\Parameter[0]\Type = 4
Parameters\Parameter[0]\Value = @Value
Parameters\Parameter[1]\Guid[0] = $4C7CAD6666087055
Parameters\Parameter[1]\Guid[1] = $37830B31A238189A
Parameters\Parameter[1]\NumberOfValues = 1
Parameters\Parameter[1]\Type = 4
Parameters\Parameter[1]\Value = @RequestedDepth
Default
*Parameters = #Null
EndSelect
CLSID(0) = $11D31A04557CF400 + ImageType : CLSID(1) = $2EF31EF80000739A
If *Filename
; File Mode
Result = Bool(GdipSaveImageToFile(Bitmap, PeekS(*Filename), @CLSID(), *Parameters) = 0)
Else
; Memory Mode
If CreateStreamOnHGlobal_(#Null, #True, @Stream) = 0; Create empty stream which can grow
If GdipSaveImageToStream(Bitmap, Stream, @CLSID(), *Parameters) = 0
Stream\Seek(0, #STREAM_SEEK_END, @Size); Check stream size after saving to stream
If Size > 0
Result = AllocateMemory(Size, #PB_Memory_NoClear)
If Result
Stream\Seek(0, #STREAM_SEEK_SET, #Null)
Stream\Read(Result, Size, #Null); Copy encoded image to allocated memory
EndIf
EndIf
EndIf
Stream\Release()
EndIf
EndIf
GdipDisposeImage(Bitmap)
EndIf
EndIf
If TBuffer
FreeMemory(TBuffer)
EndIf
ProcedureReturn Result
EndProcedure
Procedure.i _Encode24_(*Filename, *Buffer, Width.l, Height.l, LinePitch.l, Flags.l, EncoderFlags.l, RequestedDepth.l)
ProcedureReturn _Encode_($21808, *Filename, *Buffer, Width, Height, LinePitch, Flags, EncoderFlags, RequestedDepth)
EndProcedure
Procedure.i _Encode32_(*Filename, *Buffer, Width.l, Height.l, LinePitch.l, Flags.l, EncoderFlags.l, RequestedDepth.l)
ProcedureReturn _Encode_($26200A, *Filename, *Buffer, Width, Height, LinePitch, Flags, EncoderFlags, RequestedDepth)
EndProcedure
;}
CompilerElseIf #PB_Compiler_OS = #PB_OS_MacOS
;{ >>> MAC <<<
;- Global variables (Mac)
Global.i NSImageCompressionFactor, NSImageCompressionMethod
;- Imports (Mac)
ImportC -framework Accelerate"
dlsym(handle, symbol.p-utf8)
strlen(*s)
vImageUnpremultiplyData_RGBA8888(*src, *dest, flags)
CFDataGetBytePtr(theData)
CFRelease(cf)
CFURLCreateFromFileSystemRepresentation(allocator, *buffer, bufLen, isDirectory)
CGBitmapContextCreate(*data, width, height, bitsPerComponent, bytesPerRow, colorspace, bitmapInfo)
CGColorSpaceCreateDeviceRGB()
CGColorSpaceRelease(colorspace)
CGContextDrawImage(c, xf.f, yf.f, wf.f, hf.f, image, d0.f, d1.f, d2.f, d3.f, xd.d, yd.d, wd.d, hd.d)
CGContextRelease(context)
CGDataProviderCopyData(provider)
CGDataProviderCreateWithData(*info, *data, size, releaseData)
CGDataProviderRelease(provider)
CGImageCreate(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, space, bitmapInfo, provider, *decode, shouldInterpolate, intent)
CGImageGetBitmapInfo(image)
CGImageGetBitsPerPixel(image)
CGImageGetBytesPerRow(image)
CGImageGetDataProvider(image)
CGImageGetHeight(image)
CGImageGetWidth(image)
CGImageRelease(image)
CGImageSourceCreateImageAtIndex(isrc, index, options)
CGImageSourceCreateWithDataProvider(provider, options)
CGImageSourceCreateWithURL(url, options)
EndImport
;- Private procedures (Mac)
ProcedureC.i _Start_()
Static Started.i
If Not Started
NSImageCompressionFactor = PeekI(dlsym(-2, "NSImageCompressionFactor"))
NSImageCompressionMethod = PeekI(dlsym(-2, "NSImageCompressionMethod"))
Started = #True
EndIf
ProcedureReturn #True
EndProcedure
ProcedureC _Cleanup_(*Globals.PB_ImageDecoderGlobals)
If *Globals\Data[0]
CGImageRelease(*Globals\Data[0]) : *Globals\Data[0] = #Null
EndIf
EndProcedure
ProcedureC.i _Check_(*Globals.PB_ImageDecoderGlobals)
Protected.i BitmapInfo, Image, ImageSource, Properties, Provider, URL
If *Globals\Mode = 0
; File Mode
URL = CFURLCreateFromFileSystemRepresentation(#Null, *Globals\Filename, strlen(*Globals\Filename), #False)
ImageSource = CGImageSourceCreateWithURL(URL, #Null)
CFRelease(URL)
Else
; Memory Mode
Provider = CGDataProviderCreateWithData(#Null, *Globals\Buffer, *Globals\Length, #Null)
ImageSource = CGImageSourceCreateWithDataProvider(Provider, #Null)
CGDataProviderRelease(Provider)
EndIf
If ImageSource
Image = CGImageSourceCreateImageAtIndex(ImageSource, 0, #Null)
CFRelease(ImageSource)
If Image
BitmapInfo = CGImageGetBitmapInfo(Image)
If BitmapInfo = 3 And CGImageGetBitsPerPixel(Image) = 32
*Globals\Data[2] = CGImageGetBytesPerRow(Image)
Else
*Globals\Data[2] = 0
EndIf
BitmapInfo & $1F
If BitmapInfo > 0 And BitmapInfo < 5
*Globals\Data[1] = #True
*Globals\OriginalDepth = 32
Else
*Globals\Data[1] = #False
*Globals\OriginalDepth = 24
EndIf
*Globals\Data[0] = Image
*Globals\Width = CGImageGetWidth(Image)
*Globals\Height = CGImageGetHeight(Image)
*Globals\Depth = 32
ProcedureReturn #True
EndIf
EndIf
ProcedureReturn #False
EndProcedure
ProcedureC.i _Decode_(*Globals.PB_ImageDecoderGlobals, *Buffer, Pitch.l, Flags.l)
Protected.i ColorSpace, Context, Source
Protected Dim vImg.i(3)
If *Globals\Data[2] = Pitch
Source = CGDataProviderCopyData(CGImageGetDataProvider(*Globals\Data[0]))
EndIf
If Source
CopyMemory(CFDataGetBytePtr(Source), *Buffer, *Globals\Height * Pitch)
CFRelease(Source)
Else
ColorSpace = CGColorSpaceCreateDeviceRGB()
Context = CGBitmapContextCreate(*Buffer, *Globals\Width, *Globals\Height, 8, Pitch, ColorSpace, 1)
CGContextDrawImage(Context, 0, 0, *Globals\Width, *Globals\Height, *Globals\Data[0], 0,0,0,0, 0, 0, *Globals\Width, *Globals\Height)
CGContextRelease(Context)
CGColorSpaceRelease(ColorSpace)
If *Globals\Data[1]; Unpremultiply when original image had an alpha channel
vImg(0) = *Buffer
vImg(1) = *Globals\Height
vImg(2) = *Globals\Width
vImg(3) = Pitch
vImageUnPremultiplyData_RGBA8888(@vImg(), @vImg(), 0)
EndIf
EndIf
_Cleanup_(*Globals)
ProcedureReturn #True
EndProcedure
ProcedureC.i _Encode_(Depth.l, *Filename, *Buffer, Width.l, Height.l, LinePitch.l, Flags.l, EncoderFlags.l, RequestedDepth.l)
Protected.i Provider, ColorSpace, Image, ImageRep, Pool, ImageType, Props, ImageData, Length, Result
Protected FileName.s, Quality.f
Provider = CGDataProviderCreateWithData(#Null, *Buffer, Height * LinePitch, #Null)
ColorSpace = CGColorSpaceCreateDeviceRGB()
If Depth = 32
Image = CGImageCreate(Width, Height, 8, 32, LinePitch, ColorSpace, 3, Provider, #Null, #False, 0)
Else
Image = CGImageCreate(Width, Height, 8, 24, LinePitch, ColorSpace, 0, Provider, #Null, #False, 0)
EndIf
ImageRep = CocoaMessage(0, CocoaMessage(0, 0, "NSBitmapImageRep alloc"), "initWithCGImage:", Image)
CGImageRelease(Image)
CGColorSpaceRelease(ColorSpace)
CGDataProviderRelease(Provider)
If ImageRep
Pool = CocoaMessage(0, 0, "NSAutoreleasePool new")
ImageType = EncoderFlags >> 20 & 7
Select ImageType
Case 0 ; TIFF
Props = CocoaMessage(0, 0, "NSDictionary dictionaryWithObject:",
CocoaMessage(0, 0, "NSNumber numberWithInt:", EncoderFlags >> 16 & 7),
"forKey:", NSImageCompressionMethod)
Case 3 ; JPEG
Quality = 0.01 * JPEGQuality(EncoderFlags)
Props = CocoaMessage(0, 0, "NSDictionary dictionaryWithObject:",
CocoaMessage(0, 0, "NSNumber numberWithFloat:@", @Quality),
"forKey:", NSImageCompressionFactor)
EndSelect
ImageData = CocoaMessage(0, ImageRep, "representationUsingType:", ImageType, "properties:", Props)
If ImageData
If *Filename
; File Mode
FileName = PeekS(*Filename, -1, #PB_UTF8)
Result = CocoaMessage(0, ImageData, "writeToFile:$", @FileName, "atomically:", #NO)
Else
; Memory Mode
Length = CocoaMessage(0, ImageData, "length")
Result = AllocateMemory(Length, #PB_Memory_NoClear)
CocoaMessage(0, ImageData, "getBytes:", Result, "length:", Length)
EndIf
EndIf
CocoaMessage(0, Pool, "release")
CocoaMessage(0, ImageRep, "release")
EndIf
ProcedureReturn Result
EndProcedure
ProcedureC.i _Encode24_(*Filename, *Buffer, Width.l, Height.l, LinePitch.l, Flags.l, EncoderFlags.l, RequestedDepth.l)
ProcedureReturn _Encode_(24, *Filename, *Buffer, Width, Height, LinePitch, Flags, EncoderFlags, RequestedDepth)
EndProcedure
ProcedureC.i _Encode32_(*Filename, *Buffer, Width.l, Height.l, LinePitch.l, Flags.l, EncoderFlags.l, RequestedDepth.l)
ProcedureReturn _Encode_(32, *Filename, *Buffer, Width, Height, LinePitch, Flags, EncoderFlags, RequestedDepth)
EndProcedure
;}
CompilerElseIf #PB_Compiler_OS = #PB_OS_Linux
;{ >>> LINUX <<<
;- Imports (Linux)
ImportC ""
free(ptr)
g_object_ref(object)
g_object_unref(object)
gdk_pixbuf_composite_color_simple(src, dest_width, dest_height, interp_type,
overall_alpha, check_size, color1, color2)
gdk_pixbuf_copy_area(src, src_x, src_y, width, height, dest, dest_x, dest_y)
gdk_pixbuf_get_bits_per_sample(pixbuf)
gdk_pixbuf_get_height(pixbuf)
gdk_pixbuf_get_n_channels(pixbuf)
gdk_pixbuf_get_width(pixbuf)
gdk_pixbuf_loader_close(loader, *error)
gdk_pixbuf_loader_get_pixbuf(loader)
gdk_pixbuf_loader_new()
gdk_pixbuf_loader_write(loader, buf, count, *error)
gdk_pixbuf_new_from_data(*data, colorspace, has_alpha, bits_per_sample,
width, height, rowstride, destroy_fn, destroy_fn_data)
gdk_pixbuf_new_from_file(*filename, *error)
gdk_pixbuf_save(pixbuf, *filename, type.p-ascii, *error, param.p-ascii, value.p-ascii, null = 0)
gdk_pixbuf_save_to_buffer(pixbuf, *buffer, *buffer_size, type.p-ascii, *error, param.p-ascii, value.p-ascii, null = 0)
EndImport
;- Global variables (Linux)
Global Dim Type.s(7)
;- Private procedures (Linux)
ProcedureC.i _Start_()
Static Started.i
If Not Started
Type(0) = "tiff" : Type(1) = "bmp" : Type(2) = "gif" : Type(3) = "jpeg" : Type(4) = "png"
Started = #True
EndIf
ProcedureReturn #True
EndProcedure
ProcedureC _Cleanup_(*Globals.PB_ImageDecoderGlobals)
If *Globals\Data[0]
g_object_unref(*Globals\Data[0]) : *Globals\Data[0] = #Null
EndIf
EndProcedure
ProcedureC.i _Check_(*Globals.PB_ImageDecoderGlobals)
Protected.i Loader, PixBuf
If *Globals\Mode = 0
; File Mode
PixBuf = gdk_pixbuf_new_from_file(*Globals\Filename, #Null)
Else
; Memory Mode
Loader = gdk_pixbuf_loader_new()
gdk_pixbuf_loader_write(Loader, *Globals\Buffer, *Globals\length, #Null)
gdk_pixbuf_loader_close(Loader, #Null)
PixBuf = gdk_pixbuf_loader_get_pixbuf(Loader)
If PixBuf : g_object_ref(PixBuf) : EndIf
g_object_unref(Loader)
EndIf
If PixBuf
*Globals\Data[0] = PixBuf
*Globals\Width = gdk_pixbuf_get_width(PixBuf)
*Globals\Height = gdk_pixbuf_get_height(PixBuf)
*Globals\OriginalDepth = gdk_pixbuf_get_bits_per_sample(PixBuf) * gdk_pixbuf_get_n_channels(PixBuf)
*Globals\Depth = 32
ProcedureReturn #True
EndIf
ProcedureReturn #False
EndProcedure
ProcedureC.i _Decode_(*Globals.PB_ImageDecoderGlobals, *Buffer, Pitch, Flags)
Protected.i Result, PixBuf
PixBuf = gdk_pixbuf_new_from_data(*Buffer, 0, #True, 8, *Globals\Width, *Globals\Height, Pitch, #Null, 0)
If PixBuf
gdk_pixbuf_copy_area(*Globals\Data[0], 0, 0, *Globals\Width, *Globals\Height, PixBuf, 0, 0)
g_object_unref(PixBuf)
Result = #True
EndIf
_Cleanup_(*Globals)
ProcedureReturn Result
EndProcedure
ProcedureC.i _Encode_(HasAlpha, *Filename, *Buffer, Width.l, Height.l, LinePitch.l, Flags.l, EncoderFlags.l, RequestedDepth.l)
Protected.i Result, PixBuf, TPixBuf, ImageType, Error, TBuffer, TBuffer_Size
Protected.s Param, Value
PixBuf = gdk_pixbuf_new_from_data(*Buffer, 0, HasAlpha, 8, Width, Height, LinePitch, #Null, 0)
If PixBuf
ImageType = EncoderFlags >> 20 & 7
If HasAlpha And (ImageType = 1 Or ImageType = 3)
; Try to flatten alpha channel for BMP and JPEG
TPixBuf = gdk_pixbuf_composite_color_simple(PixBuf, Width, Height, 0, 255, 16, $FFFFFFFF, $FFFFFFFF)
If TPixBuf
g_object_unref(PixBuf) : PixBuf = TPixBuf
EndIf
EndIf
Select ImageType
Case 0 ; TIFF
Param = "compression" : Value = Str(EncoderFlags >> 16 & 7)
Case 3 ; JPEG
Param = "quality" : Value = Str(JPEGQuality(EncoderFlags))
EndSelect
If *Filename
; File mode
Result = gdk_pixbuf_save(PixBuf, *Filename, Type(ImageType), @Error, Param, Value)
Else
; Memory mode
If gdk_pixbuf_save_to_buffer(PixBuf, @TBuffer, @TBuffer_Size, Type(EncoderFlags >> 20 & 7), @Error, Param, Value)
Result = AllocateMemory(TBuffer_Size, #PB_Memory_NoClear)
If Result
CopyMemory(TBuffer, Result, TBuffer_Size)
EndIf
free(TBUffer)
EndIf
EndIf
g_object_unref(PixBuf)
EndIf
ProcedureReturn Result
EndProcedure
ProcedureC.i _Encode24_(*Filename, *Buffer, Width.l, Height.l, LinePitch.l, Flags.l, EncoderFlags.l, RequestedDepth.l)
ProcedureReturn _Encode_(#False, *Filename, *Buffer, Width, Height, LinePitch, Flags, EncoderFlags, RequestedDepth)
EndProcedure
ProcedureC.i _Encode32_(*Filename, *Buffer, Width.l, Height.l, LinePitch.l, Flags.l, EncoderFlags.l, RequestedDepth.l)
ProcedureReturn _Encode_(#True, *Filename, *Buffer, Width, Height, LinePitch, Flags, EncoderFlags, RequestedDepth)
EndProcedure
;}
CompilerEndIf
;- Public procedures (all OS)
Procedure ModuleImagePluginStop()
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
If Token
GdiplusShutdown(Token) : Token = 0
EndIf
CompilerEndIf
EndProcedure
Procedure.i UseSystemImageDecoder()
Static SystemImageDecoder.PB_ImageDecoder, Registered.i
If _Start_() And Registered = #False
SystemImageDecoder\ID = #SystemImagePlugin
SystemImageDecoder\Check = @_Check_()
SystemImageDecoder\Cleanup = @_Cleanup_()
SystemImageDecoder\Decode = @_Decode_()
PB_ImageDecoder_Register(SystemImageDecoder)
Registered = #True
EndIf
ProcedureReturn Registered
EndProcedure
Procedure.i UseSystemImageEncoder()
Static SystemImageEncoder.PB_ImageEncoder, Registered.i
If _Start_() And Registered = #False
SystemImageEncoder\ID = #SystemImagePlugin
SystemImageEncoder\Encode24 = @_Encode24_()
SystemImageEncoder\Encode32 = @_Encode32_()
PB_ImageEncoder_Register(SystemImageEncoder)
Registered = #True
EndIf
ProcedureReturn Registered
EndProcedure
EndModule