Page 1 of 1

Flippin' Images

Posted: Wed Oct 14, 2009 3:18 pm
by blueb
There have been a great deal of changes in the image libs, etc.

I found some code in CodeArchiv that did what I wanted (I believe it was by Freak), except that the images are now upside down in 4.40.

Code: Select all

Procedure GetShellThumbnail(FileName$, Image, Width, Height, Depth = #PB_Image_DisplayFormat) 
  Protected Result = 0, ImageResult 
  Protected Desktop.IShellFolder, Folder.IShellFolder 
  Protected Extract.IExtractImage 
  Protected *pidlFolder.ITEMIDLIST, *pidlFile.ITEMIDLIST  
  Protected Priority, Flags, Bitmap = 0, size.SIZE 

  If SHGetDesktopFolder_(@Desktop) >= 0 
    If Desktop\ParseDisplayName(#Null, #Null, GetPathPart(FileName$), #Null, @*pidlFolder, #Null) = #S_OK 
      If Desktop\BindToObject(*pidlFolder, #Null, ?IID_IShellFolder, @Folder) = #S_OK 
        If Folder\ParseDisplayName(#Null, #Null, GetFilePart(FileName$) , #Null, @*pidlFile, #Null) = #S_OK 
          If Folder\GetUIObjectOf(#Null, 1, @*pidlFile, ?IID_IExtractImage, 0, @Extract) = #S_OK 

            ImageResult = CreateImage(Image, Width, Height, Depth) 
            If ImageResult 
              If Image = #PB_Any 
                Image = ImageResult 
              EndIf    
              If Depth = #PB_Image_DisplayFormat 
                Depth = ImageDepth(Image) 
              EndIf 
                                  
              size\cx = Width 
              size\cy = Height 
              
              If Extract\GetLocation(Space(#MAX_PATH), #MAX_PATH, @Priority, @size, Depth, @Flags) >= 0                
                If Extract\Extract(@Bitmap) >= 0 And Bitmap 
                                  
                  If StartDrawing(ImageOutput(Image)) 
                    DrawImage(Bitmap, 0, 0) 
                    StopDrawing()                    
                    Result = ImageResult 
                  EndIf 
                  
                  DeleteObject_(Bitmap) 
                EndIf 
              EndIf                
              Extract\Release() 
            EndIf 
            
            If Result = 0 
              FreeImage(Image) 
            EndIf            
          EndIf 
                    
          CoTaskMemFree_(*pidlFile) 
        EndIf                        
        Folder\Release() 
      EndIf      
      CoTaskMemFree_(*pidlFolder)      
    EndIf    
    Desktop\Release() 
  EndIf 

  ProcedureReturn Result 
  
  DataSection  
    IID_IShellFolder: ; {000214E6-0000-0000-C000-000000000046} 
      Data.l $000214E6 
      Data.w $0000, $0000 
      Data.b $C0, $00, $00, $00, $00, $00, $00, $46 
  
    IID_IExtractImage: ; {BB2E617C-0920-11D1-9A0B-00C04FC2D6C1} 
      Data.l $BB2E617C 
      Data.w $0920, $11D1 
      Data.b $9A, $0B, $00, $C0, $4F, $C2, $D6, $C1 
  EndDataSection  
EndProcedure

#ExplorerGadget = 0 
#ImageGadget    = 1 
#Image = 0 

If OpenWindow(0, 0, 0, 500, 400, "Shell Thumbnails", #PB_Window_SystemMenu|#PB_Window_ScreenCentered) 

  ExplorerTreeGadget(#ExplorerGadget, 5, 5, 190, 390, "C:\") 
  ImageGadget(#ImageGadget, 225, 100, 250, 200, 0, #PB_Image_Border) 

  Repeat 
    Event = WaitWindowEvent() 
    
    If Event = #PB_Event_Gadget And EventGadget() = #ExplorerGadget And EventType() = #PB_EventType_Change      
    
      If GetShellThumbnail(GetGadgetText(#ExplorerGadget), #Image, 250, 200) 
        SetGadgetState(#ImageGadget, ImageID(#Image)) 
      Else 
        SetGadgetState(#ImageGadget, 0) 
      EndIf 
      
    EndIf 
    
  Until Event = #PB_Event_CloseWindow 
EndIf 
End 
How can I flip the images and is there a better way with the new image commands?

--blueb

Re: Flippin' Images

Posted: Wed Oct 14, 2009 4:58 pm
by srod
That code doesn't work for me at all on Vista with PB 4.31 or 4.4.

I usually use SHGetFileInfo_() in order to get the default icons.

Re: Flippin' Images

Posted: Wed Oct 14, 2009 9:15 pm
by blueb
I've just tried the program on my work computer, which is running XP Pro with Pure 4.40b4.

Everything appears to work fine. I'mable to open BMP, JPG AND GIF with no trouble and the pictures are oriented properly.


My home unit with the problem is running Vista Ultimate and Pure 4.40b5

--blueb

Re: Flippin' Images

Posted: Thu Oct 15, 2009 11:24 am
by srod
Ah yes, I see... confirmed. BitBlt_() shows the images correctly, but then you lose the alpha-channel of course.

Might be linked to this : http://www.purebasic.fr/english/viewtop ... =4&t=39524

Re: Flippin' Images

Posted: Thu Oct 15, 2009 2:15 pm
by freak
Yes, BitBlt_() is the way to go here. This works:

Code: Select all

Procedure GetShellThumbnail(FileName$, Image, Width, Height, Depth = 24)
  Protected Result = 0, ImageResult
  Protected Desktop.IShellFolder, Folder.IShellFolder
  Protected Extract.IExtractImage
  Protected *pidlFolder.ITEMIDLIST, *pidlFile.ITEMIDLIST 
  Protected Priority, Flags, Bitmap = 0, size.SIZE
  Protected DC, SourceDC, BitmapInfo.BITMAP

  If SHGetDesktopFolder_(@Desktop) >= 0
    If Desktop\ParseDisplayName(#Null, #Null, GetPathPart(FileName$), #Null, @*pidlFolder, #Null) = #S_OK
      If Desktop\BindToObject(*pidlFolder, #Null, ?IID_IShellFolder, @Folder) = #S_OK
        If Folder\ParseDisplayName(#Null, #Null, GetFilePart(FileName$) , #Null, @*pidlFile, #Null) = #S_OK
          If Folder\GetUIObjectOf(#Null, 1, @*pidlFile, ?IID_IExtractImage, 0, @Extract) = #S_OK

            ImageResult = CreateImage(Image, Width, Height, Depth)
            If ImageResult
              If Image = #PB_Any
                Image = ImageResult
              EndIf   
                                 
              size\cx = Width
              size\cy = Height
             
              If Extract\GetLocation(Space(#MAX_PATH), #MAX_PATH, @Priority, @size, Depth, @Flags) >= 0               
                If Extract\Extract(@Bitmap) >= 0 And Bitmap
                                 
                  DC = StartDrawing(ImageOutput(Image))
                  If DC
                    SourceDC = CreateCompatibleDC_(DC)
                    If SourceDC
                      GetObject_(Bitmap, SizeOf(BITMAP), @BitmapInfo)
                      SelectObject_(SourceDC, Bitmap)
                      BitBlt_(DC, 0, 0, BitmapInfo\bmWidth, BitmapInfo\bmHeight, SourceDC, 0, 0, #SRCCOPY)
                      DeleteDC_(SourceDC)
                    EndIf
                    StopDrawing()                   
                    Result = ImageResult
                  EndIf
                 
                  DeleteObject_(Bitmap)
                EndIf
              EndIf               
              Extract\Release()
            EndIf
           
            If Result = 0
              FreeImage(Image)
            EndIf           
          EndIf
                   
          CoTaskMemFree_(*pidlFile)
        EndIf                       
        Folder\Release()
      EndIf     
      CoTaskMemFree_(*pidlFolder)     
    EndIf   
    Desktop\Release()
  EndIf

  ProcedureReturn Result
 
  DataSection 
    IID_IShellFolder: ; {000214E6-0000-0000-C000-000000000046}
      Data.l $000214E6
      Data.w $0000, $0000
      Data.b $C0, $00, $00, $00, $00, $00, $00, $46
 
    IID_IExtractImage: ; {BB2E617C-0920-11D1-9A0B-00C04FC2D6C1}
      Data.l $BB2E617C
      Data.w $0920, $11D1
      Data.b $9A, $0B, $00, $C0, $4F, $C2, $D6, $C1
  EndDataSection 
EndProcedure

#ExplorerGadget = 0
#ImageGadget    = 1
#Image = 0

If OpenWindow(0, 0, 0, 500, 400, "Shell Thumbnails", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)

  ExplorerTreeGadget(#ExplorerGadget, 5, 5, 190, 390, "C:\")
  ImageGadget(#ImageGadget, 225, 100, 250, 200, 0, #PB_Image_Border)

  Repeat
    Event = WaitWindowEvent()
   
    If Event = #PB_Event_Gadget And EventGadget() = #ExplorerGadget And EventType() = #PB_EventType_Change     
   
      If GetShellThumbnail(GetGadgetText(#ExplorerGadget), #Image, 250, 200)
        SetGadgetState(#ImageGadget, ImageID(#Image))
      Else
        SetGadgetState(#ImageGadget, 0)
      EndIf
     
    EndIf
   
  Until Event = #PB_Event_CloseWindow
EndIf
End 
Here is the reason for all this:
DrawImage() in ImageOutput() no longer uses API. To support the new drawing modes it operates on the pixel data directly. Now, Windows allows you to create a Bitmap that either stores its pixel rows top-down in memory, or bottom-up (the default). But there is no way to find out this orientation when all you have is a HBITMAP as it is here. So DrawImage() cannot know the orientation of the input image and so it assumes bottom-up because this is the more common orientation and also the way all PB images are stored.

Long story short: If you are dealing with top-down images or images of unknown memory orientation, BitBlt_() is your only choice because through MS some magic, it knows the image orientation and can draw the image accordingly.

Did i mention that GDI is a mess? :P

Re: Flippin' Images

Posted: Thu Oct 15, 2009 2:26 pm
by srod
GetDIBits_(), if used to query the bitmap, should tell you if the bitmap is top-down or bottom-up.

Re: Flippin' Images

Posted: Thu Oct 15, 2009 2:43 pm
by freak
srod wrote:GetDIBits_(), if used to query the bitmap, should tell you if the bitmap is top-down or bottom-up.
Nope. It returns a positive height value no matter what was used in the bitmap creation. Its the same for GetObject_().

Re: Flippin' Images

Posted: Thu Oct 15, 2009 2:59 pm
by srod
Ahh.... teach me not to test my own assertion! I knew GetObject_() always returned a positive value but just assumed that GetDIBits_(), when you set the relevant parameters to zero, would report the height correctly. A quick test and I can confirm that you are correct there. :) Strange that GDI does not allow us to accurately recover the original BITMAPINFOHEADER structure from a DIB.

Re: Flippin' Images

Posted: Thu Oct 15, 2009 3:08 pm
by Fred
Timo spent about 1 day on the subject, so i bet he is correct :twisted:

Re: Flippin' Images

Posted: Thu Oct 15, 2009 3:11 pm
by blueb
Thanks for getting to the bottom of this Freak.

It works on Vista Ultimate.

--blueb

Re: Flippin' Images

Posted: Thu Oct 15, 2009 3:25 pm
by srod
Fred wrote:Timo spent about 1 day on the subject, so i bet he is correct :twisted:
Nope, no doubts at all there! :) Just a case of me not testing out my own assertion - and not for the first time either! :wink:

Re: Flippin' Images

Posted: Thu Oct 15, 2009 6:25 pm
by Thalius
Fred wrote:Timo spent about 1 day on the subject, so i bet he is correct :twisted:
does he still have his hair ? :mrgreen:

Re: Flippin' Images

Posted: Thu Oct 15, 2009 9:52 pm
by Fred
AFAIK, yes ;)