Page 1 of 1

Get an image for free [Windows only]

Posted: Fri Jan 10, 2025 6:26 pm
by Zapman
When I was a child, you could receive an image as a reward for being very well-behaved. Some printers produced small images specifically designed for this purpose. Teachers and parents would buy them and give them to the best-behaved children.
The small procedure below will give you images, even if you haven't been well-behaved and polite.

The idea is to provide a quick solution to obtain an image when test code or code intended for the PureBasic forum requires an image to work.
Until now, you had to write a procedure to create the image, or search for an image on your disk, locate its address, ensure the correct decoder was selected to open it, load it into memory, and finally use it, hoping that your code would work on another computer than yours.
Here is a simpler solution!

First, here is the list of images I get on my computer. Please tell me if you get the same.

The code is just after this image.

Image

Code: Select all

;
; *****************************************************************************
;
;                             GetAnImageForFree
;                     Zapman - Jan 2025 - Windows only
;
; This very small library offers a single function that explores your computer
; memory to find images. This function is GetAnImageForFree(). The second part
; of the code only contains a demonstration procedure.
;
; The idea is to provide a quick solution to obtain an image when test code or
; code intended for the PureBasic forum requires an image to work.
; Until now, you had to write a Procedure to create the image, or search for an
; image on your disk, locate its address, ensure the correct decoder was selected
; to open it, load it into memory, and finally use it.
;
; No more of that: simply copy and paste the GetAnImageForFree() Procedure into
; your code, create an empty image with CreateImage() and pass its number when 
; calling the Procedure. Your image is ready!
; This Procedure does not require any image decoder Or file address to work.
; The demonstration code provided at the end of this file will show you the type
; of images that can be retrieved using this method.
;
; *****************************************************************************
;
CompilerIf #PB_Compiler_IsMainFile
  EnableExplicit
