Page 1 of 1

Windows Imaging Component

Posted: Thu Sep 08, 2016 6:04 pm
by wilbert
While looking for ways to encode images, I also encountered WIC.
I was curious about it and ported an example
https://msdn.microsoft.com/en-us/library/windows/desktop/ee719871(v=vs.85).aspx#tiffencoding
Maybe it's interesting for someone.

Include file

Code: Select all

; >>> Constants <<<

Enumeration
  #WICDecodeMetadataCacheOnDemand
  #WICDecodeMetadataCacheOnLoad
EndEnumeration
  
Enumeration
  #WICBitmapEncoderCacheInMemory
  #WICBitmapEncoderCacheTempFile
  #WICBitmapEncoderNoCache
EndEnumeration

Enumeration
  #WICBitmapUseAlpha
  #WICBitmapUsePremultipliedAlpha
  #WICBitmapIgnoreAlpha
EndEnumeration

Enumeration
  #WICBitmapPaletteTypeCustom
  #WICBitmapPaletteTypeMedianCut
  #WICBitmapPaletteTypeFixedBW
  #WICBitmapPaletteTypeFixedHalftone8
  #WICBitmapPaletteTypeFixedHalftone27
  #WICBitmapPaletteTypeFixedHalftone64
  #WICBitmapPaletteTypeFixedHalftone125
  #WICBitmapPaletteTypeFixedHalftone216
  #WICBitmapPaletteTypeFixedWebPalette = 7
  #WICBitmapPaletteTypeFixedHalftone252
  #WICBitmapPaletteTypeFixedHalftone256
  #WICBitmapPaletteTypeFixedGray4
  #WICBitmapPaletteTypeFixedGray16
  #WICBitmapPaletteTypeFixedGray256
EndEnumeration

Enumeration
  #WICBitmapDitherTypeNone
  #WICBitmapDitherTypeSolid = 0
  #WICBitmapDitherTypeOrdered4x4
  #WICBitmapDitherTypeOrdered8x8
  #WICBitmapDitherTypeOrdered16x16
  #WICBitmapDitherTypeSpiral4x4
  #WICBitmapDitherTypeSpiral8x8
  #WICBitmapDitherTypeDualSpiral4x4
  #WICBitmapDitherTypeDualSpiral8x8
  #WICBitmapDitherTypeErrorDiffusion
EndEnumeration

Enumeration
  #WICTiffCompressionDontCare
  #WICTiffCompressionNone
  #WICTiffCompressionCCITT3
  #WICTiffCompressionCCITT4
  #WICTiffCompressionLZW
  #WICTiffCompressionRLE
  #WICTiffCompressionZIP
  #WICTiffCompressionLZWHDifferencing
EndEnumeration


; >>> Structures <<<

Structure PROPBAG2 Align #PB_Structure_AlignC
  dwType.l
  vt.u
  cfType.u
  dwHint.l
  *pstrName
  clsid.CLSID
EndStructure


; >>> Interfaces <<<

Interface IWICImagingFactory Extends IUnknown
  CreateDecoderFromFilename(wzFilename.p-unicode, *pguidVendor, dwDesiredAccess,  metadataOptions, *ppIDecoder)
  CreateDecoderFromStream(*pIStream, *pguidVendor, metadataOptions, *ppIDecoder)
  CreateDecoderFromFileHandle(hFile, *pguidVendor, metadataOptions, *ppIDecoder)
  CreateComponentInfo(clsidComponent, *ppIInfo)
  CreateDecoder(guidContainerFormat, *pguidVendor, *ppIDecoder)
  CreateEncoder(guidContainerFormat, *pguidVendor, *ppIEncoder)
  CreatePalette(*ppIPalette)
  CreateFormatConverter(*ppIFormatConverter)
  CreateBitmapScaler(*ppIBitmapScaler)
  CreateBitmapClipper(*ppIBitmapClipper)
  CreateBitmapFlipRotator(*ppIBitmapFlipRotator)
  CreateStream(*ppIWICStream)
  CreateColorContext(*ppIWICColorContext)
  CreateColorTransformer(*ppIWICColorTransform)
  CreateBitmap(uiWidth, uiHeight, pixelFormat, option, *ppIBitmap)
  CreateBitmapFromSource(*piBitmapSource, option, *ppIBitmap)
  CreateBitmapFromSourceRect(*piBitmapSource, x, y, width, height, *ppIBitmap)
  CreateBitmapFromMemory(uiWidth, uiHeight, pixelFormat, cbStride, cbBufferSize, *pbBuffer, *ppIBitmap)
  CreateBitmapFromHBITMAP(hBitmap, hPalette, options, *ppIBitmap)
  CreateBitmapFromHICON(hIcon, *ppIBitmap)
  CreateComponentEnumerator(componentTypes, options, *ppIEnumUnknown)
  CreateFastMetadataEncoderFromDecoder(*pIDecoder, *ppIFastEncoder)
  CreateFastMetadataEncoderFromFrameDecode(*pIFrameDecoder, *ppIFastEncoder)
  CreateQueryWriter(guidMetadataFormat, *pguidVendor, *ppIQueryWriter)
  CreateQueryWriterFromReader(*pIQueryReader, *pguidVendor, *ppIQueryWriter)
