Author Topic: SaveBMPLibrary  (Read 1219 times)

0 Members and 1 Guest are viewing this topic.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3572
    • Steve’s QB64 Archive Forum
SaveBMPLibrary
« on: November 02, 2018, 05:03:52 AM »
If you guys check around, you'll find that I have a nice SaveImage library (link here: http://qb64.freeforums.net/thread/55/save-image-library ), which can be used to let us save the screen as either a PNG or BMP format.

The issue with this library is that it:
1) Apparently doesn't work on Linux/Mac
2) It also has recently been a PITA for me to try and convince it to work in the 64-bit version of QB64.

So, with these issues in mind, I decided to back up and punt, and I rebuilt the SaveBMP portion to make it where it'd work on *any* OS for us.  Linux, Mac, Windows -- 32 and 64 bit -- none should have any issue with this library.

IF you're on Windows, using the 32-bit version of QB64, feel free to keep using SaveImage.  It does all this does, and then some.  This is just a replacement so folks who can't use the one, can still easily plug in a quick routine to save images from their program.

Code is below:

Code: QB64: [Select]
  1. CONST SaveTextAs256Color = 0 'or -1 if you want to save screen 0 text screens in 256 colors
  2. 'Note, you can also make the variable DIM SHARED, and then change its value as needed for your work.
  3. '      Just change its value before you make the call to SaveBMP or SaveFullBMP.
  4.  
  5. CLS , 2
  6.  
  7. FOR i = 0 TO 15
  8.     COLOR 15 - i
  9.     PRINT "COLOR "; i
  10. SaveBMP "test.bmp", 0, 0, 0, _WIDTH, _HEIGHT
  11.  
  12.  
  13.  
  14.  
  15.  
  16.  
  17. '**************************
  18. ' Code beyond this point can go into a nice SaveBMPLibrary.BM
  19. '**************************
  20.  
  21.  
  22.  
  23. SUB SaveFullBMP (filename$)
  24.     SaveBMP filename$, 0, 0, 0, _WIDTH - 1, _HEIGHT - 1
  25.  
  26. SUB SaveBMP (filename$, image&, x1%, y1%, x2%, y2%)
  27.     'Super special STEVE-Approved BMP Export routine for use with any QB64 graphic mode.
  28.     IF x1% < 0 OR y1% < 0 THEN ERROR 5: EXIT FUNCTION
  29.     IF x2% > _WIDTH(image&) OR y2% > _HEIGHT(image&) THEN ERROR 5: EXIT FUNCTION
  30.     IF x2% = _WIDTH(image&) THEN x2% = x2% - 1
  31.     IF y2% = _HEIGHT(image&) THEN y2% = y2% - 1
  32.  
  33.     IF _PIXELSIZE(image&) = 0 THEN
  34.         IF SaveTextAs256Color THEN
  35.             tempimage& = TextScreenToImage256&(image&)
  36.         ELSE
  37.             tempimage& = TextScreenToImage32&(image&)
  38.         END IF
  39.         F = _FONT(image&)
  40.         FW = _FONTWIDTH(F): FH = _FONTHEIGHT(F)
  41.         SaveBMP filename$, tempimage&, x1% * FW, y1% * FH, x2% * FW, y2% * FH
  42.         _FREEIMAGE tempimage&
  43.         EXIT FUNCTION
  44.     END IF
  45.  
  46.     TYPE BMPFormat
  47.         ID AS STRING * 2
  48.         Size AS LONG
  49.         Blank AS LONG
  50.         Offset AS LONG
  51.         Hsize AS LONG
  52.         PWidth AS LONG
  53.         PDepth AS LONG
  54.         Planes AS INTEGER
  55.         BPP AS INTEGER
  56.         Compression AS LONG
  57.         ImageBytes AS LONG
  58.         Xres AS LONG
  59.         Yres AS LONG
  60.         NumColors AS LONG
  61.         SigColors AS LONG
  62.     END TYPE
  63.  
  64.  
  65.     DIM BMP AS BMPFormat
  66.     DIM x AS LONG, y AS LONG
  67.     DIM temp AS STRING, t AS STRING * 1
  68.  
  69.     DIM n AS _MEM, o AS _OFFSET, m AS _MEM
  70.     m = _MEMIMAGE(image&)
  71.  
  72.     IF x1% > x2% THEN SWAP x1%, x2%
  73.     IF y1% > y2% THEN SWAP y1%, y2%
  74.     IF x2% = _WIDTH(imagehandle%) THEN x2% = _WIDTH(imagehandle%) - 1 'troubleshoot in case user does a common mistake for 0-width instead of 0 - (width-1) for fullscreen
  75.     IF y2% = _HEIGHT(imagehandle%) THEN y2% = _HEIGHT(imagehandle%) - 1 'troubleshoot in case user does a common mistake for 0-width instead of 0 - (width-1) for fullscreen
  76.  
  77.     s& = _SOURCE
  78.     _SOURCE image&
  79.  
  80.     BMP.PWidth = (x2% - x1%) + 1
  81.     BMP.PDepth = (y2% - y1%) + 1
  82.     BMP.ID = "BM"
  83.     BMP.Blank = 0
  84.     BMP.Hsize = 40
  85.     BMP.Planes = 1
  86.     BMP.Compression = 0
  87.     BMP.Xres = 0
  88.     BMP.Yres = 0
  89.  
  90.     BMP.SigColors = 0
  91.  
  92.     SELECT CASE _PIXELSIZE(image&)
  93.         CASE 1
  94.             temp = SPACE$(x2% - x1% + 1)
  95.             OffsetBITS& = 54 + 1024 'add palette in 256 color modes
  96.             BMP.BPP = 8
  97.             IF BMP.PWidth MOD 4 THEN ZeroPAD$ = SPACE$(4 - (BMP.PWidth MOD 4))
  98.             ImageSize& = (BMP.PWidth + LEN(ZeroPAD$)) * BMP.PDepth
  99.             BMP.ImageBytes = ImageSize&
  100.             BMP.NumColors = 256
  101.             BMP.Size = ImageSize& + OffsetBITS&
  102.             BMP.Offset = OffsetBITS&
  103.         CASE 4
  104.             temp = SPACE$(3)
  105.             OffsetBITS& = 54 'no palette in 24/32 bit
  106.             BMP.BPP = 24
  107.             IF ((BMP.PWidth * 3) MOD 4) THEN ZeroPAD$ = SPACE$(4 - ((BMP.PWidth * 3) MOD 4))
  108.             ImageSize& = (BMP.PWidth + LEN(ZeroPAD$)) * BMP.PDepth
  109.             BMP.ImageBytes = ImageSize&
  110.             BMP.NumColors = 0
  111.             BMP.Size = ImageSize& * 3 + OffsetBITS&
  112.             BMP.Offset = OffsetBITS&
  113.     END SELECT
  114.  
  115.     F = FREEFILE
  116.     n = _MEMNEW(BMP.Size)
  117.     _MEMPUT n, n.OFFSET, BMP
  118.     o = n.OFFSET + 54
  119.     zp& = LEN(ZeroPAD$)
  120.  
  121.     IF BMP.BPP = 8 THEN 'Store the Palette for 256 color mode
  122.         FOR c& = 0 TO 255 ' read BGR color settings from JPG image + 1 byte spacer(CHR$(0))
  123.             cv& = _PALETTECOLOR(c&, image) ' color attribute to read.
  124.             b$ = CHR$(_BLUE32(cv&)) + CHR$(_GREEN32(cv&)) + CHR$(_RED32(cv&)) + CHR$(0) 'spacer byte
  125.             _MEMPUT n, o, b$
  126.             o = o + 4
  127.         NEXT
  128.         y = y2% + 1
  129.         w& = _WIDTH(image&)
  130.         x = x2% - x1% + 1
  131.         DO
  132.             y = y - 1
  133.             _MEMGET m, m.OFFSET + (w& * y + x1%), temp
  134.             _MEMPUT n, o, temp
  135.             o = o + x
  136.             _MEMPUT n, o, ZeroPAD$
  137.             o = o + zp&
  138.         LOOP UNTIL y = y1%
  139.     ELSE
  140.         y = y2% + 1
  141.         w& = _WIDTH(image&)
  142.         DO
  143.             y = y - 1: x = x1% - 1
  144.             DO
  145.                 x = x + 1
  146.                 _MEMGET m, m.OFFSET + (w& * y + x) * 4, temp
  147.                 _MEMPUT n, o, temp
  148.                 o = o + 3
  149.             LOOP UNTIL x = x2%
  150.             _MEMPUT n, o, ZeroPAD$
  151.             o = o + zp&
  152.         LOOP UNTIL y = y1%
  153.     END IF
  154.     _MEMFREE m
  155.     OPEN filename$ FOR BINARY AS #F
  156.     t1$ = SPACE$(BMP.Size)
  157.     _MEMGET n, n.OFFSET, t1$
  158.     PUT #F, , t1$
  159.     _MEMFREE n
  160.     CLOSE #F
  161.     _SOURCE s&
  162.  
  163. FUNCTION TextScreenToImage256& (image&)
  164.     d& = _DEST: s& = _SOURCE
  165.     DIM Plt(15) AS LONG
  166.     _SOURCE image&: _DEST image&
  167.     FOR i = 0 TO 15: Plt(i) = _PALETTECOLOR(i, image&): NEXT
  168.     f& = _FONT(image&)
  169.     _FONT f&
  170.     fw& = _FONTWIDTH
  171.     fh& = _FONTHEIGHT
  172.     w& = _WIDTH * _FONTWIDTH
  173.     h& = _HEIGHT * _FONTHEIGHT '+ _HEIGHT
  174.     l& = (_WIDTH * _HEIGHT) * 2 'The screen is width * height in pixels.  (80X25) = 2000 X 2 bytes each = 4000 total bytes to hold a page of screen 0 text and color
  175.     tempscreen& = _NEWIMAGE(w&, h& + _HEIGHT, 256)
  176.     Screen0to256& = _NEWIMAGE(w&, h&, 256)
  177.  
  178.     DIM m AS _MEM, b AS _UNSIGNED _BYTE, t AS STRING * 1
  179.     DIM o AS _OFFSET
  180.     m = _MEMIMAGE(image&)
  181.     o = m.OFFSET
  182.  
  183.     _DEST (tempscreen&)
  184.     FOR i = 0 TO 15: _PALETTECOLOR i, Plt(i): NEXT
  185.     _FONT f&
  186.  
  187.     FOR i = 0 TO l& - 2 STEP 2
  188.         _MEMGET m, m.OFFSET + i, t
  189.         _MEMGET m, m.OFFSET + i + 1, b
  190.         IF b > 127 THEN b = b - 128
  191.         COLOR b MOD 16, b \ 16
  192.         PRINT t;
  193.     NEXT
  194.     _PUTIMAGE , tempscreen&, Screen0to256&, (0, 0)-(w&, h&)
  195.     _FREEIMAGE tempscreen&
  196.     _DEST d&: _SOURCE s&
  197.     _MEMFREE m
  198.     TextScreenToImage256 = Screen0to256&
  199.  
  200. FUNCTION TextScreenToImage32& (image&)
  201.     d& = _DEST: s& = _SOURCE
  202.     DIM Plt(15) AS LONG
  203.     _SOURCE image&
  204.     FOR i = 0 TO 15: Plt(i) = _PALETTECOLOR(i, image&): NEXT
  205.     f& = _FONT(image&)
  206.     _FONT f&
  207.     fw& = _FONTWIDTH
  208.     fh& = _FONTHEIGHT
  209.     w& = _WIDTH * _FONTWIDTH
  210.     h& = _HEIGHT * _FONTHEIGHT '+ _HEIGHT
  211.     l& = (_WIDTH * _HEIGHT) * 2 'The screen is width * height in pixels.  (80X25) = 2000 X 2 bytes each = 4000 total bytes to hold a page of screen 0 text and color
  212.     tempscreen& = _NEWIMAGE(w&, h& + _HEIGHT, 32)
  213.     Screen0to32& = _NEWIMAGE(w&, h&, 32)
  214.     _DEST tempscreen&
  215.  
  216.     DIM m AS _MEM, b AS _UNSIGNED _BYTE, t AS STRING * 1
  217.     DIM o AS _OFFSET
  218.     m = _MEMIMAGE(image&)
  219.     o = m.OFFSET
  220.  
  221.     _FONT f&
  222.  
  223.     FOR i = 0 TO l& - 2 STEP 2
  224.         _MEMGET m, m.OFFSET + i, t
  225.         _MEMGET m, m.OFFSET + i + 1, b
  226.         IF b > 127 THEN b = b - 128
  227.         fgc = b MOD 16: bgc = b \ 16
  228.         COLOR _RGB32(_RED(fgc, image&), _GREEN(fgc, image&), _BLUE(fgc, image&)), _RGB32(_RED(bgc, image&), _GREEN(bgc, image&), _BLUE(bgc, image&))
  229.         PRINT t;
  230.     NEXT
  231.     _PUTIMAGE , tempscreen&, Screen0to32&, (0, 0)-(w&, h&)
  232.     _FREEIMAGE tempscreen&
  233.     _DEST d&: _SOURCE s&
  234.     _MEMFREE m
  235.     TextScreenToImage32 = Screen0to32&
  236.  
