SaveImage SUB: Difference between revisions

From QB64 Phoenix Edition Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
 
(5 intermediate revisions by the same user not shown)
Line 15: Line 15:
* Bitmaps can be 1, 4, 8 or 24/32 bits per pixel(BPP) color palettes. QB64 is capable of working with high color bitmaps.
* Bitmaps can be 1, 4, 8 or 24/32 bits per pixel(BPP) color palettes. QB64 is capable of working with high color bitmaps.
* Screen or Image width and height calculations are automatically made using the image handle value.
* Screen or Image width and height calculations are automatically made using the image handle value.
* Use an image handle value of 0(zero) to get a screen shot of the entire active program screen.
* Use an image handle value of ''zero(0)'' to get a screen shot of the entire active program screen.
* '''Note:''' SCREEN 0 text mode cannot be screen saved in QBasic or QB64 using this SUB.
* '''Note:''' SCREEN 0 text mode cannot be screen saved in QBasic or QB64 using this SUB.




{{PageExamples}}
{{PageExamples}}
; Example: *The following example uses the SaveImage SUB program to save a loaded 32 bit JPEG image as a bitmap using QB64's graphic functions.
;* Example: Using the SaveImage SUB program to save a loaded 32 bit PNG image as a bitmap (BMP) using QB64's graphic functions.
: *Change the _LOADIMAGE filename to an image file you can access.
{{CodeStart}}
{{CodeStart}}
i& = {{Cl|_LOADIMAGE}}("nice.jpg",32) ' loads a 32 bit .JPG file image
{{Text|<nowiki>'load a 32 bit .PNG file image</nowiki>|#919191}}
SaveImage i&, "nice"      'saves it as .BMP file "nice.bmp"
i& = {{Cl|_LOADIMAGE}}({{Text|<nowiki>"source\peLogo.png"</nowiki>|#FFB100}}, {{Text|32|#F580B1}})
'SaveImage 0, "screenshot" 'saves entire program screen as "screenshot.bmp"
{{Cl|IF}} i& < {{Text|-1|#F580B1}} {{Cl|THEN}}
    {{Text|<nowiki>'load success: get image's width/height</nowiki>|#919191}}
    w& = {{Cl|_WIDTH (function)|_WIDTH}}(i&): h& = {{Cl|_HEIGHT}}(i&)
    {{Text|<nowiki>'TEST-1: directly save the loaded image as .BMP file "logo.bmp"</nowiki>|#919191}}
    {{Text|SaveImage|#55FF55}} i&, {{Text|<nowiki>"logo"</nowiki>|#FFB100}}
    {{Text|<nowiki>'TEST-2: make a new 4:3 program SCREEN of the loaded image's width/height</nowiki>|#919191}}
    {{Cl|SCREEN}} {{Cl|_NEWIMAGE}}(({{Text|4|#F580B1}} * w&), ({{Text|3|#F580B1}} * h&), {{Text|32|#F580B1}})
    {{Text|<nowiki>'now tile-fill the screen with the loaded image</nowiki>|#919191}}
    {{Cl|FOR}} x& = {{Text|0|#F580B1}} {{Cl|TO}} ({{Text|4|#F580B1}} * w&) {{Cl|STEP}} w&
        {{Cl|FOR}} y& = {{Text|0|#F580B1}} {{Cl|TO}} ({{Text|3|#F580B1}} * h&) {{Cl|STEP}} h&
            {{Cl|_PUTIMAGE}} (x&, y&), i&
        {{Cl|NEXT}} y&
    {{Cl|NEXT}} x&
    {{Text|<nowiki>'and then save the entire program screen as "screenshot.bmp"</nowiki>|#919191}}
    {{Text|SaveImage|#55FF55}} {{Text|0|#F580B1}}, {{Text|<nowiki>"screenshot"</nowiki>|#FFB100}}
{{Cl|ELSE}}
    {{Text|<nowiki>'load failure: print error</nowiki>|#919191}}
    {{Cl|PRINT}} {{Text|<nowiki>"Cannot find/load the given image."</nowiki>|#FFB100}}
{{Cl|END IF}}
{{Cl|END}}
{{Cl|END}}


{{Cl|SUB}} SaveImage (image {{Cl|AS}} {{Cl|LONG}}, filename {{Cl|AS}} {{Cl|STRING}})
{{Cl|SUB}} {{Text|SaveImage|#55FF55}} (image {{Cl|AS}} {{Cl|LONG}}, filename {{Cl|AS}} {{Cl|STRING}})
bytesperpixel& = {{Cl|_PIXELSIZE}}(image&)
bytesperpixel& = {{Cl|_PIXELSIZE}}(image&)
{{Cl|IF}} bytesperpixel& = 0 {{Cl|THEN}} {{Cl|PRINT}} "Text modes unsupported!": {{Cl|END}}
{{Cl|IF}} bytesperpixel& = {{Text|0|#F580B1}} {{Cl|THEN}} {{Cl|PRINT}} {{Text|<nowiki>"Text modes unsupported!"</nowiki>|#FFB100}}: {{Cl|END}}
{{Cl|IF}} bytesperpixel& = 1 {{Cl|THEN}} bpp& = 8 {{Cl|ELSE}} bpp& = 24
{{Cl|IF}} bytesperpixel& = {{Text|1|#F580B1}} {{Cl|THEN}} bpp& = {{Text|8|#F580B1}} {{Cl|ELSE}} bpp& = {{Text|24|#F580B1}}
x& = {{Cl|_WIDTH (function)|_WIDTH}}(image&)
x& = {{Cl|_WIDTH (function)|_WIDTH}}(image&)
y& = {{Cl|_HEIGHT}}(image&)
y& = {{Cl|_HEIGHT}}(image&)
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)
b$ = {{Text|<nowiki>"BM????QB64????"</nowiki>|#FFB100}} + {{Cl|MKL$}}({{Text|40|#F580B1}}) + {{Cl|MKL$}}(x&) + {{Cl|MKL$}}(y&) + {{Cl|MKI$}}({{Text|1|#F580B1}}) + {{Cl|MKI$}}(bpp&) + {{Cl|MKL$}}({{Text|0|#F580B1}}) + {{Text|<nowiki>"????"</nowiki>|#FFB100}} + {{Cl|STRING$}}({{Text|16|#F580B1}}, {{Text|0|#F580B1}}) {{Text|<nowiki>'partial BMP header info(???? to be filled later)</nowiki>|#919191}}
{{Cl|IF}} bytesperpixel& = 1 {{Cl|THEN}}
{{Cl|IF}} bytesperpixel& = {{Text|1|#F580B1}} {{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|FOR}} c& = {{Text|0|#F580B1}} {{Cl|TO}} {{Text|255|#F580B1}} {{Text|<nowiki>' read BGR color settings from JPG image + 1 byte spacer(CHR$(0))</nowiki>|#919191}}
    cv& = {{Cl|_PALETTECOLOR (function)|_PALETTECOLOR}}(c&, image&) ' color attribute to read.
        cv& = {{Cl|_PALETTECOLOR (function)|_PALETTECOLOR}}(c&, image&) {{Text|<nowiki>' color attribute to read.</nowiki>|#919191}}
    b$ = b$ +{{Cl|CHR$}}({{Cl|_BLUE32}}(cv&))+{{Cl|CHR$}}({{Cl|_GREEN32}}(cv&))+{{Cl|CHR$}}({{Cl|_RED32}}(cv&))+{{Cl|CHR$}}(0) 'spacer byte
        b$ = b$ + {{Cl|CHR$}}({{Cl|_BLUE32}}(cv&)) + {{Cl|CHR$}}({{Cl|_GREEN32}}(cv&)) + {{Cl|CHR$}}({{Cl|_RED32}}(cv&)) + {{Cl|CHR$}}({{Text|0|#F580B1}}) {{Text|<nowiki>'spacer byte</nowiki>|#919191}}
  {{Cl|NEXT}}
    {{Cl|NEXT}}
{{Cl|END IF}}
{{Cl|END IF}}
{{Cl|MID$}}(b$, 11, 4) = {{Cl|MKL$}}({{Cl|LEN}}(b$)) ' image pixel data offset(BMP header)
{{Cl|MID$}}(b$, {{Text|11|#F580B1}}, {{Text|4|#F580B1}}) = {{Cl|MKL$}}({{Cl|LEN}}(b$)) {{Text|<nowiki>' image pixel data offset(BMP header)</nowiki>|#919191}}
lastsource& = {{Cl|_SOURCE}}
lastsource& = {{Cl|_SOURCE (function)|_SOURCE}}
{{Cl|_SOURCE}} image&
{{Cl|_SOURCE}} image&
{{Cl|IF}} ((x& * 3) {{Cl|MOD}} 4) {{Cl|THEN}} padder$ = {{Cl|STRING$}}(4 - ((x& * 3) {{Cl|MOD}} 4), 0)
{{Cl|IF}} ((x& * {{Text|3|#F580B1}}) {{Cl|MOD}} {{Text|4|#F580B1}}) {{Cl|THEN}} padder$ = {{Cl|STRING$}}({{Text|4|#F580B1}} - ((x& * {{Text|3|#F580B1}}) {{Cl|MOD}} {{Text|4|#F580B1}}), {{Text|0|#F580B1}})
{{Cl|FOR...NEXT|FOR}} py& = y& - 1 {{Cl|TO}} 0 {{Cl|STEP}} -1 ' read JPG image pixel color data
{{Cl|FOR}} py& = y& - {{Text|1|#F580B1}} {{Cl|TO}} {{Text|0|#F580B1}} {{Cl|STEP}} {{Text|-1|#F580B1}} {{Text|<nowiki>' read JPG image pixel color data</nowiki>|#919191}}
  r$ = ""
    r$ = {{Text|<nowiki>""</nowiki>|#FFB100}}
  {{Cl|FOR...NEXT|FOR}} px& = 0 {{Cl|TO}} x& - 1
    {{Cl|FOR}} px& = {{Text|0|#F580B1}} {{Cl|TO}} x& - {{Text|1|#F580B1}}
  c& = {{Cl|POINT}}(px&, py&) 'POINT 32 bit values are large {{Cl|LONG}} values
        c& = {{Cl|POINT}}(px&, py&) {{Text|<nowiki>'POINT 32 bit values are large LONG values</nowiki>|#919191}}
  {{Cl|IF}} bytesperpixel& = 1 {{Cl|THEN}} r$ = r$ + {{Cl|CHR$}}(c&) {{Cl|ELSE}} r$ = r$ + {{Cl|LEFT$}}({{Cl|MKL$}}(c&), 3)
        {{Cl|IF}} bytesperpixel& = {{Text|1|#F580B1}} {{Cl|THEN}} r$ = r$ + {{Cl|CHR$}}(c&) {{Cl|ELSE}} r$ = r$ + {{Cl|LEFT$}}({{Cl|MKL$}}(c&), {{Text|3|#F580B1}})
  {{Cl|NEXT}} px&
    {{Cl|NEXT}} px&
  d$ = d$ + r$ + padder$
    d$ = d$ + r$ + padder$
{{Cl|NEXT}} py&
{{Cl|NEXT}} py&
{{Cl|_SOURCE}} lastsource&
{{Cl|_SOURCE}} lastsource&
{{Cl|MID$}}(b$, 35, 4) = {{Cl|MKL$}}({{Cl|LEN}}(d$)) ' image size(BMP header)
{{Cl|MID$}}(b$, {{Text|35|#F580B1}}, {{Text|4|#F580B1}}) = {{Cl|MKL$}}({{Cl|LEN}}(d$)) {{Text|<nowiki>' image size(BMP header)</nowiki>|#919191}}
b$ = b$ + d$ ' total file data bytes to create file
b$ = b$ + d$ {{Text|<nowiki>' total file data bytes to create file</nowiki>|#919191}}
{{Cl|MID$}}(b$, 3, 4) = {{Cl|MKL$}}({{Cl|LEN}}(b$)) ' size of data file(BMP header)
{{Cl|MID$}}(b$, {{Text|3|#F580B1}}, {{Text|4|#F580B1}}) = {{Cl|MKL$}}({{Cl|LEN}}(b$)) {{Text|<nowiki>' size of data file(BMP header)</nowiki>|#919191}}
{{Cl|IF}} {{Cl|LCASE$}}({{Cl|RIGHT$}}(filename$, 4)) <> ".bmp" {{Cl|THEN}} ext$ = ".bmp"
{{Cl|IF}} {{Cl|LCASE$}}({{Cl|RIGHT$}}(filename$, {{Text|4|#F580B1}})) <> {{Text|<nowiki>".bmp"</nowiki>|#FFB100}} {{Cl|THEN}} ext$ = {{Text|<nowiki>".bmp"</nowiki>|#FFB100}}
f& = {{Cl|FREEFILE}}
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|OPEN#File_Access_Modes|FOR}} {{Cl|OPEN#File_Access_Modes|OUTPUT}} {{Cl|OPEN|AS}} #f&: {{Cl|CLOSE}} #f& {{Text|<nowiki>' erases an existing file</nowiki>|#919191}}
{{Cl|OPEN}} filename$ + ext$ {{Cl|FOR (file statement)|FOR}} {{Cl|BINARY}} {{Cl|AS}} #f&
{{Cl|OPEN}} filename$ + ext$ {{Cl|OPEN#File_Access_Modes|FOR}} {{Cl|OPEN#File_Access_Modes|BINARY}} {{Cl|OPEN|AS}} #f&
{{Cl|PUT}} #f&,,b$
{{Cl|PUT}} #f&, , b$
{{Cl|CLOSE}} #f&
{{Cl|CLOSE}} #f&
{{Cl|END SUB}}
{{Cl|END SUB}}
Line 88: Line 105:




{{PageNavigation}}
{{PageReferences}}

Latest revision as of 13:31, 19 November 2024



Attention!! - This page is outdated and provided for reference and/or education only.
(Return to historic Table of Contents)

Starting with QB64-PE v3.9.0 the functionality described here was superseded by _SAVEIMAGE.



The SaveImage SUB program to create Bitmaps of other type Images or Screenshots
Bitmaps are image files with the .BMP file name extension.


  • Bitmaps can be 1, 4, 8 or 24/32 bits per pixel(BPP) color palettes. QB64 is capable of working with high color bitmaps.
  • Screen or Image width and height calculations are automatically made using the image handle value.
  • Use an image handle value of zero(0) to get a screen shot of the entire active program screen.
  • Note: SCREEN 0 text mode cannot be screen saved in QBasic or QB64 using this SUB.


Examples

Example
  • Using the SaveImage SUB program to save a loaded 32 bit PNG image as a bitmap (BMP) using QB64's graphic functions.
'load a 32 bit .PNG file image
i& = _LOADIMAGE("source\peLogo.png", 32)
IF i& < -1 THEN
    'load success: get image's width/height
    w& = _WIDTH(i&): h& = _HEIGHT(i&)
    'TEST-1: directly save the loaded image as .BMP file "logo.bmp"
    SaveImage i&, "logo"
    'TEST-2: make a new 4:3 program SCREEN of the loaded image's width/height
    SCREEN _NEWIMAGE((4 * w&), (3 * h&), 32)
    'now tile-fill the screen with the loaded image
    FOR x& = 0 TO (4 * w&) STEP w&
        FOR y& = 0 TO (3 * h&) STEP h&
            _PUTIMAGE (x&, y&), i&
        NEXT y&
    NEXT x&
    'and then save the entire program screen as "screenshot.bmp"
    SaveImage 0, "screenshot"
ELSE
    'load failure: print error
    PRINT "Cannot find/load the given image."
END IF
END

SUB SaveImage (image AS LONG, filename AS STRING)
bytesperpixel& = _PIXELSIZE(image&)
IF bytesperpixel& = 0 THEN PRINT "Text modes unsupported!": END
IF bytesperpixel& = 1 THEN bpp& = 8 ELSE bpp& = 24
x& = _WIDTH(image&)
y& = _HEIGHT(image&)
b$ = "BM????QB64????" + MKL$(40) + MKL$(x&) + MKL$(y&) + MKI$(1) + MKI$(bpp&) + MKL$(0) + "????" + STRING$(16, 0) 'partial BMP header info(???? to be filled later)
IF bytesperpixel& = 1 THEN
    FOR c& = 0 TO 255 ' read BGR color settings from JPG image + 1 byte spacer(CHR$(0))
        cv& = _PALETTECOLOR(c&, image&) ' color attribute to read.
        b$ = b$ + CHR$(_BLUE32(cv&)) + CHR$(_GREEN32(cv&)) + CHR$(_RED32(cv&)) + CHR$(0) 'spacer byte
    NEXT
END IF
MID$(b$, 11, 4) = MKL$(LEN(b$)) ' image pixel data offset(BMP header)
lastsource& = _SOURCE
_SOURCE image&
IF ((x& * 3) MOD 4) THEN padder$ = STRING$(4 - ((x& * 3) MOD 4), 0)
FOR py& = y& - 1 TO 0 STEP -1 ' read JPG image pixel color data
    r$ = ""
    FOR px& = 0 TO x& - 1
        c& = POINT(px&, py&) 'POINT 32 bit values are large LONG values
        IF bytesperpixel& = 1 THEN r$ = r$ + CHR$(c&) ELSE r$ = r$ + LEFT$(MKL$(c&), 3)
    NEXT px&
    d$ = d$ + r$ + padder$
NEXT py&
_SOURCE lastsource&
MID$(b$, 35, 4) = MKL$(LEN(d$)) ' image size(BMP header)
b$ = b$ + d$ ' total file data bytes to create file
MID$(b$, 3, 4) = MKL$(LEN(b$)) ' size of data file(BMP header)
IF LCASE$(RIGHT$(filename$, 4)) <> ".bmp" THEN ext$ = ".bmp"
f& = FREEFILE
OPEN filename$ + ext$ FOR OUTPUT AS #f&: CLOSE #f& ' erases an existing file
OPEN filename$ + ext$ FOR BINARY AS #f&
PUT #f&, , b$
CLOSE #f&
END SUB
Code by Galleon


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$ to add final header numerical data converted to ASCII characters by MKI$ or MKL$.

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.

The actual image is read as pixel attributes from the image bottom to the top for proper formatting with zero padding when necessary.

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.


See also


QB64 Programming References

Wiki Pages
Main Page with Articles and Tutorials
QB64 specific keywords (alphabetical)
Original QBasic keywords (alphabetical)
QB64 OpenGL keywords (alphabetical)
Keywords by Usage
Got a question about something?
Frequently Asked Questions about QB64
QB64 Phoenix Edition Community Forum
Links to other QBasic Sites:
Pete's QBasic Forum
Pete's QBasic Downloads