|
Post by brendan on Jun 27, 2020 6:43:50 GMT -5
Hi, I have several large 5000px X 5000px images tiled from a very large tiff. The program views a image tile and allows basic drawing functions lines, shapes, text used for mapping. I would like to save the loaded image with the flushed graphics the same size as the original image only renamed for use as an overlay later. Currently I'm only able to save the graphics window which is a tiny portion of the original size. Anyway to save the entire 5000px X 5000px image with the flushed graphics?
|
|
Tasp
Full Member
Posts: 215
|
Post by Tasp on Jun 27, 2020 7:34:52 GMT -5
I'm doing something similar with mapping myself atm. And I'm in no way good with graphics but I think you need to be using something like GETBMP print #handle, "getbmp bmpName x y width height"
This might be helpful as well, alycesrestaurant.com/gdip2.htm
|
|
|
Post by Rod on Jun 27, 2020 9:51:57 GMT -5
The limitation is getbmp because it can only capture what you can see on screen. So as you have tiled the tiff so you will need to tile the overlay. When saving, break the overlay into visible portions, display a portion, getbmp it and save it as a tilex.bmp You might set the scroll position programmatically as you capture the overlay tiles.
On loading you can load your background and display it in a fixed size graphicbox with scrollbars. You can then drawbmp all the overlay tiles in the appropriate location.
So you can display and draw to a very large bmp in whatever size graphicbox suits. You can also print the large graphic using an appropriate "size" parameter. The only thing you cant do is getbmp and save, because of the "has to be visible" issue.
|
|
|
Post by Carl Gundel on Jun 27, 2020 10:01:54 GMT -5
The limitation is getbmp because it can only capture what you can see on screen. This limitation will end with LB5.
|
|
|
Post by brendan on Jun 27, 2020 14:54:51 GMT -5
Thanks for the quick replies. I still only load one tif at a time for viewing in the program. Navigating around the complete tileset is done by up,down,left,right arrows. this just unloads one image and loads a new one. Thanks Rod, I could do all that in native LB if I captured the scroll tab positions and apply the process to one image. I have since found an old article #101 on writing BMP to memory DC by alyce will see if i can use the technique. Otherwise when can we expect LB5 ;-)
|
|
|
Post by brendan on Jun 27, 2020 19:02:23 GMT -5
The limitation is getbmp because it can only capture what you can see on screen. So as you have tiled the tiff so you will need to tile the overlay. When saving, break the overlay into visible portions, display a portion, getbmp it and save it as a tilex.bmp You might set the scroll position programmatically as you capture the overlay tiles. On loading you can load your background and display it in a fixed size graphicbox with scrollbars. You can then drawbmp all the overlay tiles in the appropriate location. So you can display and draw to a very large bmp in whatever size graphicbox suits. You can also print the large graphic using an appropriate "size" parameter. The only thing you cant do is getbmp and save, because of the "has to be visible" issue. Hi Rod, again thanks. That works it just means i have a lot of smaller overlays rather than the whole 5000x5000 image. #main.map "flush" SaveName$ = upto$(ImageFilename$,".") + "_" + str$(overlay) + ".bmp" '// get scroll tab positions top left corner // scrollDir = _SBS_HORZ hpos = GetScrollPos(hWnd(#main.map), scrollDir) scrollDir = _SBS_VERT vpos = GetScrollPos(hWnd(#main.map), scrollDir) GraphicWidth = GraphicBoxWidth - 20 : GraphicHeight = GraphicBoxHeight - 20 #main.map, "getbmp overlay ";hpos;" ";vpos;" ";GraphicWidth ;" ";GraphicHeight bmpsave "overlay",SaveName$ call ImageZoomActual bHnd$ cursor hourglass '// load screenshot // loadbmp "overlay", SaveName$ #main.map, "drawbmp overlay ";hpos;" ";vpos;" ; flush" '// reset scroll tabs // pos = hpos scrollDir = _SBS_HORZ scrollFlag = _WM_HSCROLL Call SetScrollPos hWnd(#main.map), pos, scrollDir, scrollFlag pos = vpos scrollDir = _SBS_VERT scrollFlag = _WM_VSCROLL Call SetScrollPos hWnd(#main.map), pos, scrollDir, scrollFlag cursor normal
|
|
|
Post by Rod on Jun 28, 2020 3:40:41 GMT -5
|
|
|
Post by Chris Iverson on Jun 28, 2020 4:23:36 GMT -5
I'll take a shot at converting it tomorrow. It doesn't look too bad to me; actually fairly straightforward.
A good chunk of it can be left out; it gets two DCs, and does scaling to convert it to the current window's size before saving it to a file. (Plus all of the boilerplate win32 message loop code.)
Looks like it's CreateCompatibleDC() to create an in-memory device context that matches the one for the current window; CreateCompatibleBitmap() to do the same; SelectObject() to select it into the in-memory DC; BitBlt() from the window DC to the memory DC to copy the bitmap to memory; GetObject() to copy the bitmap data from the in-memory bitmap handle to a buffer in the application; create the headers necessary for making a BMP file; convert the local bitmap data buffer to a device-independent bitmap; write the bitmap headers to the file; write the DIB bitmap data to the file.
Okay, still a lot when I write it like that, but something that can be done.
The only thing I'm worried about is if this will actually get a full bitmap from LB. It could be that the steps above is exactly what LB is doing internally when you use GETBMP, and the reason that it doesn't capture anything beyond the window is because LB doesn't bother to draw anything beyond the window, meaning attempting to pull that data could still be useless.
|
|
|
Post by Rod on Jun 28, 2020 4:46:51 GMT -5
Well no, Liberty can hold the whole bmp and we can draw to the whole bmp. We know that because we can print huge unseen bmps. So don't restrict it to the window size use the size of the DC image? I know we can hold huge bmps in a DC so perhaps we leave Liberty to the side and just work with a couple of DCs?
|
|
|
Post by Chris Iverson on Jun 28, 2020 16:47:08 GMT -5
That may be what we have to do in the meantime, until LB5 is production-ready. I know LB can hold those bitmaps in memory(as you point out with being able to print the whole thing), but the problem is, I can't seem to find a way to reference that memory.
In the example given, the DC that gets cloned is the window DC, which is typically clamped to the size of the drawing area. If I pull the graphicbox's DC, and grab the bitmap in it, that bitmap is locked to the size of the graphics window.
|
|
|
Post by Rod on Jun 29, 2020 3:05:54 GMT -5
Here is how I would start, this gets a large bmp in a DC other than the screen DC and it can be of any size.
When I get a little more time I am going to experiment and see if I can get the large bmp to copy from the screen DC to the memory DC I know I can load the large bmp to the screen DC and I can see it and scroll it. Getting it into the memory DC will be the trick, either with select object or blitting one to the other.
nomainwin WindowWidth = 600 WindowHeight = 600 UpperLeftX = (DisplayWidth-WindowWidth)/2 UpperLeftY = (DisplayHeight-WindowHeight)/2 graphicbox #1.g, 50,80,500,300 open "Blitter" for graphics_nf_nsb as #1 #1 "trapclose [quit]"
' bDC is our screen buffer, (DC handle to the graphicsbox) 'it already exists bDC=GetDC(hwnd(#1.g))
' mDC is a copy of the screen in memory 'we need to create it mDC=CreateCompatibleDC(bDC)
'now select a large bmp into it, its amorphous loadbmp "largebmp","c:\basic\jetski\base.bmp" hBitmap=hbmp("largebmp") oldBmp=SelectObject(mDC,hBitmap)
'now you have a very large bmp sitting in mDC 'it is that DC we need to grab and save as a bmp.
wait
Function GetDC(hWnd) CallDLL #user32, "GetDC",_ hWnd As ulong,_ 'window or control handle GetDC As ulong 'returns device context End Function
Function CreateCompatibleDC(hDC) CallDLL #gdi32,"CreateCompatibleDC",_ hDC As ulong,_ 'window DC CreateCompatibleDC As ulong 'memory DC End Function
Function SelectObject(hDC,hObject) CallDLL #gdi32,"SelectObject",_ hDC As ulong,_ 'memory device context hObject As long,_ 'handle of object SelectObject As long 'returns previously selected object End Function
|
|
|
Post by Rod on Jun 29, 2020 4:25:27 GMT -5
Well I am remembering doing all this stuff years ago. Then I knew even less about blitting and DCs. It seems the screen is the stumbling block, while the image it may hold can be huge you cant get a copy of it with getbmp or blit. Chris may know of another method to copy the screen contents but given we have not had that functionality for so long perhaps not.
However all is not lost because we can interact with a DC, we could draw the bmp directly to the DC and we can do all of the usual line drawing and text placement by API. We can blit it into view in Liberty and scroll it about.
So it would be really useful to have code that takes a DC and saves it as a .bmp.
nomainwin WindowWidth = 600 WindowHeight = 750 UpperLeftX = (DisplayWidth-WindowWidth)/2 UpperLeftY = (DisplayHeight-WindowHeight)/2 graphicbox #1.g, 50,50,500,300 graphicbox #1.h, 50,400,500,300 open "Blitter" for graphics_nf_nsb as #1 #1 "trapclose [quit]"
'fill the screen with a large bmp loadbmp "largebmp","c:\basic\jetski\base.bmp" #1.g "down ; drawbmp largebmp 0 0" #1.h "down ; fill black"
' gDC is DC handle to the graphicsbox #1.g) 'it already exists gDC=GetDC(hwnd(#1.g))
' hDC is DC handle to the graphicsbox #1.h) 'it already exists hDC=GetDC(hwnd(#1.h))
'this does not work=========================
'blit the bottom right portion of the large 'graphic 1600,600 to #1.g from #1.h to show blit 'does not get access to full bmp result=blit(hDC,0,0,500,300,gDC,1100,300)
' mDC is a copy of gDC in memory 'we need to create it mDC=CreateCompatibleDC(gDC)
'now select a large bmp into it, its amorphous hBitmap=hbmp("largebmp") oldBmp=SelectObject(mDC,hBitmap)
'this does work==============================
'blit the bottom right portion of the large 'graphic 1600,600 to #1.g from mDC to prove it is there result=blit(hDC,0,0,500,300,mDC,1100,300)
'now you have a very large bmp sitting in mDC 'it is that DC we need to grab and save as a bmp.
wait [quit] close#1 end
Function GetDC(hWnd) CallDLL #user32, "GetDC",_ hWnd As ulong,_ 'window or control handle GetDC As ulong 'returns device context End Function
Function CreateCompatibleDC(hDC) CallDLL #gdi32,"CreateCompatibleDC",_ hDC As ulong,_ 'window DC CreateCompatibleDC As ulong 'memory DC End Function
Function SelectObject(hDC,hObject) CallDLL #gdi32,"SelectObject",_ hDC As ulong,_ 'memory device context hObject As long,_ 'handle of object SelectObject As long 'returns previously selected object End Function
function blit(dDC,x,y,w,h,sDC,sx,sy) CallDll #gdi32, "BitBlt", _ dDC as ulong,_ 'The destination DC x as long,_ 'x location on destination y as long,_ 'y location on destination w as long,_ 'width to transfer h as long,_ 'height to transfer sDC as ulong,_ 'The source DC sx as long,_ 'x location in source sy as long,_ 'y location in source _SRCCOPY as ulong,_ 'The operation to be performed blit as long 'nonzero if successful end function
|
|
|
Post by tenochtitlanuk on Jul 1, 2020 6:14:43 GMT -5
While we wait for LB5 you might get some mileage from Francesco's technique- which he supplied with a ready made function for us. Basically he moves the extra-large image behind the graphicbox and temporarily saves each visible section as a grid of tiles, then programmatically assembles them into the required BMP format. ( BMP file format is well documented and several of us have done similar manipulation) His example creates an 1800x1800 BMP but only part is visible when first created as the graphicbox display window he used is only 600x600. Easily modified to your choice- perhaps 500x500 display of part of your 5000x5000. If you watch it run you'll see the successive gridded sections briefly in the window as the screen image is moved by 'locate'. Just a thought. 'JB Spirograph v0.02 pre-alfa :) By Francesco
'Main purpose is to demonstrate the use of the function SaveGraphicBox. 'See below to read more about that function. 'The pic will be saved to the current dir with name "Spirograph.bmp"
'Here you can initialize bmp file settings ImageWidth =1800: ImageHeight =1800: xdpi =300:ydpi =300: FileName$ ="Spirograph.bmp"
'Open 600x600 window and (ImageWidth)x(ImageHeight) graphicbox nomainwin WindowWidth =600: WindowHeight =600 UpperLeftX =( DisplayWidth -WindowWidth) /2: UpperLeftY =( DisplayHeight -WindowHeight) /2 graphicbox #w.g, 0, 0, ImageWidth, ImageHeight
open "JB Spirograph v0.01 by Francesco" for window_nf as #w
'Initialize random values for the epicycloid x0 =ImageWidth /2: y0 =ImageHeight /2: r1 =0: r2 =0: p =0: da =1: i =x0: if x0 >y0 then i =y0 t =int( i /50): if t <5 then t =5
while ( r1 +r2 +p) <int( i /2) while r1=r2 r1 =int( t +( i -2 *t) *rnd( 1)) while r2 =0: r2 =int( t +( i -r1 -2 *t) *rnd( 1)) -r1: wend wend p =int( t +( i -r1 -r2 -t) *rnd( 1)) wend
if abs( r1) <=abs( r2) then t =abs( r1) if abs( r1) >abs( r2) then t =abs( r2)
for i =t to 1 step -1 if ( ( abs( r1) mod i) =0) and ( ( abs( r2) mod i) =0) then if i>1 then n =int( 360 *abs( r2) /i): i =0 if i=1 then n =int( 360 *abs( r2) /3) end if next
'Here you can re-initialize the values of the spirograph. 'Uncomment next lines and set your values 'or they will be (reasonably) random.
'r1 = 60 '(pixels) radius of main circle 'r2 = 60 '(pixels) radius of second circle 'p = 60 '(pixels) offset of drawing point relative to 2nd circle 'da = 1 '(degrees) increment of the angle (resolution) 'n = 34560 '(decimal) number of points to calculate
'Draw epicycloid print #w.g, "down; place 0 0; color white; backcolor white" print #w.g, "boxfilled "; ImageWidth; " "; ImageHeight print #w.g, "flush; color black" a =0 print #w.g, "place "; x0 +r1 +r2 +p; " "; y0
for i = 1 to n ar =asn( 1) /90 *a x =int( ( r1 +r2) *cos( ar) +p *cos( ( r1 +r2) *ar /r2)) y =int( ( r1 +r2) *sin( ar) +p *sin( ( r1 +r2) *ar /r2)) print #w.g, "goto "; x0 +x; " "; y0 +y a =a +da next
print #w.g, "flush"
'Call SaveGraphicBox function, show result and exit t =SaveGraphicBox( FileName$, "#w.g", 0, 0, ImageWidth, ImageHeight, xdpi, ydpi)
run "rundll32.exe C:\Windows\system32\shimgvw.dll,ImageView_Fullscreen "+DefaultDir$ +"\" +FileName$
close #w
end
'**************************************************************************************************** '* SaveGraphicBox saves part of a graphicbox to a bmp file to the default dir path. '* This function can grab and save the bitmap of very large graphicboxes while getbmp+bmpsave '* can grab and save only visible parts of them, thus being limited by the size of the desktop. '* This function moves the graphicbox and grabs it divided in many small bmp files and then '* merges them to single large bmp file. The graphicbox must be opened in a "window" type window. '* '* Parameters: '* FileName$: name of the bmp file '* boxHandle$: handle of the graphicbox '* xStart: x of upper left corner of the portion to grab '* yStart: y of upper left corner of the portion to grab '* xSize: horizontal size in pixels of the portion to grab '* ySize: vertical size in pixels of the portion to grab '* xdpi: horizontal dpi that will be stored in bmp file header '* ydpi: vertical dpi that will be stored in bmp file header '****************************************************************************************************
function SaveGraphicBox( FileName$, boxHandle$, xStart, yStart, xSize, ySize, xdpi, ydpi) SaveGraphicBox =0: winHandle$ =left$( boxHandle$, instr( boxHandle$, ".") -1) nx =1 +int( ( xSize -1) /500): ny =1 +int( ( ySize -1) /500) ly =-1 *yStart: nt =1: yS =ySize
for i =1 to ny lx = -1 *xStart: xS =xSize for j =1 to nx dx =500: if xS <500 then dx =xS dy =500: if yS <500 then dy =yS print #boxHandle$, "locate "; lx; " "; ly; " "; 500 -1 *lx +2; " "; 500 -1 *ly +2 print #winHandle$, "refresh": print #boxHandle$, "flush" print #boxHandle$, "getbmp bmp "; -1 *lx; " "; -1 *ly; " "; dx; " "; dy bmpsave "bmp", "SGBtemp" +right$( "00" +str$( nt), 3) +".bmp" lx =lx -500: xS =xS -500: nt =nt +1 next ly =ly -500: yS =yS -500 next
print #boxHandle$, "locate 0 0 "; WindowWidth; " "; WindowHeight print #winHandle$, "refresh": print #boxHandle$, "flush" open "SGBtemp001.bmp" for input as #1: h$ =input$( #1, 14) hlen =asc( mid$( h$, 11, 1)) +256 *asc( mid$( h$, 12, 1)) +256 *256 *asc( mid$( h$, 13, 1)) +256 *256 *256 *asc( mid$( h$, 14, 1)) h$ =h$ +input$( #1, hlen -14): close #1 nt=1: bmlen =0
for i=1 to ny for j=1 to nx open "SGBtemp"+right$("00"+str$( nt),3)+".bmp" for input as #1:t$=input$(#1,6):close #1 l=asc( mid$( t$, 3, 1) )+256 *asc( mid$( t$, 4, 1)) +256 *256 *asc( mid$( t$, 5, 1)) +256 *256 *256 *asc( mid$( t$, 6,1)) bmlen =bmlen +l -hlen: nt =nt +1 next next
pixlen =int( bmlen /( xSize *ySize))
open FileName$ for output as #1: n =int( bmlen /1000)
print #1, h$;
for i =1 to n: print #1, space$( 1000);: next print #1, space$( bmlen -n *1000); close #1
open FileName$ for binary as #1: actualseek =hlen t =lof( #1): seek #1, 2: for i =1 to 4: print #1, chr$( t and 255);: t =t/256: next t =xSize: seek #1, 18: for i =1 to 4: print #1, chr$( t and 255);: t =t/256: next t =ySize: seek #1, 22: for i =1 to 4: print #1, chr$( t and 255);: t =t/256: next t =bmlen: seek #1, 34: for i =1 to 4: print #1, chr$( t and 255);: t =t/256: next t =int( xdpi*(100/2.54)): seek #1, 38: for i =1 to 4: print #1, chr$( t and 255);: t =t/256: next t =int( ydpi *( 100 /2.54)): seek #1, 42: for i =1 to 4: print #1, chr$( t and 255);: t =t /256: next
for i =ny to 1 step -1 t =0 for j =1 to nx nt =( i -1) *nx +j
open "SGBtemp"+right$("00"+str$(nt),3)+".bmp" for input as #2 t$ =input$( #2, hlen) w =asc( mid$( t$, 19, 1)) +256 *asc( mid$( t$, 20, 1)) +256 *256 *asc( mid$( t$, 21, 1)) +256 *256 *256 *asc( mid$( t$, 22, 1)) h =asc( mid$( t$, 23, 1)) +256 *asc( mid$( t$, 24, 1)) +256 *256 *asc( mid$( t$, 25, 1)) +256 *256 *256 *asc( mid$( t$, 26, 1)) for k =1 to h seek #1, actualseek +t +( k -1) *xSize *pixlen print #1, input$( #2, w *pixlen) next close #2 t =t +w *pixlen next actualseek =loc( #1) next
close #1 nt =1
for i =1 to ny for j =1 to nx kill "SGBtemp" +right$( "00" +str$( nt), 3) +".bmp" nt =nt +1 next j next i end function
Example image with grid coordinates superposed..
|
|
|
Post by tenochtitlanuk on Jul 5, 2020 13:49:31 GMT -5
In a sense, this time I do the opposite- take the kind of large BMP that this code can generate, and move it 'behind' a graphicbox window to display part. This version allows you to click on desired horizontal/vertical position, but you could instead drag it, or click at an edge or corner and have it move in that direction... below is an animation of a series of moused movements..
You'll need the or create your own ( 24 bit) Incidentally, on my Linux setup, at least, de-remming the lines to save after each alteration mess up the redraw. Is this an LB bug???
' *********************************************************** ' ** ** ' ** scrollBigBmpInWindow3.bas July 4 2020 ** ' ** ** ' ** tenochtitlanuk 5 July 2020 ** ' ** ** ' ** Demonstrates moving a large BMP viewed in a ** ' ** small graphicbox. ** ' ** ** ' ***********************************************************
nomainwin
WindowWidth =560: WindowHeight =600 UpperLeftX =100: UpperLeftY =100
graphicbox #w.g1, 10, 10, 500, 500 graphicbox #w.g2, 520, 10, 20, 500 graphicbox #w.g3, 10, 520, 500, 20
global XX, YY
open "Scrolling big BMP in smaller graphicbox." for window as #w
#w "trapclose quit"
#w.g2 "when leftButtonUp changeY" #w.g3 "when leftButtonUp changeX"
#w.g2 "size 8 ; down" #w.g3 "size 8 ; down"
XX =900 YY =900
loadbmp "scr", "Spirograph.bmp"
#w.g1 "down ; drawbmp scr "; XX -1800 +250; " "; YY -1800 +250 #w.g1 "flush" #w.g2 "set 10 250" #w.g3 "set 250 10"
wait
sub quit h$ close #w end end sub
sub changeX h$, x, y XX =int( ( 500 -x) /500 *1800) #w.g3 "cls ; set "; x; " 10" #w.g1 "cls ; drawbmp scr "; XX -1800 +250; " "; YY -1800 +250 #w.g1 "flush" '#w.g1 "getbmp scr 0 0 500 500": fOut$ ="forAnimn" +str$( time$( "seconds")) +".bmp": bmpsave "scr", fOut$ end sub
sub changeY h$, x, y YY =int( ( 500 -y) /500 *1800) #w.g2 "cls ; set 10 "; y #w.g1 "cls ; drawbmp scr "; XX -1800 +250; " "; YY -1800 +250 #w.g1 "flush" '#w.g1 "getbmp scr 0 0 500 500": fOut$ ="forAnimn" +str$( time$( "seconds")) +".bmp": bmpsave "scr", fOut$ end sub
sub sleep ms 'calldll #kernel32, "Sleep", ms as long, ret as void end sub
|
|
|
Post by Rod on Jul 5, 2020 14:05:32 GMT -5
Is it because getbmp scr replaces the original full sized scr with the reduced sized getbmp scr
|
|