« Last Edit: November 02, 2018, 05:06:26 AM by SMcNeill »
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3572
    • Steve’s QB64 Archive Forum
Re: SaveBMPLibrary
« Reply #1 on: November 02, 2018, 05:22:11 AM »
A brief explaination of the functions.

If you grab the attachment from the first post, just include it in your program, at the bottom of the code, and you're all set to make use of everything.

Code: QB64: [Select]
  1. 'Your code goes first
  2.  
  3.  
  4.  
  5. 'and then down at the end:
  6.  
  7. '$INCLUDE:'SaveBMP.BM'

***************************************

To save the full screen to a BMP file on your disk, it's as simple as:

SaveFullBMP filename$

Screen mode doesn't matter; the routine automatically detects what screen you're in, and it handles everything itself.  Text screens work just fine (SCREEN 0), as well as 256 color and 32 bit color screens.

****************************************

To save a portion of a screen, or an inactive screen, all you do is:

SaveBMP filename$, image&, x1%, y1%, x2%, y2%

filename% is the name of the file you want to save it to.
image& is the image handle you want to save.  (0 for the active desktop.)
And the other 4 are the X/Y coordinates of the screen section you want to save.

For example, to save a section of the screen from 100,100 to 400,400, it'd be:
SaveBMP "whatever.BMP", 0, 100, 100, 400, 400
 
