Announcement

Collapse
No announcement yet.

Png and Tiff files

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    Png and Tiff files

    I have been exploring adding Tiff and Png files to an image processing program that I have developed. I am particularly interested in 16 bpp grayscale and 48 bpp color versions. I decided to try GDI+ despite Jose Roca's caution that GDI+ did not handle these versions properly. I hoped that I might be able to just use GDI+ to load the file, and then grab the bytes in memory without doing any further processing in GDI+. What I found is that this approach worked fine for 8 bpp images, but not at all for 16 bpp grayscale or 48 bpp color. In the latter cases the image bytes seem to get rescaled to use only about 6 of the available 256 levels. The code follows, and what I would like to know is whether someone could suggest an alternative approach or work-around that might preserve the high dynamic range images?

    Ken German
    Code:
    '#####################
    [FONT=MS Mincho][FONT=Courier New]Public Function Open_Tif_Png(imageData As String, Index As Integer) As Boolean[/FONT][/FONT]
    
    [FONT=MS Mincho][FONT=Courier New]Dim I As Long, J As Long, K As Long    'index variables[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]Dim statusNow As GpStatus[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]Dim gdipBeginInfo As GdiplusStartupInput[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]Dim gdipToken As Long           'created at GDI+ start, used to close GDI+[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]Dim bmpData As BitmapData       'data structure from GDI+ lock[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]Dim ptrBmp As Long              'pointer from GDI+ file read[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]Dim nuRect As RECTL             'rectangular picture structure of locked data[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]Dim xWidth As Single            'image width in pixels[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]Dim yHeight As Single           'image height in pixels[/FONT][/FONT]
    
    [FONT=MS Mincho][FONT=Courier New]Dim ptrBitmapData As Long       'pointer RECTL data[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]Dim xStride As Long             'width*bytesperpixel padded/4 [/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]Dim pixFormat As Long           'return from GetPixelImageFormat[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]Dim bytePerPixel As Long        'name says it all[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]Dim byteArray() As Byte         'memory block for image data[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]Dim datalength As Long          'ubound of byteArray[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]'######################[/FONT][/FONT]
    
    [FONT=MS Mincho][FONT=Courier New]gdipBeginInfo.DebugEventCallback = 0[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]gdipBeginInfo.GdiplusVersion = 1[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]gdipBeginInfo.SuppressBackgroundThread = 0[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]gdipBeginInfo.SuppressExternalCodecs = 0[/FONT][/FONT]
    
    [FONT=MS Mincho][FONT=Courier New]    'Start GDI+[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]    statusNow = GdiplusStartup(gdipToken, gdipBeginInfo)[/FONT][/FONT]
    
    [FONT=MS Mincho][FONT=Courier New]    'Load file[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]    statusNow = GdipCreateBitmapFromFile(StrPtr(imageData), ptrBmp)[/FONT][/FONT]
    
    [FONT=MS Mincho][FONT=Courier New]    'Get width and height of image[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]    statusNow = GdipGetImageDimension(ptrBmp, xWidth, yHeight)[/FONT][/FONT]
    
    [FONT=MS Mincho][FONT=Courier New]    'Set size of image data to be opened for read[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]    nuRect.Height = yHeight[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]    nuRect.left = 0[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]    nuRect.top = 0[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]    nuRect.Width = xWidth[/FONT][/FONT]
    
    [FONT=MS Mincho][FONT=Courier New]   'get pixel format of opened image[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]    statusNow = GdipGetImagePixelFormat(ptrBmp, pixFormat)[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]    'lock bitmap data for reading[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]    statusNow = GdipBitmapLockBits(ptrBmp, nuRect, ImageLockModeRead, pixFormat, bmpData)[/FONT][/FONT]
    
    [FONT=MS Mincho][FONT=Courier New]    xStride = Abs(bmpData.Stride)   'negative means inverted [/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]    ptrBitmapData = bmpData.Scan0Ptr[/FONT][/FONT]
    
    [FONT=MS Mincho][FONT=Courier New]    Select Case pixFormat[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]        Case 137224             [/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]            '%PixelFormat24bppRGB                   [/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]            bytePerPixel = 3[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]        Case 198659             [/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]            '%PixelFormat8bppIndexed    [/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]            bytePerPixel = 1[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]        Case 2498570            [/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]            '%PixelFormat32bppARGB      [/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]            bytePerPixel = 4[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]        Case 1060876            [/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]            '%PixelFormat48bppRGB       [/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]            bytePerPixel = 6[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]        Case Else[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]            'Quit[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]            Screen.MousePointer = vbDefault[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]            MsgBox "Unrecognized pixel format!", vbOKOnly, "FILE READ ERROR"[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]            statusNow = GdipBitmapUnlockBits(ptrBmp, bmpData)[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]            statusNow = GdipDisposeImage(ptrBmp)[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]            statusNow = GdipDisposeImage(ptrBmp)[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]            Exit Function[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]        End Select[/FONT][/FONT]
    
    [FONT=MS Mincho][FONT=Courier New]    datalength = xStride * yHeight - 1[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]    ReDim byteArray(datalength)[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]    CopyMemory byteArray(0), ptrBitmapData, datalength[/FONT][/FONT]
    
    [FONT=MS Mincho][FONT=Courier New]'following code creates an image from byteArray() and closes GDI+ functions neatly but has no impact on the stated problem[/FONT][/FONT]
     
    [FONT=MS Mincho][FONT=Courier New]'##########################################[/FONT][/FONT]
    'The above code is actually the VB6 prototype and would be modified appropriatly before proceeding to the PB DLL
    Last edited by Gary Beene; 25 Jul 2014, 11:28 PM. Reason: Code: tags

    #2
    Since nobody had a suggestion I'll close this thread with my own solution. The solution is to forget about GDI+ and switch to FreeImage. With the exception of FITS, FreeImage can handle almost every useful image format and pixel depth. The only disadvantages are that the DLL is larger than GDI+ and the documentation makes the Windows API look verbose by comparison. For the problem of reading 16 and 48 bpp formats into memory the following code is even simpler than the GDI+ version.
    Code:
    '-------------------------------------------------
    [FONT=MS Mincho][FONT=Courier New]Public Function Open_Tif_Png(imageName As String, Index As Integer) As Boolean[/FONT][/FONT]
    
    [FONT=MS Mincho][FONT=Courier New]Dim xWidth As Single                    'image width in pixels[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]Dim yHeight As Single                   'image height in pixels[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]Dim ptrBitmapData As Long           'pointer to dib from FI Load[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]Dim ptrDIB As Long                       'pointer to dib data[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]Dim xStride As Long                      'width*bytesperpixel padded to mod 4[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]Dim pixFormat As Long                  'return from GetPixelImageFormat[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]Dim bytePerPixel As Long              'name says it all[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]Dim byteArray() As Byte                 'memory block for receiving pixel stream[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]Dim datalength As Long                 'ubound of byteArray[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]Dim ext As String                            'file extension of imageName[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]'######################[/FONT][/FONT]
    
    [FONT=MS Mincho][FONT=Courier New]ext = Right$(imageName, 3)[/FONT][/FONT]
    
    [FONT=MS Mincho][FONT=Courier New]    'Start FreeImage.DLL[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]    Call FreeImage_Initialise(0)[/FONT][/FONT]
    
    [FONT=MS Mincho][FONT=Courier New]    Select Case ext[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]        Case "tif", "TIF"[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]            ptrDIB = FreeImage_Load(FIF_TIFF, imageName)[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]        Case "png", "PNG"[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]            ptrDIB = FreeImage_Load(FIF_PNG, imageName)[/FONT][/FONT]
    
    [FONT=MS Mincho][FONT=Courier New]        Case Else[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]            Screen.MousePointer = vbDefault[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]            MsgBox "Unrecognized file extension.", vbOKOnly, "READ ERROR"[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]            GoTo close1[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]    End Select[/FONT][/FONT]
    
    [FONT=MS Mincho][FONT=Courier New]    If ptrDIB = 0 Then[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]        Screen.MousePointer = vbDefault[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]        MsgBox imageName & " failed to open.", vbOKOnly, "READ ERROR"[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]        Call FreeImage_DeInitialise[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]        Exit Function[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]    End If[/FONT][/FONT]
    
    [FONT=MS Mincho][FONT=Courier New]    bytePerPixel = FreeImage_GetBPP(ptrDIB) \ 8[/FONT][/FONT]
    
    [FONT=MS Mincho][FONT=Courier New]    'Get image size and dimension VB byteArray for memory copy[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]    xWidth = FreeImage_GetWidth(ptrDIB)[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]    yHeight = FreeImage_GetHeight(ptrDIB)[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]    xStride = FreeImage_GetPitch(ptrDIB)[/FONT][/FONT]
    
    [FONT=MS Mincho][FONT=Courier New]    datalength = xStride * yHeight - 1[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]    ReDim byteArray(datalength)[/FONT][/FONT]
    
    [FONT=MS Mincho][FONT=Courier New]    'Get data pointer and copy memory[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]    ptrBitmapData = FreeImage_GetBits(ptrDIB)[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]    CopyMemory byteArray(0), ptrBitmapData, datalength[/FONT][/FONT]
    
    [FONT=MS Mincho][FONT=Courier New]'at this point the image data is in byteArray and can be manipulated directly[/FONT][/FONT]
    [FONT=MS Mincho][FONT=Courier New]'or converted to a matrix for convolutions etc.[/FONT][/FONT]
     
    [FONT=MS Mincho][FONT=Courier New]'To avoid a memory leak FreeImage has to be deinitialised and the bitmap killed before the function concludes just as for GDI+[/FONT][/FONT]
    Ken German
    Last edited by Gary Beene; 25 Jul 2014, 11:29 PM. Reason: Code: tags

    Comment

    Working...
    X
    😀
    🥰
    🤢
    😎
    😡
    👍
    👎