CompilerEndIf
;
Procedure GetAnImageForFree(Start = 1, NbAttempt = 1000, MinSize = 16, PBImage = -1)
  ; By Zapman - Jan 2025.
  ;
  ; Explore the memory an return the first found image from 'Start' address.
  ;
  ; 'NbAttempt' is the limit number of attempts before stopping the exploration.
  ;
  ; 'MinSize' contains the minimum size for the searched image.
  ;
  ; If PBImage contains a valid image created with 'CreateImage()',
  ; the found image will be copied to PBImage.
  ; If PBImage = -1, the memory will only be checked for an existing image
  ; and nothing will be copied nowhere.
  ;
  ; If existing, PBImage can be 24 bits or 32 bits.
  ;
  Protected Result = 0, bitmap.BITMAP, hDestBitmap
  Protected ct, w, h, ImgWidth, ImgHeight, IsAlpha
  Protected x, y, PixelColor, NotEmpty
  Protected EndOfExploration = Start + NbAttempt
  Protected oldDestBitmap, oldSrcBitmap
  Protected blend, *blend.BLENDFUNCTION = @blend
  Protected hdcDest, hdcSrc = CreateCompatibleDC_(#Null) ; Create a memory hDC.
  ;
  If OpenLibrary(0, "Msimg32.dll")
    If hdcSrc
      If IsImage(PBImage) ; Check if the destination given image is valid.
        hDestBitmap = ImageID(PBImage) ; Get the  destination image handle.
        If GetObject_(hDestBitmap, SizeOf(BITMAP), @bitmap) ; get the destination image size.
          ImgWidth = bitmap\bmWidth
          ImgHeight = bitmap\bmHeight
          IsAlpha = bitmap\bmBitsPixel
          If ImgWidth * ImgHeight ; Check if the destination image has not a null size.
            If StartDrawing(ImageOutput(PBImage))
              ; Erase the given image background:
              If isAlpha = 32
                ; Transparent background
                DrawingMode(#PB_2DDrawing_AllChannels)
                Box(0, 0, ImgWidth, ImgHeight, 0)
              Else
                ; White background
                Box(0, 0, ImgWidth, ImgHeight, $FFFFFF)
              EndIf
              StopDrawing()
            Else
              Goto GAIFF_CleanAndReturn
            EndIf
            ;
            hdcDest = CreateCompatibleDC_(#Null)    ; Create a memory hDC for the destination image
            oldDestBitmap = SelectObject_(hdcDest, hDestBitmap) ; Associate the destination image with hdcDest.
          Else
            Goto GAIFF_CleanAndReturn
          EndIf
          If oldDestBitmap = 0
            Goto GAIFF_CleanAndReturn
          EndIf
        Else
          Goto GAIFF_CleanAndReturn
        EndIf
      ElseIf PBImage <> -1
        Goto GAIFF_CleanAndReturn
      EndIf
      ;
      For ct = Start To EndOfExploration
        If GetObject_(ct, SizeOf(BITMAP), @bitmap) ; Check is there is an image at this address.
          w = bitmap\bmWidth                       ; If any, get the found image size.
          h = bitmap\bmHeight
          If w >= MinSize And h >= MinSize           ; Ensure that the found image has good dimensions.
            oldSrcBitmap = SelectObject_(hdcSrc, ct) ; Associate the found image with hdcSrc
            If oldSrcBitmap
              Result = ct
              If hDestBitmap
                ; Copy the found image into PBImage:
                *blend\BlendOp = #AC_SRC_OVER
                *blend\BlendFlags = 0
                *blend\AlphaFormat = #AC_SRC_ALPHA
                *blend\SourceConstantAlpha = 255
                CallFunction(0, "AlphaBlend", hdcDest, 0, 0, ImgWidth, ImgHeight, hdcSrc, 0, 0, w, h, blend)
                ;
                ; Now, check if the resulting image is empty:
                ;
                NotEmpty = #False
                If StartDrawing(ImageOutput(PBImage))
                  If IsAlpha = 32
                    DrawingMode(#PB_2DDrawing_AllChannels)
                  EndIf
                  ; Check each pixel to see if all are equal to a solid color (e.g., white).
                  For y = 0 To ImgHeight - 1
                    For x = 0 To ImgWidth - 1
                      PixelColor = Point(x, y)
                      If IsAlpha = 24
                        ; Check if the pixel is white:
                        If PixelColor <> RGB(255, 255, 255) ; If a different pixel is found...
                          NotEmpty = #True
                          Break
                        EndIf
                      ElseIf IsAlpha = 32 And Alpha(PixelColor); Check if the pixel is transparent.
                        NotEmpty = #True
                        Break
                      EndIf
                    Next x
                  Next y
                  StopDrawing()
                Else
                  Result = 0
                EndIf
                ;
                If NotEmpty = #False
                  Result = 0
                EndIf
              EndIf
              If Result : Break : EndIf
            EndIf
          EndIf
        EndIf
      Next
      ;
      GAIFF_CleanAndReturn:
      If oldDestBitmap
        SelectObject_(hdcDest, oldDestBitmap)
      EndIf
      If hdcDest : DeleteDC_(hdcDest) : EndIf
      If oldSrcBitmap
        SelectObject_(hdcSrc, oldSrcBitmap)
      EndIf
      If hdcSrc : DeleteDC_(hdcSrc) : EndIf
    EndIf
    CloseLibrary(0)
  EndIf
  ProcedureReturn Result
EndProcedure
;
; *****************************************************************************
;
;                                 Demo program
;
; *****************************************************************************
;
CompilerIf #PB_Compiler_IsMainFile
  ;
  ; The following won't run when this file is used as 'Included'.
  ;
  #ImageWidth = 50
  #ImageHeight = 50
  #HorizontalSpacing = 55
  #VerticalSpacing = 75
  ;
  Procedure DrawImagesOnSurfImage(SurfImageID, StartRangeMin, StartRangeMax)
    ;
    ; Explore the numbers between StartRangeMin And StartRangeMax,
    ; retrieve the corresponding image if it exists, and draw it on
    ; the drawing surface SurfImageID.
    ;
    Protected x, y, Start, Result, Text$
    Protected MaxWidth, NStart, BottomMargin
    Protected SurfImageHeightNeeded = 0
    Protected ImageID = CreateImage(#PB_Any, 50, 50, 32)
    ;
    ; Check if SurfImageID is valid:
    If IsImage(ImageID) And IsImage(SurfImageID) And StartDrawing(ImageOutput(SurfImageID))
      MaxWidth = OutputWidth() - #HorizontalSpacing
      StopDrawing()
      x = 10
      y = 10
      For Start = StartRangeMin To StartRangeMax
        ; Try to get an image with the Start value
        NStart = GetAnImageForFree(Start, StartRangeMax - Start, 16, ImageID)
        If NStart And StartDrawing(ImageOutput(SurfImageID))
          Start = NStart
          ; Draw the image:
          DrawingMode(#PB_2DDrawing_AllChannels)
          DrawImage(ImageID(ImageID), x, y, #ImageWidth, #ImageHeight)
          ; Draw the number under the image:
          Text$ = Str(Start)
          DrawingMode(#PB_2DDrawing_Transparent)
          DrawText(x + (#ImageWidth - TextWidth(Text$)) / 2, y + #ImageHeight + 5, Text$, RGB(0, 0, 0))
          ;
          ; Next position
          x + #HorizontalSpacing
          If x > MaxWidth
            x = 10
            y + #VerticalSpacing
          EndIf
          StopDrawing()
        EndIf
        ;
      Next Start
      ;
      BottomMargin = #HorizontalSpacing - #Imagewidth ; reserve a bottom margin equal to horizontal margin between images.
      SurfImageHeightNeeded = y + #VerticalSpacing + BottomMargin; Total Necessary Height for drawing all images.
      ;
    EndIf
    ProcedureReturn SurfImageHeightNeeded
  EndProcedure
  
  ; Create a window with a ScrollAreaGadget containing an ImageGadget containg a big image.
  If OpenWindow(0, 0, 0, 584, 600, "Tableau d'images", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
    Define ScrollBarWidth = 30
    ; First create the big image (SurfImage).
    Define SurfImage = CreateImage(#PB_Any, DesktopScaledX(WindowWidth(0)) - ScrollBarWidth, 4000, 32)
    If StartDrawing(ImageOutput(SurfImage))
      Define SurfImageWidth = OutputWidth()
      Define SurfImageHeight = OutputHeight()
      DrawingMode(#PB_2DDrawing_AllChannels)
      Box(0, 0, SurfImageWidth, SurfImageHeight, $FFFFE0E0) ; Color the SurfImage area with pale blue.
      StopDrawing()
    EndIf
    ; Fill the big image with all images found in memory from address 1 to 2000:
    Define StartMin = 1, StartMax = 4000
    Define SurfImageHeightNeeded = DrawImagesOnSurfImage(SurfImage, StartMin, StartMax)
    ; Grab the big image to SurfImageHeightNeeded
    Define SurfImage2
    GrabImage(SurfImage, SurfImage2, 0, 0, SurfImageWidth, SurfImageHeightNeeded)
    FreeImage(SurfImage)
    ;
    ; Create the ScrollAreaGadget:
    ScrollAreaGadget(0, 0, 0, WindowWidth(0), WindowHeight(0), DesktopUnscaledY(SurfImageWidth), DesktopUnscaledY(SurfImageHeightNeeded))
    ;
    ; Fill the ScrollAreaGadget with an Imagegadget containing the big image:
    ImageGadget(1, 2, 2, DesktopUnscaledY(SurfImageWidth), DesktopUnscaledY(SurfImageHeightNeeded), ImageID(SurfImage2))
    CloseGadgetList()
    ;
    Repeat
      Define Event = WaitWindowEvent()
    Until Event = #PB_Event_CloseWindow
  EndIf
CompilerEndIf

Re: Get an image for free [Windows only]

Posted: Sat Jan 11, 2025 3:54 am
by BarryG
I've got my own code that creates a similar table of icons in a grid like that. :)

So here's a tip from my experience: check the icon on ALL versions of Windows, because what appears as something on one Windows can look totally different and unrelated on another. This caught me out a few times. Example: In "shell32.dll", index 265 is a clock on Win 10 but a briefcase on Win 11.

Re: Get an image for free [Windows only]

Posted: Sat Jan 11, 2025 5:17 am
by SPH
not the same here (W11)

Re: Get an image for free [Windows only]

Posted: Sat Jan 11, 2025 6:25 am
by BarryG
SPH wrote: Sat Jan 11, 2025 5:17 amnot the same here (W11)
What do you mean? So you're agreeing with me that they're not the same on Win 10 and 11?

BTW, I only just realized that your avatar changes color. :)

Re: Get an image for free [Windows only]

Posted: Sun Jan 12, 2025 1:40 pm
by SPH

Re: Get an image for free [Windows only]

Posted: Sun Jan 12, 2025 4:28 pm
by Axolotl
@Zapman,
thanks for sharing.
BTW: I am not so picky when it comse to images. so I use the following command on several files. And of cause created my very own image (icon) viewer.

Code: Select all

; ExtractIconEx_()
; File Location is %SystemRoot%\system32\  -- but path is not needed, because it is part of the %PATH% anyway. 
; Shell32.dll 
; moricons.dll 
; setupapi.dll

Re: Get an image for free [Windows only]

Posted: Sun Jan 12, 2025 5:13 pm
by Zapman
BarryG wrote: Sat Jan 11, 2025 3:54 am I've got my own code that creates a similar table of icons in a grid like that. :)
I remember that. You're code probably inspired mine.
BarryG wrote: Sat Jan 11, 2025 3:54 amSo here's a tip from my experience: check the icon on ALL versions of Windows, because what appears as something on one Windows can look totally different and unrelated on another. This caught me out a few times. Example: In "shell32.dll", index 265 is a clock on Win 10 but a briefcase on Win 11.
You're right. But the goal wasn't to get precise references for some images, but to explore the memory as a game. Note that an image is always returned because the procedure explores the memory until it founds one.

Thanks to everyones for your returns.
I'd love to see other results as images, if somebody has time to post some.
Axolotl wrote: Sun Jan 12, 2025 4:28 pmI use the following command on several files. And of cause created my very own image (icon) viewer.

Code: Select all

; ExtractIconEx_()
; File Location is %SystemRoot%\system32\  -- but path is not needed, because it is part of the %PATH% anyway. 
; Shell32.dll 
; moricons.dll 
; setupapi.dll
I didn't know that usefull tips. Thank you, Axolotl!

Re: Get an image for free [Windows only]

Posted: Sun Feb 02, 2025 12:35 pm
by Zapman
From an Axolotl's idea, here is a version with ExtractIcon.

This time, for most of them, the images will be the same on all versions of Windows and for all users. But, as BarryG said, you have to test that

Code: Select all

;
; *****************************************************************************
;
;                         GetAnImageForFree Shell32
;                     Zapman - Jan 2025 - Windows only
;
;    This file should be saved under the name "GetAnImageForFreeShell32.pbi".
;
; This very small library offers a pannel of images that can be found in
; shell32.dll. You can replace 'shell32' by 'imageres' to get other images.
;
; *****************************************************************************
;
CompilerIf #PB_Compiler_IsMainFile
  EnableExplicit
CompilerEndIf
;
Procedure GetImageFromShell32(IconNum, ImgWidth, ImgHeight)
  ;
  Protected TransparentImage = 0
  Protected hIcon = ExtractIcon_(0, "shell32.dll", IconNum)
  ; You could also try "imageres.dll"
  ;
  If hIcon
    TransparentImage = CreateImage(#PB_Any, ImgWidth, ImgHeight, 32, #PB_Image_Transparent)
    If TransparentImage
      Protected Dest_hDC = StartDrawing(ImageOutput(TransparentImage))
      If Dest_hDC
        DrawingMode(#PB_2DDrawing_AlphaBlend)
        Box(0, 0, ImgWidth, ImgHeight, RGBA(0, 0, 0, 0))
        DrawIconEx_(Dest_hDC, 0, 0, hIcon, ImgWidth, ImgHeight, 0, #Null, #DI_NORMAL)
        StopDrawing()
        DeleteDC_(Dest_hDC)
      EndIf
    EndIf
    DestroyIcon_(hIcon)
  EndIf
  ;
  ProcedureReturn TransparentImage
EndProcedure
;
; *****************************************************************************
;
;                                 Demo program
;
; *****************************************************************************
;
CompilerIf #PB_Compiler_IsMainFile
  ;
  ; The following won't run when this file is used as 'Included'.
  ;
  #ImageWidth = 32
  #ImageHeight = 32
  #HorizontalSpacing = 40
  #VerticalSpacing = 60
  ;
  Procedure DrawImagesOnSurfImage(SurfImageID, StartRangeMin, StartRangeMax)
    ;
    ; Explore the numbers between StartRangeMin And StartRangeMax,
    ; retrieve the corresponding image if it exists, and draw it on
    ; the drawing surface SurfImageID.
    ;
    Protected x, y, Start, Result, Text$, ImageID
    Protected MaxWidth, NStart, BottomMargin
    Protected SurfImageHeightNeeded = 0
    ;
    ; Check if SurfImageID is valid:
    If IsImage(SurfImageID) And StartDrawing(ImageOutput(SurfImageID))
      MaxWidth = OutputWidth() - #HorizontalSpacing
      StopDrawing()
      x = 10
      y = 10
      For Start = StartRangeMin To StartRangeMax
        ; Try to get an image with the Start value
        ImageID = GetImageFromShell32(Start, #ImageWidth, #ImageHeight)
        If ImageID And StartDrawing(ImageOutput(SurfImageID))
          ; Draw the image:
          DrawingMode(#PB_2DDrawing_AlphaBlend)
          DrawImage(ImageID(ImageID), x, y, #ImageWidth, #ImageHeight)
          ; Draw the number under the image:
          Text$ = Str(Start)
          DrawingMode(#PB_2DDrawing_Transparent)
          DrawText(x + (#ImageWidth - TextWidth(Text$)) / 2, y + #ImageHeight + 2, Text$, RGB(0, 0, 0))
          ;
          ; Next position
          x + #HorizontalSpacing
          If x > MaxWidth
            x = 10
            y + #VerticalSpacing
          EndIf
          StopDrawing()
        EndIf
        ;
      Next Start
      ;
      BottomMargin = #HorizontalSpacing - #Imagewidth ; reserve a bottom margin equal to horizontal margin between images.
      SurfImageHeightNeeded = y + #VerticalSpacing + BottomMargin; Total Necessary Height for drawing all images.
      ;
    EndIf
    ProcedureReturn SurfImageHeightNeeded
  EndProcedure
  
  ; Create a window with a ScrollAreaGadget containing an ImageGadget containg a big image.
  If OpenWindow(0, 0, 0, 584, 600, "Tableau d'images", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
    Define ScrollBarWidth = 30
    ; First create the big image (SurfImage).
    Define SurfImage = CreateImage(#PB_Any, DesktopScaledX(WindowWidth(0)) - ScrollBarWidth, 4000, 32)
    If StartDrawing(ImageOutput(SurfImage))
      Define SurfImageWidth = OutputWidth()
      Define SurfImageHeight = OutputHeight()
      DrawingMode(#PB_2DDrawing_AllChannels)
      Box(0, 0, SurfImageWidth, SurfImageHeight, $FFFFE0E0) ; Color the SurfImage area with pale blue.
      StopDrawing()
    EndIf
    ; Fill the big image with all images found in memory from address 1 to 2000:
    Define StartMin = 1, StartMax = 2000
    Define SurfImageHeightNeeded = DrawImagesOnSurfImage(SurfImage, StartMin, StartMax)
    ; Grab the big image to SurfImageHeightNeeded
    Define SurfImage2
    GrabImage(SurfImage, SurfImage2, 0, 0, SurfImageWidth, SurfImageHeightNeeded)
    FreeImage(SurfImage)
    ;
    ; Create the ScrollAreaGadget:
    ScrollAreaGadget(0, 0, 0, WindowWidth(0), WindowHeight(0), DesktopUnscaledY(SurfImageWidth), DesktopUnscaledY(SurfImageHeightNeeded))
    ;
    ; Fill the ScrollAreaGadget with an Imagegadget containing the big image:
    ImageGadget(1, 2, 2, DesktopUnscaledY(SurfImageWidth), DesktopUnscaledY(SurfImageHeightNeeded), ImageID(SurfImage2))
    CloseGadgetList()
    ;
    Repeat
      Define Event = WaitWindowEvent()
    Until Event = #PB_Event_CloseWindow
  EndIf
CompilerEndIf