****************************************

If you look, there's also 2 more functions in this little package:

FUNCTION TextScreenToImage256& (image&)
FUNCTION TextScreenToImage32& (image&)


These allow you to take an existing text screen and convert it over to either a 256 color screen, or a 32-bit color screen.

newscreen = TextScreenToImage32& (0) would be all it'd normally take to convert a SCREEN 0 to a 32-bit color screen.

 
****************************************

And, if you look, there *IS* one variable/CONST which you can set, to change the behavior of the routines:

SaveTextAs256Color

Since QB64 currently doesn't load 256 color images, you may not want to save a text screen as a 256 color screen.  (Or, then again, you might, if you're going to use it for something externally and want to reduce overall size of the file.)  This variable lets you change the mode which SaveBMP uses to convert a text screen into.

SaveTextAs256Color = 0   <-- Then you use 32-bit colors when converting and saving.
SaveTextAs256Color = (anything but 0)    <--   Then you use 256 colors when converting and saving.

****************************************
****************************************

And that's the whole thing in a nutshell.  :D
« Last Edit: November 02, 2018, 05:24:20 AM by SMcNeill »
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1062
  • TOXIC
Re: SaveBMPLibrary
« Reply #2 on: November 02, 2018, 07:38:53 AM »
Always liked this one. Thanks for resurrecting it!
TOXIC

