[Need "bitmapobject.bi", included below,
or next post if not enough space here.]
[Notes, CREDITS, and another example in 3rd post, below.]
This relatively-small and relatively easy to use object will
load these 24/32bit bitmap types: BMP/GIF/JPEG/EXIF/PNG/TIFF
to an automatically created and sized fb Image, from where it
may then be put() to a GFX screen. The source bitmaps may be
from local files OR from an http: URL. If from URL the bitmap
is downloaded to memory-only, not written to disk.
Example image download (image reduced in size, here):
http://www.mediafire.com/view/o9ldn7e9f ... test-3.jpg
Note text annotation.
What may be of more general interest is the objects facility
to generate on-the-fly arbitrary font text. You specify the
text, the font name [font family, i.e., "Arial"], the font
size desired [in points], the font style [i.e., Bold], and
the foreground and background colors for the text. The text
is then rendered to a fb Image, from where it may be put()
to a GFX screen.
Example font test (see below for include file):
http://www.mediafire.com/view/2my96aunz ... test-6.jpg
Usage can be as simple as this (with no error-checking, this
is for demo only):
Code: Select all
'bitmapobject test #1
#include once "bitmapobject.bi"
'
dim bmp as bitmapobject ptr = new bitmapobject
'
bmp->Loadbmp("http://freebasic.net/sites/default/files/horse_original_r_0.gif")
'
put (0,0),bmp->Sprite
'
bmp->ReleaseSprite 'like ImageDestroy()
'
'please cleanup:
delete bmp
sleep
to the size of the downloaded bitmap, and an Image sized to the
size of the downloaded bitmap.
Same code with recommended error checking:
Code: Select all
'bitmapobject test #2
#include once "bitmapobject.bi"
'
dim as integer res
dim as string filename
'
dim bmp as bitmapobject ptr = new bitmapobject
'
filename = "http://freebasic.net/sites/default/files/horse_original_r_0.gif"
'
res=bmp->Loadbmp(filename) 'if res=1 then success
if bmp->IsValid then 'if bmp->IsValid = 1 then is OK
put(0,0),bmp->Sprite,pset
bmp->ReleaseSprite 'like ImageDestroy, necessary!
else
if ScreenPtr=0 then
screenres(640,480,32)
end if
print "Error:"
print res;" ";bmp->errmess
print "Sleeping to Exit"
sleep
end
end if
'
'please cleanup:
delete bmp
1. include the include...
2. Dim a new bitmapobject.
You may dim multiples, limited only by variable name validity
and memory (objects and especially bitmaps occupy MEMORY).
You may also Dim arrays, as in:
Code: Select all
#include once "bitmapobject.bi"
dim bmp(1 to 6) as bitmapobject ptr
'
for i as integer = 1 to 6
bmp(i) = new bitmapobject
next i
'
'use them...
'
'free them...
for i as integer = 1 to 6
delete bmp(i)
next i
'
3. Load a bitmap (or create "fonted" text)
May load from local file or http: URL. Please test IsValid
after loading or creating fonted text.
4. put(x,y) the Sprite somewhere, eventually.
Then you MUST ->ReleaseSprite, eventually. MUST do this
before reusing the object. If you dont ->ReleaseSprite you
will have a memory leak if the object is reused.
5. delete the object.
I dont know how fb will treat "new" objects when they go out
of scope. You should test with each new fb iteration.
Documentation and code examples in subsequent posts.
This is bitmapobject.bi (if not enough space for it in this post, see next):
Code: Select all
'bitmapobject.bi v20140427
' SAVEAS "bitmapobject.bi"
'
#include once "win\gdiplus.bi"
using gdiplus
#include once "windows.bi"
#include once "win\wininet.bi"
'
Type FBGDI_Image_Struct
hDC As HDC
jBitmap As HBITMAP
hPalette As HPALETTE
Sprite As Any Ptr
Buffer As Any Ptr
Data As UByte Ptr
end type
type FBGDI_Image As FBGDI_Image_Struct Ptr
'
type bitmapobject
'
declare destructor()
'
declare function LoadBmp(_
byval filename as string,_
noscreen as integer = 0,_
xsize as integer = 0,_
ysize as integer = 0,_
noresize as integer = 0) as integer
'
declare function LoadFont(_
byval strtext as string = "Feed Me",_
byval fontname as string = "Arial",_
fontsize as integer = 12,_
fstyle as integer = 0,_
forecolor as integer = rgba(255,255,255,255),_
backcolor as integer = rgba(0,0,0,255)) as integer
'
declare function FBGDI_Create Alias "FBGDI_Create" (_
ByVal w As Integer,_
ByVal h As Integer,_
d As Integer = 32) As FBGDI_Image
'
declare sub ReColor(_
byval img as any ptr,_
ReplaceThis As Uinteger,_
WithThis As Uinteger)
'
declare sub ReleaseSprite()
'
declare sub keepalive()
'
declare function dlfile(_
sURL as string,_
ByRef DLbuffer as string,_
mode as integer =0) as integer
'
declare function SetScreen(_
ontop as integer =0,_
showhide as integer =0) as integer
'
dim as integer iwidth,iheight,filesize,IsValid
dim as double begintime,endtime,loadtime
dim as any ptr ImgPtr,Sprite
dim as FBGDI_Image TSprite
dim as string errmess,orgname
'
end type
'
'===================================================
destructor bitmapobject
ReleaseSprite
end destructor
'
sub bitmapobject.ReleaseSprite()
'
if this.Tsprite <> 0 then
DeleteDC(TSprite->hDC)
DeleteObject(TSprite->buffer)
DeleteObject(TSprite->jbitmap)
TSprite->Sprite=0
TSprite=0
end if
this.IsValid=0
'
end sub
'
'===================================================
function bitmapobject.LoadBmp(_
byval filename as string,_
noscreen as integer = 0,_
xsize as integer = 0,_
ysize as integer = 0,_
noresize as integer = 0) as integer
'
this.Sprite=0
this.IsValid=0
errmess="No Error"
begintime=timer
'
if filename="" then
errmess="No filename specified"
return -1
else
orgname=filename
end if
'
dim as GdiplusStartupInput gdipsi
dim as ULONG_PTR gdipToken
dim as GpImage ptr pImage=0,pThumb=0
'
dim as integer res
dim as integer filehandle
dim as double wratio
dim as string sbuffer
'
dim as HBITMAP iBmp=0
dim as HGLOBAL hglobal = 0
dim as any ptr pGlobalBuffer = 0
dim as LPSTREAM iImageStream = 0
dim as RECT dc
'
'=====================================
'
gdipsi.GdiplusVersion = 1
if (GdiplusStartup(@gdipToken,@gdipsi,null)<>0) then
errmess="GdiplusStartup failed"
return -2
end if
'
if instr(ucase(filename),"HTTP")=1 then
filesize=dlfile(filename,sbuffer)
if filesize<=0 then
GdiplusShutdown(gdipToken)
return filesize
end if
hglobal=GlobalAlloc(&H42,filesize)
pGlobalBuffer = GlobalLock(hGlobal)
CopyMemory(pGlobalBuffer,strptr(sbuffer),filesize)
CreateStreamOnHGlobal(hGlobal,0,@iImageStream)
GdipCreateBitmapFromStream(iImageStream,@pImage)
sbuffer=""
else
if (GdipCreateBitmapFromFile(wstr(filename),@pimage)<>0) then
errmess="CreateBitmapFromFile failed, bad file type or name"
res= -4
if iImageStream<>0 then IUnknown_Release(iImageStream)
if pGlobalBuffer<>0 then GlobalUnlock(pGlobalBuffer)
if hGlobal<>0 then GlobalFree(hGlobal)
if pImage<>0 then GdipDisposeImage(pImage)
if pThumb<>0 then GdipDisposeImage(pThumb)
if ibmp<>0 then deleteobject(ibmp)
GdiplusShutdown(gdipToken)
return res
end if
'
end if
'
GdipGetImageWidth (pimage,@iwidth)
GdipGetImageheight (pimage,@iheight)
'
'============== allow image scaling
if xsize>0 and ysize>0 then
iwidth = xsize
iheight = ysize
elseif xsize>0 then
wratio = xsize/iwidth
iwidth = xsize
iheight = int(iheight * wratio)
elseif ysize>0 then
wratio = ysize/iheight
iheight = ysize
iwidth = int(iwidth * wratio)
end if
'==============
'
wratio=iwidth/iheight
'
'============== Make too-large image fit desktop
if noresize=0 then
GetWindowRect(GetDesktopWindow,@dc)
if iwidth > dc.Right then
iwidth=dc.right
iheight = int(iheight * wratio)
end if
if iheight > dc.Bottom then
iheight=dc.bottom
iwidth = int(iheight * wratio)
end if
end if
'==============
'
GdipGetImageThumbnail( pImage, iwidth, iheight, @pThumb, null, null )
'
dim as HWND vhwnd = GetDesktopWindow
dim pDC as HDC = getDC(vhwnd)
dim as HDC MemDC = CreateCompatibleDC(pDC)
'
res=GdipCreateHBITMAPFromBitmap(pThumb,@ibmp,0)
'
if res=0 then
SelectObject(MemDC,iBmp)
TSprite = FBGDI_Create(iwidth,iheight)
res=BitBlt(_
TSprite->hDC,_
0, 0,_
iwidth,_
iheight,_
MemDC, 0, 0, SRCCOPY)
'
this.Sprite= *(@TSprite->Sprite)
else
errmess="GdipCreateHBITMAPFromBitmap or BitBlt failed in LoadBmp()"
res= -5
end if
'
if iImageStream<>0 then IUnknown_Release(iImageStream)
if pGlobalBuffer<>0 then GlobalUnlock(pGlobalBuffer)
if hGlobal<>0 then GlobalFree(hGlobal)
if pImage<>0 then GdipDisposeImage(pImage)
if pThumb<>0 then GdipDisposeImage(pThumb)
if ibmp<>0 then deleteobject(ibmp)
ReleaseDC(vhwnd,pDc)
DeleteDC(MemDC)
GdiplusShutdown(gdipToken)
'
if noscreen=0 then
screenres(iwidth,iheight,32,,4)
if res<0 then print errmess:return res
end if
'
endtime=timer
loadtime=endtime-begintime
this.IsValid=1
return 1
'
end function
'
'===================================================
'See: http://www.ampsoft.net/webdesign-l/WindowsMacFonts.html for fontnames
'See: http://en.wikipedia.org/wiki/List_of_Microsoft_Windows_fonts
function bitmapobject.LoadFont(_
byval strtext as string = "Feed Me",_
byval fontname as string = "Arial",_
fontsize as integer = 12,_
fstyle as integer = 0,_
forecolor as integer = rgba(255,255,255,255),_
backcolor as integer = rgba(0,0,0,255)) as integer
'
dim as GdiplusStartupInput gdipsi
dim as ULONG_PTR gdipToken
dim as integer hStatus
'
dim as GpGraphics ptr pGraphics
dim as Gpfont ptr pFont
dim as GpFontFamily ptr pFontFamily = NULL
dim as Gpbrush ptr pBlackBrush,tpen,tbrush
dim as GpStringFormat ptr pformat
dim as GpBitmap ptr gbmp
'
dim as RECTF rcf,layoutRect,boundRect
dim as HBITMAP iBmp=0
dim as integer res
'
this.Sprite=0
this.IsValid=0
errmess="No Error"
res=0
'
if strtext ="" then errmess="No text to print":return -1
if fontname="" then errmess="No fontname specified":return -1
if fontsize<6 then errmess="Font size too small, <6": return -1
'
gdipsi.GdiplusVersion = 1
if (GdiplusStartup(@gdipToken,@gdipsi,null)<>0) then
errmess="GdiplusStartup failed"
return -2
end if
'
dim as HWND vhwnd = GetDesktopWindow
dim pDC as HDC = getDC(vhwnd)
dim as HDC MemDC = CreateCompatibleDC(pDC)
'
'============================================================
'
'check if fontname is valid, then get size
hStatus = GdipCreateFromHDC(pDC, @pGraphics)
hStatus = GdipCreateFontFamilyFromName(wstr(fontname),NULL,@pFontFamily)
if hStatus = 0 and pFontFamily <> NULL then
hStatus = GdipCreateFont(_
pFontFamily,_
fontsize,_
fstyle,_
UnitPoint,_
@pFont)
'
GdipDeleteFontFamily(pFontFamily)
else
res= -3
errmess="This font is unavailable"
if pFontFamily <> NULL then GdipDeleteFontFamily(pFontFamily)
goto cleanupafterfont:
end if
'
layoutRect.x = 0.0: layoutRect.y = 0.0: layoutRect.Width = 800.0: layoutRect.Height = 200.0
hStatus = GdipCreateStringFormat(0, LANG_NEUTRAL,@pFormat)
hStatus = GdipSetStringFormatAlign(pFormat,0)' %StringAlignmentFar)
'
'measure the string
hStatus = GdipMeasureString(_
pGraphics,_
wstr(strText),_
len(strText),_
pFont,_
@layoutRect,_
pFormat,_
@boundRect,_
0,0)
'
iwidth = int(boundRect.Width + 1)
iheight= int(boundRect.Height + 1)
'
if pFormat then GdipDeleteStringFormat(pFormat)
if pGraphics then GdipDeleteGraphics(pGraphics)
'
if iwidth<4 or iheight<4 then
res= -3
errmess = "Unable to get font size in LoadFont()"
goto cleanupafterfont:
end if
'
'============================================================
'
hstatus=GdipCreateBitmapFromScan0(iwidth,iheight,NULL,PixelFormat32bppARGB,NULL,@Gbmp)
hstatus=GdipGetImageGraphicsContext(Gbmp,@pGraphics)
'
GdipCreateSolidFill(backcolor,@tbrush)
GdipFillRectangle(pGraphics,tbrush,0,0,iwidth,iheight)
'
hStatus = GdipCreateSolidFill(forecolor,@pBlackBrush)
'
rcf.x = 0.0 : rcf.y = 0.0
hStatus = GdipDrawString(_
pGraphics,_
wstr(strText),_
LEN(strText),_
pFont,_
@rcf,_
NULL,_
pBlackBrush)
'
hstatus=GdipCreateHBITMAPFromBitmap(gbmp,@ibmp,0)
'
if hstatus=0 then
SelectObject(MemDC,iBmp)
TSprite = FBGDI_Create(iwidth,iheight)
res=BitBlt(_
TSprite->hDC,_
0, 0,_
iwidth,_
iheight,_
MemDC, 0, 0, SRCCOPY)
'
this.Sprite= *(@TSprite->Sprite)
else
errmess="GdipCreateHBITMAPFromBitmap or BitBlt failed in LoadFont()"
res= -5
goto cleanupafterfont:
end if
'
this.IsValid=1
res=1
'
cleanupafterfont:
'
'cleanup
if pFont then GdipDeleteFont(pFont)
if tpen then GdipDeleteBrush(tpen)
if tbrush then GdipDeleteBrush(tbrush)
if pBlackBrush then GdipDeleteBrush(pBlackBrush)
if pGraphics then GdipDeleteGraphics(pGraphics)
if ibmp<>0 then deleteobject(ibmp)
if gbmp<>0 then GdipDisposeImage(gbmp)
'
ReleaseDC(vhwnd,pDc)
DeleteDC(MemDC)
GdiplusShutdown(gdipToken)
'
return res
'
end function
'
'===================================================
'@jofer's code, modified
private function bitmapobject.FBGDI_Create Alias "FBGDI_Create" (ByVal w As Integer, ByVal h As Integer, d As Integer = 32) As FBGDI_Image
'
dim BitmapInfo As BITMAPINFO Ptr
dim Image as FBGDI_Image
dim iUsage as integer
dim as integer r, g, b, x,res
'
if (w < 4) then return 0
'
Image = CAllocate(SizeOf(FBGDI_Image_Struct))
Image->hDC = CreateCompatibleDC(GetDC(0))
'
BitmapInfo = CAllocate(SizeOf(BITMAPINFO) + 255*SizeOf(RGBQUAD))
with BitmapInfo->bmiHeader
.biSize = SizeOf(BITMAPINFOHEADER)
.biWidth = w
.biHeight = -(h+1)
.biPlanes = 1
.biBitCount = d
.biCompression = BI_RGB
end with
'
Image->jBitmap = CreateDIBSection(Image->hDC, BitmapInfo, DIB_RGB_COLORS, @Image->Buffer, NULL, 0)
SelectObject Image->hDC, Image->jBitmap
'
'Map the viewport origin to (0, 1) and clip it
' so the top line can be used for FB sprite data
SelectClipRgn Image->hDC, CreateRectRgn(0, 1, w, h+1)
SetViewportOrgEx Image->hDC, 0, 1, NULL
'
'Set the FB Sprite header
Image->Data = Cast(UByte Ptr, Image->Buffer) + w*(d Shr 3)
Image->Sprite = Cast(Any Ptr, Image->Data - 4)
'
CPtr(UShort Ptr, Image->Sprite)[0] = (w Shl 3) Or (d Shr 3)
CPtr(UShort Ptr, Image->Sprite)[1] = h
'
Deallocate BitmapInfo
'
return Image
'
end function
'
'this is @dodicat's code, modified.
sub bitmapobject.ReColor(byval img as any ptr,ReplaceThis as uinteger,WithThis as uinteger)
'
dim as integer _x,_y
dim as integer pitch,pitch2
dim as any pointer row,row2
dim as uinteger pointer pixel,pixel2
dim as uinteger col
'
Imageinfo img,_x,_y,,pitch2,row2
'
for y as integer=0 to _y-1
for x as integer=0 to _x-1
pixel=row2+pitch2*((y))+((x)) Shl 2
(col)=*pixel
if col=ReplaceThis then col=WithThis
pixel2=row2+pitch2*((y))+((x)) Shl 2
*pixel2=(col)
next x
next y
'
end sub
'
'===================================================
function bitmapobject.dlfile(_
sURL as string,_
ByRef DLbuffer as string,_
mode as integer =0) as integer
'
this.filesize=0
'
dim as HINTERNET hOpen,hFile
dim as integer ctot,fh,nret,res,timeout
dim as string tbuff,ts
dim as string scUserAgent = "FreeBASIC"
dim as string mybuff,filename
'
if mode<>0 then filename=DLbuffer
'
'Test for internet connection..
res=InternetAttemptConnect(0)
if res<>0 then
errmess="InternetAttemptConnect failed in dlfile()"
return -1
end if
'
'create an internet connection
hOpen=InternetOpen(scUserAgent,INTERNET_OPEN_TYPE_PRECONFIG,NULL,NULL,0)
if hOpen=0 then
errmess="InternetOpen failed in dlfile()"
return -2 'failed..
end if
'
'set timeout in milliseconds
timeout=5000
res=InternetSetOption(_
hOpen,_
INTERNET_OPTION_RECEIVE_TIMEOUT,_
@timeout,_
SizeOf(timeout))
'
'Open the url
hFile=InternetOpenUrl(hOpen,sURL,NULL,0,INTERNET_FLAG_RELOAD or INTERNET_FLAG_NO_CACHE_WRITE,0)
if hFile=0 then
errmess="InternetOpenUrl failed in dlfile()"
return -3 'failed..
end if
'
ctot=0
DLbuffer=""
nret=99
while nret>0
mybuff=space(2048)
res=InternetReadFile(hFile,strptr(mybuff),2048,@nret)
if nret>0 then
DLbuffer += left(mybuff,nret)
ctot+=nret
end if
wend
'
if mode<>0 then
if ctot>0 then
kill filename
fh=freefile
open filename for binary access write as fh
put #fh,,DLbuffer
close fh
end if
end if
'
InternetCloseHandle(hFile)
InternetCloseHandle(hOpen)
'
this.filesize=ctot
'
if ctot=0 then
errmess="0 bytes downloaded in dlfile, failed"
return -4
end if
'
return ctot
'
end function
'
'===================================================
sub bitmapobject.keepalive()
'
dim as integer res
dim as HWND hwnd
'
screencontrol(2,cast(integer,hwnd))
keybd_event(VK_MENU,0, KEYEVENTF_EXTENDEDKEY,0)
keybd_event(VK_MENU,0, KEYEVENTF_EXTENDEDKEY OR KEYEVENTF_KEYUP, 0)
res=SetForegroundWindow(hwnd)
'
end sub
'
function bitmapobject.SetScreen(ontop as integer =0,showhide as integer =0) as integer
'
if Screenptr=0 then return 0
if (ontop>1 orElse ontop<0) _
orElse _
(showhide>1 orElse showhide<0) then return 0
'
dim as integer res
dim as integer flags = SWP_NOMOVE Or SWP_NOSIZE Or SWP_NOREDRAW
dim as HWND zhwnd,placement
'
ScreenControl(2,cast(integer,zhwnd))
if zhwnd=0 then return 0
'
if showhide=1 then
flags Or= SWP_HIDEWINDOW
else
flags Or= SWP_SHOWWINDOW
end if
'
if ontop=1 then
placement = cast(..HWND,-1)
else
placement = cast(..HWND,-2)
end if
'
res=SetWindowPos(zhwnd,placement,0,0,0,0,flags)
'
return res
'
end function
ETA: bi mod, to include "https:" files.