EndInterface

Interface IWICStream Extends IStream
  InitializeFromIStream(Stream.IStream)
  InitializeFromFilename(Filename.p-unicode, AccessMode.l)
  InitializeFromMemory(*Buffer, BufferSize.l)
  InitializeFromIStreamRegion(Stream.IStream, Offset.q, MaxSize.q)
EndInterface

Interface IWICBitmapSource Extends IUnknown
  GetSize(*puiWidth, *puiHeight)
  GetPixelFormat(*pPixelFormat)
  GetResolution(*pDpiX, *pDpiY)
  CopyPalette(*pIPalette)
  CopyPixels(*prc, cbStride, cbBufferSize, *pbBuffer)
EndInterface

Interface IWICBitmap Extends IWICBitmapSource
  Lock(*prcLock, flags, *ppILock)
  SetPalette(*pIPalette)
  SetResolution(dpiX.d, dpiY.d)
EndInterface

Interface IWICFormatConverter Extends IWICBitmapSource
  Initialize(*pISource, dstFormat, dither, *pIPalette, alphaThresholdPercent.d, paletteTranslate)
  CanConvert(srcPixelFormat, dstPixelFormat, *pfCanConvert)
EndInterface

Interface IWICPalette Extends IUnknown
  InitializePredefined(ePaletteType, fAddTransparentColor)
  InitializeCustom(*pColors, colorCount)
  InitializeFromBitmap(*pISurface, colorCount, fAddTransparentColor)
  InitializeFromPalette(*pIPalette)
  GetType(*pePaletteType)
  GetColorCount(*pcCount)
  GetColors(colorCount, *pColors, *pcActualColors)
  IsBlackWhite(*pfIsBlackWhite)
  IsGrayscale(*pfIsGrayscale)
  HasAlpha(*pfHasAlpha)
EndInterface

Interface IWICBitmapDecoder Extends IUnknown
  QueryCapability(*pIStream, *pdwCapability)
  Initialize(*pIStream, cacheOptions)
  GetContainerFormat(*pguidContainerFormat)
  GetDecoderInfo(*ppIDecoderInfo)
  CopyPalette(*pIPalette)
  GetMetadataQueryReader(*ppIMetadataQueryReader)
  GetPreview(*ppIBitmapSource)
  GetColorContexts(cCount, *ppIColorContexts, *pcActualCount)
  GetThumbnail(*ppIThumbnail)
  GetFrameCount(*pCount)
  GetFrame(index, *ppIBitmapFrame)
EndInterface

Interface IWICBitmapEncoder Extends IUnknown
  Initialize(*pIStream, cacheOption)
  GetContainerFormat(*pguidContainerFormat)
  GetEncoderInfo(*ppIEncoderInfo)
  SetColorContexts(cCount,  *ppIColorContext)
  SetPalette(*pIPalette)
  SetThumbnail(*pIThumbnail)
  SetPreview(*pIPreview)
  CreateNewFrame(*ppIFrameEncode, *ppIEncoderOptions)
  Commit()
  GetMetadataQueryWriter(*ppIMetadataQueryWriter)
EndInterface

Interface IWICBitmapFrameDecode Extends IWICBitmapSource
  GetMetadataQueryReader(*ppIMetadataQueryReader)
  GetColorContexts(cCount, *ppIColorContexts, *pcActualCount)
  GetThumbnail(*ppIThumbnail)
EndInterface

Interface IWICBitmapFrameEncode Extends IUnknown
  Initialize(*pIEncoderOptions)
  SetSize(uiWidth, uiHeight)
  SetResolution(dpiX.d, dpiY.d)
  SetPixelFormat(*pPixelFormat)
  SetColorContexts(cCount, *ppIColorContext)
  SetPalette(*pIPalette)
  SetThumbnail(*pIThumbnail)
  WritePixels(lineCount, cbStride, cbBufferSize, *pbPixels)
  WriteSource(*pIBitmapSource, *prc)
  Commit()
  GetMetadataQueryWriter(*ppIMetadataQueryWriter)
