Get an image for free [Windows only]
Posted: Fri Jan 10, 2025 6:26 pm
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.
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.

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