Offline Petr

  • Forum Resident
  • Posts: 1580
  • The best code is the DNA of the hops.
Re: SaveBMPLibrary
« Reply #3 on: November 02, 2018, 01:13:02 PM »
Hi Steve. Add here please BI file, because this call:   DIM PNGImageHeader AS PNGImageHeaderType  is not valid now.


No. It is ok, I just have a mess here
« Last Edit: November 02, 2018, 01:24:43 PM by Petr »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3572
    • Steve’s QB64 Archive Forum
Re: SaveBMPLibrary
« Reply #4 on: November 02, 2018, 01:16:25 PM »
Hi Steve. Add here please BI file, because this call:   DIM PNGImageHeader AS PNGImageHeaderType  is not valid now.

We don't use PNG files with this library.  Did I miss removing a reference somewhere?

EDIT:  Nope.  Just checked; no references to PNG in this library.  All this does is BMP files for us, but it does it for all OSes, and both 32-bit and 64-bit versions.
« Last Edit: November 02, 2018, 01:19:56 PM by SMcNeill »
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline Petr

  • Forum Resident
  • Posts: 1580
  • The best code is the DNA of the hops.
Re: SaveBMPLibrary
« Reply #5 on: November 02, 2018, 01:20:12 PM »
my fail
« Last Edit: November 02, 2018, 01:25:07 PM by Petr »