EndInterface


; >>> Imports <<<

CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
  Import ""
    MakeBSTR(str.p-unicode) As "_SysAllocString"
  EndImport
CompilerElse
  Import ""
    MakeBSTR(str.p-unicode) As "SysAllocString"
  EndImport
CompilerEndIf


; >>> Macros <<<

Macro SafeRelease(obj)
  If obj : obj\Release() : EndIf
EndMacro

Macro Define_ID(label,l1,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)
  label:
  !dd l1
  !dw w1,w2
  !db b1,b2,b3,b4,b5,b6,b7,b8
EndMacro


; >>> Data Section <<<

DataSection
  
  Define_ID(CLSID_WICImagingFactory        , 0xcacaf262, 0x9370, 0x4615, 0xa1, 0x3b, 0x9f, 0x55, 0x39, 0xda, 0x4c, 0x0a)
  Define_ID(IID_IWICImagingFactory         , 0xec5ec8a9, 0xc395, 0x4314, 0x9c, 0x77, 0x54, 0xd7, 0xa9, 0x35, 0xff, 0x70)
  ; Container formats
  Define_ID(GUID_ContainerFormatAdng       , 0xf3ff6d0d, 0x38c0, 0x41c4, 0xb1, 0xfe, 0x1f, 0x38, 0x24, 0xf1, 0x7b, 0x84)
  Define_ID(GUID_ContainerFormatBmp        , 0x0af1d87e, 0xfcfe, 0x4188, 0xbd, 0xeb, 0xa7, 0x90, 0x64, 0x71, 0xcb, 0xe3)
  Define_ID(GUID_ContainerFormatPng        , 0x1b7cfaf4, 0x713f, 0x473c, 0xbb, 0xcd, 0x61, 0x37, 0x42, 0x5f, 0xae, 0xaf)
  Define_ID(GUID_ContainerFormatIco        , 0xa3a860c4, 0x338f, 0x4c17, 0x91, 0x9a, 0xfb, 0xa4, 0xb5, 0x62, 0x8f, 0x21)
  Define_ID(GUID_ContainerFormatJpeg       , 0x19e4a5aa, 0x5662, 0x4fc5, 0xa0, 0xc0, 0x17, 0x58, 0x02, 0x8e, 0x10, 0x57)
  Define_ID(GUID_ContainerFormatTiff       , 0x163bcc30, 0xe2e9, 0x4f0b, 0x96, 0x1d, 0xa3, 0xe9, 0xfd, 0xb7, 0x88, 0xa3)
  Define_ID(GUID_ContainerFormatGif        , 0x1f8a5601, 0x7d4d, 0x4cbd, 0x9c, 0x82, 0x1b, 0xc8, 0xd4, 0xee, 0xb9, 0xa5)
  Define_ID(GUID_ContainerFormatWmp        , 0x57a37caa, 0x367a, 0x4540, 0x91, 0x6b, 0xf1, 0x83, 0xc5, 0x09, 0x3a, 0x4b)
  ; Pixel formats
  Define_ID(GUID_WICPixelFormat8bppIndexed , 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x04)
  Define_ID(GUID_WICPixelFormat8bppGray    , 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x08)
  Define_ID(GUID_WICPixelFormat24bppBGR    , 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0c)
  Define_ID(GUID_WICPixelFormat32bppBGRA   , 0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0f)
  
EndDataSection
Ported example

Code: Select all

; >>> Ported example code <<<

Factory.IWICImagingFactory
Encoder.IWICBitmapEncoder
BitmapFrame.IWICBitmapFrameEncode
PropertyBag.IPropertyBag2

Stream.IWICStream
Width = 640
Height = 480

If CoInitializeEx_(0,2)&-2 = 0
  uninit = #True
EndIf

