No announcement yet.

GRAPHIC Commands

  • Filter
  • Time
  • Show
Clear All
new posts

  • GRAPHIC Commands

    Contained in a Byte array named MapArray(1 to 1639478) is a 1280 by 1280 pixel BMP with a 256 color LUT. The contents of this array was not loaded as a BMP file from disc but instead was computed from a proprietary and highly-compressed image file. The content of the array represents a topographic map and it is desired to overlay this map with symbology created by the GRAPHIC set of PB commands

    One method for accomplishing this is:

    CompositePath = "C:\MAP.BMP"
    PUT 1, 1, MapArray()
    CLOSE 1

    GRAPHIC BITMAP LOAD CompositePath,1280,1280 TO BMPHandle
    GRAPHIC SCALE (0,0)-(1279,1279)

    CALL DrawRings
    CALL DrawAircraft
    CALL DrawFeatures

    GRAPHIC SAVE CompositePath

    Is there some alternate approach which would avoid the need to firstly, save the contents of MapArray to disc as a BMP file via the PUT statement and secondly, reload the BMP file for GRAPHIC operations via the GRAPHIC BITMAP LOAD statement?

    Might I somehow establish a BMPHandle for MapArray and directly use GRAPHIC ATTACH BMPHandle to initiate the drawing function?

  • #2
    Not sure if this is what you mean, but I have a application that sends/receives a bitmap string and loads the bitmap without having to save it to a temp file first. The function listed below will load the bitmap and return a bitmap handle you can use to display it. (I have never used the built in GRAPHICS commands so I can't say for sure that they will work with it, but I had no problems using the returned bitmap handle with SelectObject() in to a DC.) You should be able to modify it to suit your needs.

    Function MemCopyD(ByVal src AS Long, ByVal dst AS Long, ByVal ln AS Long) AS Long
    #Register None
       ! cld
       ! mov esi, src
       ! mov edi, dst
       ! mov ecx, ln
       ! shr ecx, 2
       ! rep movsd
       ! mov ecx, ln
       ! And ecx, 3
       ! rep movsb
       Function = 0
    End Function
    Function BMPload(sBmp As String, ByVal flag As Long, hPalette As Long ) As Dword
       Local iRet     As Long
       Local dRet     As Dword
       Local hFile    As Long
       Local dcWindow AS Long
       Local dcBitmap As Long
       Local bmf      AS BITMAPFILEHEADER Ptr
       Local bmi      AS BITMAPINFO Ptr
       Local bm       As Bitmap
       Local hBmp     As Long
       bm.bmBits = 0  'make sure the pointer is init 0
          Select Case flag
             Case %LR_LOADFROMFILE
                hFile = FreeFile
                Open sBmp For Binary AS hFile
                If Err = 0 Then Get$ hFile, Lof(hFile), sBmp
                Close #hFile
             Case %LR_LOADFROMSTRING
             Case Else
                'MSGBOX "Invalid flag. Pls use %LR_LOADFROMFILE or %LR_LOADFROMSTRING", %MB_ICONSTOP, "loadBmp"
                Exit Function
          End Select
          If sBmp = "" Then Exit Function
          If Len( sBmp ) < ( Len(BITMAPFILEHEADER) + Len( BITMAPINFO ) ) Then Exit Function
          bmf = StrPtr(sBmp)
          bmi = bmf + Len(BITMAPFILEHEADER)
          If @bmi.bmiHeader.biBitCount = 8  Then
             hPalette = @bmi.bmiHeader.biClrUsed
             If hPalette = 0 Then hPalette = 256
             @bmi.bmiHeader.biClrImportant = MakLng(&H300, hPalette)
             hPalette = CreatePalette (ByVal VarPtr(@bmi.bmiHeader.biClrImportant))
          End If
          dcWindow = GetDC(%HWND_DESKTOP)
          If dcWindow Then
             dcBitmap = CreateCompatibleDC(dcWindow)
             If dcBitmap Then
                hBmp = CreateDIBSection(dcBitmap, @bmi, %DIB_RGB_COLORS, 0, 0, 0)
                If hBmp Then
                   'Call GlobalLock(hBmp) 'says invalid handle so I dont think we need this for a bitmap object handle
                   dRet = SelectObject(dcBitmap, hBmp)
                   If dRet = %GDI_ERROR Or dRet = 0 Then
                      MyMsg "SelectObject Error in BMPLoad function."
                      If GetObject(hBmp, SizeOf(bm), bm) Then
                         If bm.bmBits <> 0 Then
                            Call MemCopyD(StrPtr(sBmp) + @bmf.bfOffBits, bm.bmBits, (bm.bmWidthBytes * bm.bmHeight))
                            MyMsg "Pointer Error in BMPLoad function.   bm.bmBits=0"
                         End If
                         MyMsg "GetObject Error in BMPLoad function."
                      End If
                   End If
                   iRet = GetLastError()
                   MyMsg "CreateDIBSection Error in BMPLoad function.  Err=" + WinErrMsg(iRet)
                End If
                MyMsg "CreateCompatibleDC Error in BMPLoad function."
             End If
             MyMsg "GetDC Error in BMPLoad function."
          End If
          If dcBitmap Then Call DeleteDC(dcBitmap)
          If dcWindow Then Call ReleaseDC(%HWND_DESKTOP, dcWindow)
          Function = hBmp
          MsgBox Error$(Err),,"BMPLoad trapped Error"
       End Try
    End Function
    FYI, the MyMsg function just displays a message in the log, change them to msgbox statements if you want.
    "I haven't lost my mind... its backed up on tape... I think??" :D


    • #3
      Thanks for the response, William. Unfortunately, I am currently not familar enough with the API to immediately adapt your function to my problem. The function certainly looks applicable as I already have the BMP loaded into the byte array ( MapArray ) and could create the BMP string to pass to your code. It is a shame that the PB statement :

      GRAPHIC BITMAP LOAD CompositePath,1280,1280 TO BMPHandle
      cannot accept the BMP in a string form and avoid the entire issue. I will continue to try and understand how I might use your function in my application.


      • #4
        Is there some alternate approach which would avoid the need to firstly, save the contents of MapArray to disc
        CreateBitmapIndirect() ==> hBMP

        Whether or not "any valid hBMP" is usable with the PB GRAPHICS commands unknown (to me, anyway).

        But what's so wrong/bad about saving to disk first? Windows itself does this zillions of times each day. And YOU can go one better by actually DELETING the temp disk file, which Windows is not really good about doing, as demonstrated by a directory of my temp folder.

        Michael Mattias
        Tal Systems (retired)
        Port Washington WI USA
        [email protected]


        • #5
          Thanks for the suggestion, Mike. The motivation for trying to bypass to store to disc --- reload from disc --- procedure is computational speed. This application is a real-time map display, driven by a GPS receiver, in which one must decompress the appropriate map image from a library, create a 1280 by 1280 pixel BMP, rotate the BMP to the direction of travel, and overlay some complex symbology, all in about 1/2 second. I am looking to eliminate any apparently wasteful operations, one of which seems to be the store/reload procedure.


          • #6
            if you process your 256 colour bitmap and lookup table into a 32 bit array of pixel values then you can copy that 32bit array into a bitmap using GRAPHIC SET BITS. I'm not sure how much time you might save because when writing a file to disk, immediately reading it back then deleting it, the file is almost certainly never written to disk but is held in cache for the duration.



            • #7
              I'm not sure how much time you might save because when writing a file to disk, immediately reading it back then deleting it, the file is almost certainly never written to disk but is held in cache for the duration

              This is an interesting comment, Paul. Actually, I never delete the temp file. I just overwrite it during the next processing cycle. I just timed the write/readback statements and got about 50 milliseconds for the process which seems like a lot if cache is being used. I used the Timer function which I suppose is somewhat suspect. How would one be sure that your cache assumption is correct?


              • #8
                If all bitmaps are the same size, why not use Paul's idea re GRAPHIC SET BITS?
                  GRAPHIC BITMAP LOAD  dummyfileofcorrectsize  to hBMP 
                    Wait for next command or whatever
                    GRAPHIC SET BITS of hBMP =  New data 

                Michael Mattias
                Tal Systems (retired)
                Port Washington WI USA
                [email protected]


                • #9
                  Yes Mike. I am trying to work Paul's idea into the problem but I am having some trouble with the LUT issue. The computed BMPs are 256 color images and the GRAPHIC BITMAP LOAD and GRAPHIC SET BITS convert them to full-color BMPs. My image rotation algorithm is designed for 256 color images and conversion to a rotation of full-color images will really slow that aspect of the process. I haven't given up, however.

                  Do you have any thoughts on Paul's cache assumption and my 50 millisecond timing result on a 3GHz machine?



                  • #10
                    Do you have any thoughts on Paul's cache assumption and my 50 millisecond timing result on a 3GHz machine?
                    I trust Paul, he's better at this kind of thing than am I.

                    Of course, you could always learn the four or five API calls you'd need to do this whole job without relying on any of the GRAPHICS statements.

                    Or, engage someone to develop exactly what you need (Positions Wanted/Offered Forum). Imagine the "one line function call" you'd like to make to refresh the screen, and see if someone can write it that way for you at a reasonable price.. e.g.....
                    I want to write:
                      CALL UpdateMyScreen (mapDataArray(), hWnd)
                    Please provide price,delivery and warranty information."
                    Michael Mattias
                    Tal Systems (retired)
                    Port Washington WI USA
                    [email protected]


                    • #11
                      looks like I was wrong (perhaps not, see later message). It's only while the file is open that it remains in the cache, as soon as it's closed the cache gets flushed to disk so it takes around 30ms on my computer, about consistent with the disk speed.

                      The 2 alternatives that come to mind are:
                      1) set up a RAM drive on your computer and use that. I've never tried it but details are available on the internet,

                      2) do the conversion yourself in memory without using files.
                      The format of the original BMP file is known. The format you need to convert it to is as described in the PB documentation under "GRAPHIC SET BITS"
                      You need to extract the pallette from the original BMP, create a new string of size width*height*4+8 bytes. Fill in the height and width as the first 8 bytes then for each pixel in the original, look up the pixel value, look up the correcponding 32 bit colour from the pallette, put that colour into the string.
                      Then, use GRAPHIC SET BITS to write that to the graphic window.

                      That should be a lot quicker than files.

                      Last edited by Paul Dixon; 21 Nov 2008, 06:23 PM.


                      • #12
                        Another Ram Drive location to try is:
                        What Do I Need?
                        Before I start, I must make this clear, this is aimed at Windows 98 and higher users, and secondly, there are two software programs available, RAMDisk and RAMDiskNT. The first one only offers a maximum of 30Mb, the latter offers up to 4Gb. ...
                        I just set up the (free) 30 mb drive and it shows in Explorer as Z drive. Very good instructions on the page above. What I did was C&P the instructions to a text editor (saved them to the sane folder the driver is in) before starting and then when had to reboot to initiate the driver, it was easy to continue.

                        Dunno if 30mb will be enough for you, Norm. If not the page points to the 4gig driver but it costs 50 bucks (after 100 uses free trial).

                        Another thought. If a Ram Drive doesn't work out (not big enough or ...), then maybe a flash drive. They come in pretty big sizes today (multi gig I think) and prices are coming down pretty fast. I think they're a lot faster than disk drives as well.
                        Last edited by Gösta H. Lovgren-2; 19 Nov 2008, 09:25 AM. Reason: Flashier output
                        It's a pretty day. I hope you enjoy it.


                        JWAM: (Quit Smoking):
                        LDN - A Miracle Drug:


                        • #13
                          Thanks for your suggestions. Last night I tried a test to get some idea how long it might take to assemble the BMP string for a 1280 by 1280 pixel image and a dummy pixel color "ABCD". The quickest method seem to be to use Peek and Poke and the result was about 350 milliseconds. The GRAPHIC GET BITS command to assemble such a string works a lot faster than that so I am somewhat dismayed by my inexperienced approach.

                             Global BMPString as String*6553600
                             Global PixelString as String*4
                             PixelString = "ABCD"
                             SourceAddress = VARPTR(PixelString)
                             BMPStringAddress = VARPTR(BMPString)
                             LastAddress=BMPStringAddress + 6553596
                             FOR TargetAddress = BMPStringAddress TO LastAddress STEP 4
                                POKE$ TargetAddress, PEEK$(SourceAddress, ArrayLength)
                             NEXT TargetAddress


                          • #14
                            Hello again, Paul
                            The report on your RAM disc idea is a big plus. There were some concerns expressed on the site listed in your last message as well as on the RAM disc site provided by Gosta that made me a bit nervous. I found the site below which provided a Microsoft-certified installation for all version of Vista and XP. It's cost is a modest $35 and it installed without the slightest hitch. Double click on the installation EXE and everything is roses thereafter. It is lighting fast and will save the constant pounding of the hard disc by the cyclic storage of the 4MB image file (i.e., on the order of twice per second driven by the GPS update rate). It is a brute force but functionally beautiful solution. Thanks to all for the assistance. Norm



                            • #15
                              good you got it sorted.
                              I didn't have time to look into it last week but the cache thing has been on my mind.
                              I've now investigated and the data is cached as I first thought BUT it is still written to disk as well. The time to write to disk is therefore still significant but the time to read it back is much less. On my system the data can be written to disk at around 60MBytes/sec (the disk speed) but it's read back at over 500MB/sec (the cache speed). So the data is cached but the benefit is only seen on reading.

                              This is probably not of interest to you now snce a RAM disk will be fast in both reading and writing and so should be significantly faster overall.