Results 1 to 7 of 7

Thread: [VB6] GDI+ Workaround: JPG > Zero-Length APP Markers

  1. #1

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    [VB6] GDI+ Workaround: JPG > Zero-Length APP Markers

    Note: Tests of successful loading of the image without applying the workaround have been done on various O/S. This patch may not be required on Win7 and above

    You probably know that GDI+ is useful for loading various image formats, but GDI+ also has issues with every format it loads. For JPGs specifically, if certain APP markers within the file have zero length data then one of two things can happen: 1) image won't load or 2) image loads, but the size reported by GDI+ is 0x0

    The attached txt file is a VB class. After you save it to disk, rename it to .cls
    I've also included a JPG with a zero-length APP marker.

    So, to play.
    1) Download the txt file & rename it .cls
    2) Create a new project and add that class to your project
    3) On the form, add a commandbutton
    4) Paste this code to your form & run project
    5) Drag/drop a JPG onto the form
    Code:
    Option Explicit
    
    Private Declare Function GdipDeleteGraphics Lib "GdiPlus.dll" (ByVal mGraphics As Long) As Long
    Private Declare Function GdipDrawImageRectRectI Lib "GdiPlus.dll" (ByVal hGraphics As Long, ByVal hImage As Long, ByVal dstX As Long, ByVal dstY As Long, ByVal dstWidth As Long, ByVal dstHeight As Long, ByVal srcX As Long, ByVal srcY As Long, ByVal srcWidth As Long, ByVal srcHeight As Long, ByVal srcUnit As Long, ByVal imageAttributes As Long, ByVal Callback As Long, ByVal callbackData As Long) As Long
    Private Declare Function GdipCreateFromHDC Lib "GdiPlus.dll" (ByVal hDC As Long, hGraphics As Long) As Long
    Private Declare Sub GdiplusShutdown Lib "gdiplus" (ByVal Token As Long)
    Private Declare Function GdiplusStartup Lib "gdiplus" (Token As Long, inputbuf As Any, Optional ByVal outputbuf As Long = 0) As Long
    Private Type GdiplusStartupInput
        GdiplusVersion           As Long
        DebugEventCallback       As Long
        SuppressBackgroundThread As Long
        SuppressExternalCodecs   As Long
    End Type
    
    Private m_Token As Long
    Private m_JPG As cJPGreader
    
    Private Sub Form_Load()
        
        Call pvCreateToken
        If m_Token = 0 Or m_Token = -1 Then
            Me.Show
            DoEvents
            MsgBox "Failed to start up GDI+", vbExclamation + vbOKOnly
            Unload Me
            Exit Sub
        End If
        Set m_JPG = New cJPGreader
        
        Me.Move (Screen.Width - 10245) \ 2, (Screen.Height - 6585) \ 2, 10245, 6585
        Me.ScaleMode = vbPixels
        Me.Command1.Move 0, 0
        Me.Command1.Caption = "Refresh"
        Me.OLEDropMode = vbOLEDropManual
    End Sub
    
    Private Sub Form_Unload(Cancel As Integer)
        Set m_JPG = Nothing
        If Not (m_Token = 0& Or m_Token = -1&) Then pvDestroyToken
    End Sub
    
    Private Function pvCreateToken() As Boolean
        Dim GSI As GdiplusStartupInput
        On Error Resume Next
        If Not m_Token = -1 Then
            GSI.GdiplusVersion = 1&
            Call GdiplusStartup(m_Token, GSI)
            If m_Token = 0 Then
                m_Token = -1&
            Else
                pvCreateToken = True
            End If
        End If
    End Function
    
    Private Sub pvDestroyToken()
        If Not (m_Token = 0 Or m_Token = -1) Then GdiplusShutdown m_Token
        m_Token = 0&
    End Sub
    
    Private Sub Command1_Click()
        Call pvRenderImage
    End Sub
    
    Private Sub pvRenderImage()
        If Not m_JPG.Handle = 0& Then
            
            Dim hGraphics As Long, w As Long, h As Long, sngRatio As Single
            Dim x As Long, Y As Long, cx As Long, cy As Long
            Const UnitPixel As Long = 2&
            
            w = m_JPG.Width
            h = m_JPG.Height
            cy = Me.ScaleHeight - Command1.Height
            If Me.ScaleWidth / w > cy / h Then
                sngRatio = cy / h
            Else
                sngRatio = Me.ScaleWidth / w
            End If
            If sngRatio > 1! Then sngRatio = 1&
            cx = w * sngRatio
            cy = h * sngRatio
            x = (Me.ScaleWidth - cx) \ 2
            Y = ((Me.ScaleHeight - Command1.Height) - cy) \ 2 + Command1.Height
            
            Me.Cls
            GdipCreateFromHDC Me.hDC, hGraphics
            GdipDrawImageRectRectI hGraphics, m_JPG.Handle, x, Y, cx, cy, 0, 0, w, h, UnitPixel, 0, 0, 0
            GdipDeleteGraphics hGraphics
        End If
    
    End Sub
    
    Private Sub Form_OLEDragDrop(Data As DataObject, Effect As Long, Button As Integer, Shift As Integer, x As Single, Y As Single)
        If Data.Files.Count Then
            m_JPG.FileName = Data.Files.Item(1)
            Call pvRenderImage
        End If
    End Sub
    See also:
    GDI+ Workaround: TIFF > JPEG-compressed images
    GDI+ Workaround: BMP > Alpha Channels + JPG/PNG Encoded
    GDI+ Workaround: PNG > adding/removing metadata
    GDI+ Workaround: Icons & Cursors
    Attached Files Attached Files
    Last edited by LaVolpe; Dec 12th, 2015 at 04:57 PM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  2. #2
    Fanatic Member
    Join Date
    Aug 2013
    Posts
    806

    Re: [VB6] GDI+ Workaround: JPG > Zero-Length APP Markers

    Okay, this might be annoying - but FYI, on Win 7, GDI+ loads the problematic JPEG without any trouble. I'm afraid I don't have Vista to test v1.1 there, but it looks like Microsoft put some work into fixing some of these issues somewhere between XP and Win 7. Good for them, I guess??
    Check out PhotoDemon, a pro-grade photo editor written completely in VB6. (Full source available at GitHub.)

  3. #3

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: [VB6] GDI+ Workaround: JPG > Zero-Length APP Markers

    Not exactly shocked. Many of these GDI+ shortcomings were discussed in hundreds of forums and MS received hundreds of bug reports from coders. For my purposes of creating an image control, it is even more annoying for me. Depending on the target O/S, some shortfalls are still active while others are not. And it's not like the workarounds are simple one-liners either. This will be something I'll have to think about: without relying on the O/S version, identifying whether a workaround is needed and set on/off switches to apply them if needed.

    Thanx for the Win7/Win8 results for the various posts I put up. I do have Win7 on a laptop, but don't have access to it on a regular basis. I have no Win8 access.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  4. #4
    Hyperactive Member
    Join Date
    Sep 2014
    Posts
    373

    Re: [VB6] GDI+ Workaround: JPG > Zero-Length APP Markers

    Just a little clarification, GDIplus loads a JPEG alright when it is with an empty marker, if Length field is not entered with "2". It would accept it if Length field is entered "0".

    I've checked that the file you uploaded is a perfectly valid one; although it has an empty marker, its Lengh entry is correctly entered. Thus the conclusion to be drawn appears to be:

    (i) GDIplus would reject a JPEG with an empty marker when its Length field is correctly entered as "2".

    (ii) GDIplus would accept a JPEG with an empty marker if its Length field is incorrectly entered as "0". This is true even on Win 7.

    Attached ZIP contains a JPEG, modified from yours (the only modification is to change Length entry from "2" to "0"), you would be able to load it without a problem, albeit its Length field entry is not a proper one.
    Attached Files Attached Files
    Last edited by Brenker; Feb 16th, 2015 at 03:05 PM. Reason: Add a remark to "ii"

  5. #5

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: [VB6] GDI+ Workaround: JPG > Zero-Length APP Markers

    @Brenker. This is not necessarily true with GDI+ versions shipped on Vista and earlier
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  6. #6
    Hyperactive Member
    Join Date
    Sep 2014
    Posts
    373

    Re: [VB6] GDI+ Workaround: JPG > Zero-Length APP Markers

    LaVolpe,

    I said what I said because I had already tested it on both Vista and Win 7.

    The screenshot shows the specific path of GDIplus used on Vista (not designated by my program), and its actual version No. Because both are long, hence screenshot.

    The above is just for a bit of fun, and to highlight the funny behaviour of GDIplus concerning the subject file. Removal of the empty marker is preferred, if one bothers.
    Attached Images Attached Images  

  7. #7

    Thread Starter
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: [VB6] GDI+ Workaround: JPG > Zero-Length APP Markers

    And I wouldn't have made the claim if I didn't experience it... Look at the screen shot, the property sheet on the left is the jpg loaded with pure GDI+, the one the right is loaded by VB's LoadPicture. Note that the image did load in GDI+, it reported 0x0 dimensions and therefore does not render with GDI+. It depends on what version happens to be on the system... When manifested, that GDI+ version won't even load the JPG.

    Name:  zJpg.jpg
Views: 463
Size:  37.3 KB
    Last edited by LaVolpe; Feb 16th, 2015 at 11:08 PM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width