SAVEIMAGE: Difference between revisions

From QB64 Phoenix Edition Wiki
Jump to navigation Jump to search
No edit summary
(Add GIF and ICO info)
 
(16 intermediate revisions by 2 users not shown)
Line 1: Line 1:
<center>'''The SAVEIMAGE SUB program to create [[Bitmaps]] of other type Images or Screenshots'''</center>
{{DISPLAYTITLE:_SAVEIMAGE}}
'''_SAVEIMAGE''' saves the contents of an image or screen page to an image file.




<center>'''Bitmaps''' are image files with the .BMP file name extension.</center>
{{PageSyntax}}
: [[_SAVEIMAGE]] {{Parameter|fileName$}}[, {{Parameter|imageHandle&}}][, {{Parameter|requirements$}}]




* Bitmaps can be 1, 4, 8 or 24/32 bits per pixel(BPP) color palettes. QB64 is capable of working with high color bitmaps.
{{PageParameters}}
* Screen or Image width and height calculations are automatically made using the image handle value.
* {{Parameter|fileName$}} is literal or variable [[STRING]] file name value.
* Use an image handle value of 0(zero) to get a screen shot of the entire active program screen.
* Optional {{Parameter|imageHandle&}} is a [[LONG]] image handle or a valid screen page number.
* '''Note: SCREEN 0 text mode cannot be screen saved in QBasic or QB64.'''
* Optional {{Parameter|requirements$}} [[STRING]] values can be:
** '''BMP''': Saves the image as Windows Bitmap if no file extension is specified.
** '''GIF''': Saves the image as Graphics Interchange Format if no file extension is specified.
** '''HDR''': Saves the image as Radiance HDR if no file extension is specified.
** '''ICO''': Saves the image as Windows Icon if no file extension is specified.
** '''JPG''': Saves the image as Joint Photographic Experts Group if no file extension is specified.
** '''PNG''': Saves the image as Portable Network Graphics if no file extension is specified.
** '''QOI''': Saves the image as Quite OK Image if no file extension is specified.
** '''TGA''': Saves the image as Truevision TARGA if no file extension is specified.




''The following example uses a SUB program created to save a 32 bit JPEG image as a bitmap using QB64's graphic functions:''
{{PageDescription}}
* {{Parameter|fileName$}} extension name takes precedence over {{Parameter|requirements$}}
* If no file extension is specified in {{Parameter|fileName$}} and no format is specified in {{Parameter|requirements$}}, then the PNG format is used by default.
* If {{Parameter|imageHandle&}} is omitted then the image handle returned by [[_DISPLAY (function)]] is used.
* Efforts are made to save the image in the highest quality possible using 32-bit RGBA format, ensuring that alpha channel information is retained whenever the format permits.
* Due to the inherent limitations of GIFs, these images are stored in an 8-bit indexed format, which results in a reduction of quality and color detail.
* Windows ICO files utilize the PNG specification, which enables the storage of images exceeding 256x256 pixels in size.
* SCREEN 0 (text mode) screens and "images" can be saved. Text surfaces are rendered internally using the master QB64-PE VGA fonts prior to saving.


: Module Demo Code: Change the _LOADIMAGE filename to an image file you can access.
 