Offline Petr

  • Forum Resident
  • Posts: 1580
  • The best code is the DNA of the hops.
Re: SaveBMPLibrary
« Reply #6 on: November 02, 2018, 01:22:56 PM »
Sorry!!! i read BAD FILE...

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3572
    • Steve’s QB64 Archive Forum
Re: SaveBMPLibrary
« Reply #7 on: November 02, 2018, 01:25:55 PM »
Sorry!!! i read BAD FILE...

No worries.  I think you were looking at the SaveImage library from the other site.  It's more flexible and saves PNG files as well as BMP, but it only runs on Windows 32-bit versions of QB64.  This works for everyone.  :)
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline Petr

  • Forum Resident
  • Posts: 1580
  • The best code is the DNA of the hops.
Re: SaveBMPLibrary
« Reply #8 on: November 02, 2018, 01:30:40 PM »
Ah, you say only in 32-bit versions? I have tried to add your PNG option to my program, but the IDE has compiled it, but program then reported that it was missing the DLL library, although it was in the same folder as EXE.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3572
    • Steve’s QB64 Archive Forum
Re: SaveBMPLibrary
« Reply #9 on: November 02, 2018, 01:59:51 PM »
Ah, you say only in 32-bit versions? I have tried to add your PNG option to my program, but the IDE has compiled it, but program then reported that it was missing the DLL library, although it was in the same folder as EXE.

That's the issue with QB64x64 I was talking about.  It needs a 64-bit version of zlib1.dll to work on 64-bit versions, and I haven't found one of those yet.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline Petr

  • Forum Resident
  • Posts: 1580
  • The best code is the DNA of the hops.
Re: SaveBMPLibrary
« Reply #10 on: November 02, 2018, 02:30:46 PM »
Yeah, so  that's why!. I was rubbing my head when I could see that DLL it was there, but  the program write, that DLL there is not... Thanks, Steve.