hr = CoCreateInstance_(?CLSID_WICImagingFactory, #Null, #CLSCTX_INPROC_SERVER, ?IID_IWICImagingFactory, @Factory)

If hr = 0
  hr = Factory\CreateStream(@Stream.IWICStream)
EndIf

If hr = 0
  hr = Stream\InitializeFromFilename("output.tif", #GENERIC_WRITE)
EndIf

If hr = 0
  hr = Factory\CreateEncoder(?GUID_ContainerFormatTiff, #Null, @Encoder.IWICBitmapEncoder)
EndIf

If hr = 0
  hr = Encoder\Initialize(Stream, #WICBitmapEncoderNoCache)
EndIf

If hr = 0
  Encoder\CreateNewFrame(@BitmapFrame.IWICBitmapFrameEncode, @PropertyBag.IPropertyBag2)
EndIf

If hr = 0
  ; This is how you customize the TIFF output.
  Option.PROPBAG2
  Option\pstrName = MakeBSTR("TiffCompressionMethod")
  VarValue.VARIANT
  VariantInit_(@VarValue)
  VarValue\vt = #VT_UI1
  VarValue\bVal = #WICTiffCompressionZIP
  hr = PropertyBag\Write(1, @Option, @VarValue)
  SysFreeString_(Option\pstrName)
  If hr = 0
    hr = BitmapFrame\Initialize(PropertyBag)
  EndIf
EndIf

If hr = 0
  hr = BitmapFrame\SetSize(Width, Height)
EndIf

CopyStructure(?GUID_WICPixelFormat24bppBGR, @FormatGUID.GUID, GUID)
If hr = 0
  hr = BitmapFrame\SetPixelFormat(@FormatGUID)
EndIf

If hr = 0
  ; We're expecting to write out 24bppRGB. Fail if the encoder cannot do it.
  hr = Bool(CompareMemory(@FormatGUID, ?GUID_WICPixelFormat24bppBGR, 16) = 0)
EndIf

If hr = 0
  Stride = (Width * 24 + 7)/8;***WICGetStride***
  BufferSize = Height * Stride
  *Buffer = AllocateMemory(BufferSize)
  *BufferPtr.Byte = *Buffer

  If *Buffer <> #Null
    For i = 0 To BufferSize - 1
      *BufferPtr\b = Random(255)
      *BufferPtr + 1
    Next
    
    hr = BitmapFrame\WritePixels(Height, Stride, BufferSize, *Buffer)

    FreeMemory(*Buffer)
  Else
    hr = #E_OUTOFMEMORY
  EndIf
EndIf

If hr = 0
  hr = BitmapFrame\Commit()
EndIf

If hr = 0
  hr = Encoder\Commit()
EndIf

If Factory
  Factory\Release()
EndIf

If BitmapFrame
  BitmapFrame\Release()
EndIf

If Encoder
  Encoder\Release()
EndIf

If Stream
  Stream\Release()
EndIf

If hr = 0
  MessageRequester("TIFF encoding example", "TIFF file succesfully written")
Else  
  MessageRequester("TIFF encoding example", "An error has occured")
EndIf

If uninit
  CoUninitialize_()
EndIf

Re: Windows Imaging Component

Posted: Sat Sep 10, 2016 6:24 am
by wilbert
GIF encoding example

Code: Select all

; >>> GIF encoding example <<<

; Load an image.
UsePNGImageDecoder()
LoadImage(0, "myImage.png")
Width = ImageWidth(0)
Height = ImageHeight(0)

If CoInitializeEx_(0,2)&-2 = 0
  uninit = #True
EndIf

hr = CoCreateInstance_(?CLSID_WICImagingFactory, #Null, #CLSCTX_INPROC_SERVER, ?IID_IWICImagingFactory, @Factory.IWICImagingFactory)

If hr = #S_OK
  ; Create Stream, Encoder, Palette, Bitmap and FormatConverter objects.
  hr | Factory\CreateStream(@Stream.IWICStream)
  hr | Factory\CreateEncoder(?GUID_ContainerFormatGif, #Null, @Encoder.IWICBitmapEncoder)
  hr | Factory\CreatePalette(@Palette.IWICPalette)
  hr | Factory\CreateBitmapFromHBITMAP(ImageID(0), #Null, #WICBitmapUseAlpha, @Bitmap.IWICBitmap)
  hr | Factory\CreateFormatConverter(@FormatConverter.IWICFormatConverter)
EndIf

If hr = #S_OK
  ; Initialize stream and encoder.
  hr | Stream\InitializeFromFilename("output.gif", #GENERIC_WRITE)
  hr | Encoder\Initialize(Stream, #WICBitmapEncoderNoCache)
  ; Create new frame.
  hr | Encoder\CreateNewFrame(@BitmapFrame.IWICBitmapFrameEncode, @PropertyBag.IPropertyBag2)
  ; Convert the bitmap to 8bppIndexed.
  hr | Palette\InitializeFromBitmap(Bitmap, 256, #True)
  hr | FormatConverter\Initialize(Bitmap, ?GUID_WICPixelFormat8bppIndexed, #WICBitmapDitherTypeErrorDiffusion,
                                  Palette, 50, #WICBitmapPaletteTypeCustom)
EndIf

; Release the Bitmap object as it isn't needed anymore.
SafeRelease(Bitmap)

If hr = #S_OK
  ; Initialize bitmap frame and set size.
  hr | BitmapFrame\Initialize(PropertyBag)
  hr | BitmapFrame\SetSize(Width, Height)
  ; Try to set pixel format to 8bppIndexed.
  CopyMemory(?GUID_WICPixelFormat8bppIndexed, @FormatGUID.GUID, 16)
  hr | BitmapFrame\SetPixelFormat(@FormatGUID)
  ; Check if the format could be set.
  hr | Bool(CompareMemory(@FormatGUID, ?GUID_WICPixelFormat8bppIndexed, 16) = 0)
EndIf

If hr = #S_OK
  ; Write and commit.
  hr | BitmapFrame\WriteSource(FormatConverter, #Null)
  hr | BitmapFrame\Commit()
  hr | Encoder\Commit()
EndIf

; Release the objects
SafeRelease(BitmapFrame)
SafeRelease(Palette)
SafeRelease(FormatConverter)
SafeRelease(Encoder)
SafeRelease(Stream)
SafeRelease(Factory)

If hr = 0
  MessageRequester("GIF encoding example", "GIF file succesfully written")
Else  
  MessageRequester("GIF encoding example", "An error has occured")
EndIf

If uninit
  CoUninitialize_()
EndIf

Re: Windows Imaging Component

Posted: Sat Sep 10, 2016 7:02 am
by es_91
Dear wilbert,

without digging your code now, i think it is great work and important. But how is it with the .gif format, are not still there patents or something fuzzy on it?

Program brings errors but i'll take a deeper look, later. Thank you very much.

:D

Re: Windows Imaging Component

Posted: Sat Sep 10, 2016 7:15 am
by wilbert
es_91 wrote:But how is it with the .gif format, are not still there patents or something fuzzy on it?
To be honest, I don't know how it is with the patents.
I assumed using the encoder that is built into Windows would be fine :?
es_91 wrote:Program brings errors but i'll take a deeper look, later. Thank you very much.
I tested it with PB 5.42 on Windows 10.

Re: Windows Imaging Component

Posted: Sat Sep 10, 2016 7:46 am
by es_91
Should all be fine. I did not look close enough. Again, thanks. 8) I always loved .gif for when you reconvert it to .bmp (8 bit using palette, which it then - after being .gif - does by default*) and compress it with LZMA/zip it's smaller than .png and better than .jpg to my experience and opinion.

Tough little file format.

(* in smart conversion tools such as paint.net)

Re: Windows Imaging Component

Posted: Sun Sep 11, 2016 11:09 am
by netmaestro
The last GIF patent to expire was IBM's in 2006. There have not been any patent holders for the GIF format for ten years. With virtually everyone using the format these days, the web is replete with uncounted millions of the things and if anyone were to claim copyright ownership on them, everyone would know all about it within a matter of hours. But patent database searches done by GNU and SFLC have turned up nothing past 2006, and with ten quiet years of steady proliferation behind us, I think we can all relax and stop looking over our shoulders for the GIF bogeyman. Good heavens, if that creature were to ever rear its ugly head it would give poor KCC a heart attack.

Re: Windows Imaging Component

Posted: Sun Sep 11, 2016 8:00 pm
by VB6_to_PBx
Good heavens, if that creature were to ever rear its ugly head it would give poor KCC a heart attack.
+ 1000

:D

Re: Windows Imaging Component

Posted: Tue Sep 13, 2016 10:07 am
by Kwai chang caine
MasterFrog wrote:Good heavens, if that creature were to ever rear its ugly head it would give poor KCC a heart attack.
:lol: :lol:

Don't worry for me, kind master of the net.... 8)
For the bad creature i have him :mrgreen:

Image

Re: Windows Imaging Component

Posted: Tue Sep 13, 2016 10:12 am
by Kwai chang caine
Thanks WILBERT i have tested your code, and it works very well 8)

Re: Windows Imaging Component

Posted: Thu Sep 22, 2016 7:00 pm
by es_91
Thanks netmaestro for the info on .gif. Much appreciated!

Now since 8 bit looks dirty on larger images, is there a way to use .gif with a slightly higher (10, )12(, 14) or 16 bits resolution?

And, in case, if not is .png the only way to store 16 bit images in a such-similar matter? (no .jpeg here, please.)

( edited )