{{PageAvailability}}
<!-- QB64 = a version or none, QBPE = a version or all, Platforms = yes or no -->
<gallery widths="48px" heights="48px" mode="nolines">
File:Qb64.png|'''none'''
File:Qbpe.png|'''v3.9.0'''
File:Apix.png
File:Win.png|'''yes'''
File:Lnx.png|'''yes'''
File:Osx.png|'''yes'''
</gallery>
<!-- Additional availability notes go below the gallery -->
* ICO and GIF support was added in '''QB64-PE v3.14.0'''.
 
 
{{PageExamples}}
;Example 1:It's possible to use '''_SAVEIMAGE''' with text screens.
:This demo draws a Mandelbrot in [[SCREEN]] 0 and then saves the screen as a .jpg image.
{{CodeStart}}
{{CodeStart}}
i& = {{Cl|_LOADIMAGE}}("nice.jpg",32) ' loads a 32 bit .JPG file image
{{Cl|OPTION}} {{Cl|_EXPLICIT}}
SaveImage i&, "nice"      'saves it as .BMP file "nice.bmp"
 
'SaveImage 0, "screenshot" 'saves entire program screen as "screenshot.bmp"
{{Cl|CONST}} X_MIN = {{Text|-2!|#F580B1}}
{{Cl|CONST}} X_MAX = {{Text|1!|#F580B1}}
{{Cl|CONST}} Y_MIN = {{Text|-1!|#F580B1}}
{{Cl|CONST}} Y_MAX = {{Text|1!|#F580B1}}
{{Cl|CONST}} MAX_ITER = {{Text|100|#F580B1}}
{{Cl|CONST}} PIX_CHAR = {{Text|48|#F580B1}}
 
{{Cl|SCREEN}} {{Text|0|#F580B1}}
{{Cl|WIDTH}} {{Text|160|#F580B1}}, {{Text|100|#F580B1}}
{{Cl|_FONT}} {{Text|8|#F580B1}}
 
{{Cl|DIM}} w {{Cl|AS}} {{Cl|LONG}}: w = {{Cl|_WIDTH (function)|_WIDTH}}
{{Cl|DIM}} h {{Cl|AS}} {{Cl|LONG}}: h = {{Cl|_HEIGHT}}
{{Cl|DIM}} maxX {{Cl|AS}} {{Cl|LONG}}: maxX = w - {{Text|1|#F580B1}}
{{Cl|DIM}} maxY {{Cl|AS}} {{Cl|LONG}}: maxY = h - {{Text|1|#F580B1}}
 
{{Cl|DIM}} y {{Cl|AS}} {{Cl|LONG}}: {{Cl|FOR}} y = {{Text|0|#F580B1}} {{Cl|TO}} maxY
    {{Cl|DIM}} x {{Cl|AS}} {{Cl|LONG}}: {{Cl|FOR}} x = {{Text|0|#F580B1}} {{Cl|TO}} maxX
        {{Cl|DIM}} cx {{Cl|AS}} {{Cl|SINGLE}}: cx = X_MIN + (x / w) * (X_MAX - X_MIN)
        {{Cl|DIM}} cy {{Cl|AS}} {{Cl|SINGLE}}: cy = Y_MIN + (y / h) * (Y_MAX - Y_MIN)
 
        {{Cl|DIM}} zx {{Cl|AS}} {{Cl|SINGLE}}: zx = {{Text|0|#F580B1}}
        {{Cl|DIM}} zy {{Cl|AS}} {{Cl|SINGLE}}: zy = {{Text|0|#F580B1}}
        {{Cl|DIM}} i {{Cl|AS}} {{Cl|LONG}}: i = {{Text|0|#F580B1}}
 
        {{Cl|DO...LOOP|DO UNTIL}} zx * zx + zy * zy >= {{Text|4|#F580B1}} {{Cl|OR (boolean)|OR}} i >= MAX_ITER
            {{Cl|DIM}} temp {{Cl|AS}} {{Cl|SINGLE}}: temp = zx * zx - zy * zy + cx
            zy = {{Text|2|#F580B1}} * zx * zy + cy
            zx = temp
            i = i + {{Text|1|#F580B1}}
        {{Cl|LOOP}}
 
        {{Cl|COLOR}} i {{Cl|MOD}} {{Text|16|#F580B1}}
 
        {{Cl|_PRINTSTRING}} (x + {{Text|1|#F580B1}}, y + {{Text|1|#F580B1}}), {{Cl|CHR$}}(PIX_CHAR)
    {{Cl|NEXT}} x
{{Cl|NEXT}} y
 
{{Cl|_SAVEIMAGE}} {{Text|<nowiki>"TextMandelbrot!.jpg"</nowiki>|#FFB100}}
 
{{Cl|END}}
{{Cl|END}}
{{CodeEnd}}
{{CodeEnd}}
----
;Example 2:Saving a graphics image to a .png file. This is much like example one. However, it renders the graphics to an 8-bit offscreen image and then passes the image handle to '''_SAVEIMAGE'''.
{{CodeStart}}
{{CodeStart}}
{{Cl|SUB}} SaveImage (image {{Cl|AS}} {{Cl|LONG}}, filename {{Cl|AS}} {{Cl|STRING}})
{{Cl|OPTION}} {{Cl|_EXPLICIT}}
bytesperpixel& = {{Cl|_PIXELSIZE}}(image&)
 
{{Cl|IF}} bytesperpixel& = 0 {{Cl|THEN}} {{Cl|PRINT}} "Text modes unsupported!": {{Cl|END}}
{{Cl|CONST}} X_MIN = {{Text|-2!|#F580B1}}
{{Cl|IF}} bytesperpixel& = 1 {{Cl|THEN}} bpp& = 8 {{Cl|ELSE}} bpp& = 24
{{Cl|CONST}} X_MAX = {{Text|1!|#F580B1}}
x& = {{Cl|_WIDTH (function)|_WIDTH}}(image&)
{{Cl|CONST}} Y_MIN = {{Text|-1!|#F580B1}}
y& = {{Cl|_HEIGHT}}(image&)
{{Cl|CONST}} Y_MAX = {{Text|1!|#F580B1}}
b$="BM????QB64????"+{{Cl|MKL$}}(40)+{{Cl|MKL$}}(x&)+{{Cl|MKL$}}(y&)+{{Cl|MKI$}}(1)+{{Cl|MKI$}}(bpp&)+{{Cl|MKL$}}(0)+"????"+{{Cl|STRING$}}(16, 0) 'partial BMP header info(???? to be filled later)
{{Cl|CONST}} MAX_ITER = {{Text|100|#F580B1}}
{{Cl|IF}} bytesperpixel& = 1 {{Cl|THEN}}
 
  {{Cl|FOR...NEXT|FOR}} c& = 0 {{Cl|TO}} 255 ' read BGR color settings from JPG image + 1 byte spacer({{Cl|CHR$}}(0))
{{Cl|DIM}} img {{Cl|AS}} {{Cl|LONG}}: img = {{Cl|_NEWIMAGE}}({{Text|640|#F580B1}} * {{Text|2|#F580B1}}, {{Text|400|#F580B1}} * {{Text|2|#F580B1}}, {{Text|256|#F580B1}})
    cv& = {{Cl|_PALETTECOLOR (function)|_PALETTECOLOR}}(c&, image&) ' color attribute to read.
{{Cl|_DEST}} img
    b$ = b$ +{{Cl|CHR$}}({{Cl|_BLUE32}}(cv&))+{{Cl|CHR$}}({{Cl|_GREEN32}}(cv&))+{{Cl|CHR$}}({{Cl|_RED32}}(cv&))+{{Cl|CHR$}}(0) 'spacer byte
 
  {{Cl|NEXT}}
{{Cl|DIM}} w {{Cl|AS}} {{Cl|LONG}}: w = {{Cl|_WIDTH (function)|_WIDTH}}
{{Cl|END IF}}
{{Cl|DIM}} h {{Cl|AS}} {{Cl|LONG}}: h = {{Cl|_HEIGHT}}
{{Cl|MID$}}(b$, 11, 4) = {{Cl|MKL$}}({{Cl|LEN}}(b$)) ' image pixel data offset(BMP header)
{{Cl|DIM}} maxX {{Cl|AS}} {{Cl|LONG}}: maxX = w - {{Text|1|#F580B1}}
lastsource& = {{Cl|_SOURCE}}
{{Cl|DIM}} maxY {{Cl|AS}} {{Cl|LONG}}: maxY = h - {{Text|1|#F580B1}}
{{Cl|_SOURCE}} image&
 
{{Cl|IF}} ((x& * 3) {{Cl|MOD}} 4) {{Cl|THEN}} padder$ = {{Cl|STRING$}}(4 - ((x& * 3) {{Cl|MOD}} 4), 0)
{{Cl|DIM}} y {{Cl|AS}} {{Cl|LONG}}: {{Cl|FOR}} y = {{Text|0|#F580B1}} {{Cl|TO}} maxY
{{Cl|FOR...NEXT|FOR}} py& = y& - 1 {{Cl|TO}} 0 {{Cl|STEP}} -1 ' read JPG image pixel color data
    {{Cl|DIM}} x {{Cl|AS}} {{Cl|LONG}}: {{Cl|FOR}} x = {{Text|0|#F580B1}} {{Cl|TO}} maxX
  r$ = ""
        {{Cl|DIM}} cx {{Cl|AS}} {{Cl|SINGLE}}: cx = X_MIN + (x / maxX) * (X_MAX - X_MIN)
  {{Cl|FOR...NEXT|FOR}} px& = 0 {{Cl|TO}} x& - 1
        {{Cl|DIM}} cy {{Cl|AS}} {{Cl|SINGLE}}: cy = Y_MIN + (y / maxY) * (Y_MAX - Y_MIN)
  c& = {{Cl|POINT}}(px&, py&) 'POINT 32 bit values are large {{Cl|LONG}} values
  {{Cl|IF}} bytesperpixel& = 1 {{Cl|THEN}} r$ = r$ + {{Cl|CHR$}}(c&) {{Cl|ELSE}} r$ = r$ + {{Cl|LEFT$}}({{Cl|MKL$}}(c&), 3)
  {{Cl|NEXT}} px&
  d$ = d$ + r$ + padder$
{{Cl|NEXT}} py&
{{Cl|_SOURCE}} lastsource&
{{Cl|MID$}}(b$, 35, 4) = {{Cl|MKL$}}({{Cl|LEN}}(d$)) ' image size(BMP header)
b$ = b$ + d$ ' total file data bytes to create file
{{Cl|MID$}}(b$, 3, 4) = {{Cl|MKL$}}({{Cl|LEN}}(b$)) ' size of data file(BMP header)
{{Cl|IF}} {{Cl|LCASE$}}({{Cl|RIGHT$}}(filename$, 4)) <> ".bmp" {{Cl|THEN}} ext$ = ".bmp"
f& = {{Cl|FREEFILE}}
{{Cl|OPEN}} filename$ + ext$ {{Cl|FOR (file statement)|FOR}} {{Cl|OUTPUT}} {{Cl|AS}} #f&: {{Cl|CLOSE}} #f& ' erases an existing file
{{Cl|OPEN}} filename$ + ext$ {{Cl|FOR (file statement)|FOR}} {{Cl|BINARY}} {{Cl|AS}} #f&
{{Cl|PUT}} #f&,,b$
{{Cl|CLOSE}} #f&
{{Cl|END SUB}}
{{CodeEnd}}
{{small|Code by Galleon}}
<center>'''This SUB program can also be [[$INCLUDE|Included]] with any program!'''</center>


        {{Cl|DIM}} zx {{Cl|AS}} {{Cl|SINGLE}}: zx = {{Text|0|#F580B1}}
        {{Cl|DIM}} zy {{Cl|AS}} {{Cl|SINGLE}}: zy = {{Text|0|#F580B1}}
        {{Cl|DIM}} i {{Cl|AS}} {{Cl|LONG}}: i = {{Text|0|#F580B1}}


''SUB Explanation:'' b$ and d$ assemble the entire string of data to create a bitmap file. Some of the bitmap header info is placed later using a [[MID$ (statement)]] to add final header numerical data converted to [[ASCII]] characters by [[MKI$]] or [[MKL$]].
        {{Cl|DO...LOOP|DO UNTIL}} zx * zx + zy * zy >= {{Text|4|#F580B1}} {{Cl|OR (boolean)|OR}} i >= MAX_ITER
            {{Cl|DIM}} temp {{Cl|AS}} {{Cl|SINGLE}}: temp = zx * zx - zy * zy + cx
            zy = {{Text|2|#F580B1}} * zx * zy + cy
            zx = temp
            i = i + {{Text|1|#F580B1}}
        {{Cl|LOOP}}


After the header, the [[RGB]] color settings are created using [[ASCII]] characters read backwards as Blue, Green, Red and CHR$(0) as a spacer. [[MKL$]] places the byte values in reverse order too. Bitmaps and icons require that format. [[LEFT$]] trims off the [[_ALPHA]] byte.
        {{Cl|PSET}} (x, y), (i {{Cl|MOD}} {{Text|16|#F580B1}}) * {{Text|16|#F580B1}} + (i {{Cl|MOD}} {{Text|8|#F580B1}})
    {{Cl|NEXT}} x
{{Cl|NEXT}} y


The actual image is read as pixel attributes from the image bottom to the top for proper formatting with zero padding when necessary.
{{Cl|_SAVEIMAGE}} {{Text|<nowiki>"Mandelbrot"</nowiki>|#FFB100}}, img


'''* Note:''' 32-bit images will be saved as 24-bit BMP files. All palette indexed images/modes will be saved as 256 color BMP files. Text modes cannot be saved. As QB64 has no official _SAVEIMAGE command yet and QBasic programs to save screen-shots don't work in QB64 yet this is a very useful alternative.
{{Cl|_DEST}} {{Text|0|#F580B1}}
{{Cl|PRINT}} {{Text|<nowiki>"Saved image."</nowiki>|#FFB100}}


{{Cl|END}}
{{CodeEnd}}




''See also:''
{{PageSeeAlso}}
* [https://qb64phoenix.com/forum/showthread.php?tid=2749 Featured in our "Keyword of the Day" series]
* [[_LOADIMAGE]], [[_ICON]], [[$EXEICON]]
* [[_LOADIMAGE]], [[_ICON]], [[$EXEICON]]
* [[SCREEN]]
* [[SCREEN]]
* [[TYPE]], [[MKI$]], [[MKL$]]
* [[TYPE]], [[MKI$]], [[MKL$]]
* [[Program ScreenShots]] {{text|(member SUB program)}}
* [[Program ScreenShots]]
* [[ThirtyTwoBit SUB]] {{text|(member SUB captures selected area)}}
* [[ThirtyTwoBit SUB]]
* [[ThirtyTwoBit MEM SUB]] {{text|(Fast SUB uses memory instead of POINT)}}
* [[ThirtyTwoBit MEM SUB]]
* [[SaveIcon32]] {{text|(converts any image to icon)}}
* [[SaveIcon32]]
* [[Bitmaps]], [[Icons and Cursors]]
* [[Bitmaps]], [[Icons and Cursors]]
 
* [[Text Using Graphics]]
 
{{PageNavigation}}

Latest revision as of 17:23, 21 July 2024

_SAVEIMAGE saves the contents of an image or screen page to an image file.


Syntax

_SAVEIMAGE fileName$[, imageHandle&][, requirements$]


Parameters

  • fileName$ is literal or variable STRING file name value.
  • Optional imageHandle& is a LONG image handle or a valid screen page number.
  • Optional requirements$ STRING values can be:
    • BMP: Saves the image as Windows Bitmap if no file extension is specified.
    • GIF: Saves the image as Graphics Interchange Format if no file extension is specified.
    • HDR: Saves the image as Radiance HDR if no file extension is specified.
    • ICO: Saves the image as Windows Icon if no file extension is specified.
    • JPG: Saves the image as Joint Photographic Experts Group if no file extension is specified.
    • PNG: Saves the image as Portable Network Graphics if no file extension is specified.
    • QOI: Saves the image as Quite OK Image if no file extension is specified.
    • TGA: Saves the image as Truevision TARGA if no file extension is specified.


Description

  • fileName$ extension name takes precedence over requirements$
  • If no file extension is specified in fileName$ and no format is specified in requirements$, then the PNG format is used by default.
  • If imageHandle& is omitted then the image handle returned by _DISPLAY (function) is used.
  • Efforts are made to save the image in the highest quality possible using 32-bit RGBA format, ensuring that alpha channel information is retained whenever the format permits.
  • Due to the inherent limitations of GIFs, these images are stored in an 8-bit indexed format, which results in a reduction of quality and color detail.
  • Windows ICO files utilize the PNG specification, which enables the storage of images exceeding 256x256 pixels in size.
  • SCREEN 0 (text mode) screens and "images" can be saved. Text surfaces are rendered internally using the master QB64-PE VGA fonts prior to saving.


Availability

  • ICO and GIF support was added in QB64-PE v3.14.0.


Examples

Example 1
It's possible to use _SAVEIMAGE with text screens.
This demo draws a Mandelbrot in SCREEN 0 and then saves the screen as a .jpg image.
OPTION _EXPLICIT

CONST X_MIN = -2!
CONST X_MAX = 1!
CONST Y_MIN = -1!
CONST Y_MAX = 1!
CONST MAX_ITER = 100
CONST PIX_CHAR = 48

SCREEN 0
WIDTH 160, 100
_FONT 8

DIM w AS LONG: w = _WIDTH
DIM h AS LONG: h = _HEIGHT
DIM maxX AS LONG: maxX = w - 1
DIM maxY AS LONG: maxY = h - 1

DIM y AS LONG: FOR y = 0 TO maxY
    DIM x AS LONG: FOR x = 0 TO maxX
        DIM cx AS SINGLE: cx = X_MIN + (x / w) * (X_MAX - X_MIN)
        DIM cy AS SINGLE: cy = Y_MIN + (y / h) * (Y_MAX - Y_MIN)

        DIM zx AS SINGLE: zx = 0
        DIM zy AS SINGLE: zy = 0
        DIM i AS LONG: i = 0

        DO UNTIL zx * zx + zy * zy >= 4 OR i >= MAX_ITER
            DIM temp AS SINGLE: temp = zx * zx - zy * zy + cx
            zy = 2 * zx * zy + cy
            zx = temp
            i = i + 1
        LOOP

        COLOR i MOD 16

        _PRINTSTRING (x + 1, y + 1), CHR$(PIX_CHAR)
    NEXT x
NEXT y

_SAVEIMAGE "TextMandelbrot!.jpg"

END

Example 2
Saving a graphics image to a .png file. This is much like example one. However, it renders the graphics to an 8-bit offscreen image and then passes the image handle to _SAVEIMAGE.
OPTION _EXPLICIT

CONST X_MIN = -2!
CONST X_MAX = 1!
CONST Y_MIN = -1!
CONST Y_MAX = 1!
CONST MAX_ITER = 100

DIM img AS LONG: img = _NEWIMAGE(640 * 2, 400 * 2, 256)
_DEST img

DIM w AS LONG: w = _WIDTH
DIM h AS LONG: h = _HEIGHT
DIM maxX AS LONG: maxX = w - 1
DIM maxY AS LONG: maxY = h - 1

DIM y AS LONG: FOR y = 0 TO maxY
    DIM x AS LONG: FOR x = 0 TO maxX
        DIM cx AS SINGLE: cx = X_MIN + (x / maxX) * (X_MAX - X_MIN)
        DIM cy AS SINGLE: cy = Y_MIN + (y / maxY) * (Y_MAX - Y_MIN)

        DIM zx AS SINGLE: zx = 0
        DIM zy AS SINGLE: zy = 0
        DIM i AS LONG: i = 0

        DO UNTIL zx * zx + zy * zy >= 4 OR i >= MAX_ITER
            DIM temp AS SINGLE: temp = zx * zx - zy * zy + cx
            zy = 2 * zx * zy + cy
            zx = temp
            i = i + 1
        LOOP

        PSET (x, y), (i MOD 16) * 16 + (i MOD 8)
    NEXT x
NEXT y

_SAVEIMAGE "Mandelbrot", img

_DEST 0
PRINT "Saved image."

END


See also