Author Topic: 8 bit graphics (continued from Off-Topic because of attachments)  (Read 4235 times)

0 Members and 1 Guest are viewing this topic.

Offline Richard

  • Seasoned Forum Regular
  • Posts: 364
    • View Profile
8 bit graphics (continued from Off-Topic because of attachments)
« on: November 04, 2020, 10:50:35 pm »
The three files below

PAINTcolor32.bit  is a 2D color spectrum
PAINTcolor256     is a MS PAINT converted above file to 256 colors
MAGICKcolor256  is using MAGICK to convert PAINTcolor32bit to a 256 color file

Would anyone care to share screenshots from their computers so that I can confirm COMPLETE compatibility between various computer hardware/software. Sometimes in various programming environments on my HP laptop - the last two files are really messed up (color-wise).


  [ You are not allowed to view this attachment ]       [ You are not allowed to view this attachment ]       [ You are not allowed to view this attachment ]  

Offline Richard Frost

  • Seasoned Forum Regular
  • Posts: 316
  • Needle nardle noo. - Peter Sellers
    • View Profile
Re: 8 bit graphics (continued from Off-Topic because of attachments)
« Reply #1 on: November 04, 2020, 11:30:17 pm »
I'm running XP on a 64 bit laptop.

My 32 bit Windows version of QB64 v1.3 will not display that 3rd file on a 32 bit  screen.  The file will 
load, but an "Invalid handle" error is generated with the _PUTIMAGE.   After converting it to  JPEG it's 
fine.  The colors  always look the same  to me - in Windows Viewer, MS Paint, or QB64.   

There is a weird splotch like a fractal tree at lower right in the Magick image.  Is that the problem?

Maybe I didn't understand the question. 
« Last Edit: November 04, 2020, 11:39:52 pm by Richard Frost »
It works better if you plug it in.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: 8 bit graphics (continued from Off-Topic because of attachments)
« Reply #2 on: November 05, 2020, 12:22:53 am »
If you've ever used my SaveImage library, it can take a lot of the hassle out of using 256 color images inside QB64.

For example, you can take a 32-bit image and dither it down to a 256 color image, much like you've done above with external programs.  The results which you get will go from your 32-bit color image above, to the following:

  [ You are not allowed to view this attachment ]  

And the code for this simple conversion is here, along with the routine to save the 256-color image as a BMP file on your drive:

Code: QB64: [Select]
  1. image1 = _LOADIMAGE("PAINTcolor32bit.bmp", 32) 'load the 32-bit image
  2. image2 = Image32To256(image1) 'convert it to a 256 color image
  3.  
  4. SaveBMP "ConvertedTo256WithQB64.bmp", image2, 0, 0, _WIDTH(image2) - 1, _HEIGHT(image2) - 1 'and save it to the drive
  5. 'and we're done!
  6.  
  7.  
  8.  
  9.  
  10. FUNCTION Image32To256 (image&)
  11.     'This routine can benefit/be altered if the user sets a CONST or DIM SHARED variable name ConvertToStandard256Palette, as so:
  12.     '     CONST ConvertToStandard256Palette = -1
  13.     '           Set the value to 0 (FALSE) to preseve the color information perfectly, using its default palette.
  14.     '           If the CONST is set (TRUE), then we convert our colors to as close of a match as possible, while
  15.     '           preserving the standard QB64 256-color palette.
  16.     DIM o AS _OFFSET
  17.     DIM t AS _UNSIGNED LONG, color256 AS _UNSIGNED LONG
  18.     DIM index256 AS _UNSIGNED LONG
  19.     TYPE Pal_type
  20.         c AS _UNSIGNED LONG 'color index
  21.         n AS LONG 'number of times it appears
  22.     END TYPE
  23.     DIM Pal(255) AS _UNSIGNED LONG
  24.     I256 = _NEWIMAGE(_WIDTH(image&), _HEIGHT(image&), 256)
  25.     DIM m(1) AS _MEM: m(0) = _MEMIMAGE(image&): m(1) = _MEMIMAGE(I256)
  26.     DO 'get the palette and number of colors used
  27.         _MEMGET m(0), m(0).OFFSET + o, t 'Get the colors from the original screen
  28.         FOR i = 0 TO colors 'check to see if they're in the existing palette we're making
  29.             IF Pal(i) = t THEN EXIT FOR
  30.         NEXT
  31.         IF i > colors THEN
  32.             Pal(colors) = t
  33.             colors = colors + 1 'increment the index for the new color found
  34.             IF colors > 255 THEN 'no need to check any further; it's not a normal QB64 256 color image
  35.                 Image32To256 = RemapImageFS(image&, I256)
  36.                 _FREEIMAGE I256
  37.                 _MEMFREE m()
  38.                 EXIT FUNCTION 'and we're done, with 100% image compatability saved
  39.             END IF
  40.         END IF
  41.         o = o + 4
  42.     LOOP UNTIL o >= m(0).SIZE
  43.  
  44.     '  we might be working with a standard qb64 256 color screen
  45.     '  check for that first
  46.     colors = colors - 1 'back up one, as we found our limit and aren't needing to set another
  47.     FOR i = 0 TO colors 'comparing palette against QB64 256 color palette
  48.         t = Pal(i)
  49.         index256 = _RGBA(_RED32(t), _GREEN32(t), _BLUE32(t), _ALPHA32(t), I256)
  50.         color256 = _RGBA32(_RED(index256, I256), _GREEN(index256, I256), _BLUE(index256, I256), _ALPHA(index256, I256))
  51.         IF t <> color256 THEN NSCU = -1: EXIT FOR
  52.     NEXT
  53.     IF NSCU THEN 'it's not a standard QB64 256 color palette, but it's still less than 256 total colors.
  54.         IF ConvertToStandard256Palette THEN
  55.             TI256 = RemapImageFS(image&, I256)
  56.             _MEMFREE m(1) 'free the old memory
  57.             _FREEIMAGE I256 'and the old image
  58.             I256 = TI256 'replace with the new image
  59.             m(1) = _MEMIMAGE(I256) 'and point the mem block to the new image
  60.         ELSE
  61.             FOR i = 0 TO colors: _PALETTECOLOR i, Pal(i), I256: NEXT 'set the palette
  62.         END IF
  63.     END IF
  64.     'If we didn't change the palette above, we should work 100% with qb64's internal 256 color palette
  65.     o = 0
  66.     DO 'Get the colors, put them to a 256 color screen, as is
  67.         _MEMGET m(0), m(0).OFFSET + o + 3, a
  68.         _MEMGET m(0), m(0).OFFSET + o + 2, r
  69.         _MEMGET m(0), m(0).OFFSET + o + 1, g
  70.         _MEMGET m(0), m(0).OFFSET + o + 0, b
  71.         _MEMPUT m(1), m(1).OFFSET + o \ 4, _RGBA(r, g, b, a, I256) AS _UNSIGNED _BYTE
  72.         o = o + 4
  73.     LOOP UNTIL o >= m(0).SIZE
  74.     _MEMFREE m()
  75.     Image32To256 = I256
  76.  
  77. FUNCTION RemapImageFS& (ohan&, dhan&) 'Routine written by RhoSigma and used (with permission) for SaveImage Library
  78.     '// +---------------+---------------------------------------------------+
  79.     '// | ###### ###### |     .--. .         .-.                            |
  80.     '// | ##  ## ##   # |     |   )|        (   ) o                         |
  81.     '// | ##  ##  ##    |     |--' |--. .-.  `-.  .  .-...--.--. .-.        |
  82.     '// | ######   ##   |     |  \ |  |(   )(   ) | (   ||  |  |(   )       |
  83.     '// | ##      ##    |     '   `'  `-`-'  `-'-' `-`-`|'  '  `-`-'`-      |
  84.     '// | ##     ##   # |                            ._.'                   |
  85.     '// | ##     ###### | Sources & Documents placed under the MIT License. |
  86.     '// +-------------------------------------------------------------------+
  87.     '// | Done by RhoSigma, R.Heyder, provided AS IS, use at your own risk. |
  88.     '// | Find me in the QB64 Forum or mail to support[member=111]RhoSigma[/member]-cw.net for  |
  89.     '// | any questions or suggestions. Thanx for your interest in my work. |
  90.     '// +-------------------------------------------------------------------+
  91.  
  92.     RemapImageFS& = -1 'so far return invalid handle
  93.     shan& = ohan& 'avoid side effect on given argument
  94.     IF shan& < -1 OR shan& = 0 THEN '0 represents the visible screen
  95.         '--- check/adjust source image & get new 8-bit image ---
  96.         swid% = _WIDTH(shan&): shei% = _HEIGHT(shan&)
  97.         IF _PIXELSIZE(shan&) <> 4 THEN
  98.             than& = _NEWIMAGE(swid%, shei%, 32)
  99.             IF than& >= -1 THEN EXIT FUNCTION
  100.             _PUTIMAGE , shan&, than&
  101.             shan& = than&
  102.         ELSE
  103.             than& = -1 'avoid freeing below
  104.         END IF
  105.         nhan& = _NEWIMAGE(swid%, shei%, 256)
  106.         '--- Floyd-Steinberg error distribution arrays ---
  107.         rhan& = _NEWIMAGE(swid%, 2, 32) 'these are missused as LONG arrays,
  108.         ghan& = _NEWIMAGE(swid%, 2, 32) 'with CHECKING:OFF this is much faster
  109.         bhan& = _NEWIMAGE(swid%, 2, 32) 'than real QB64 arrays
  110.         '--- curr/next row offsets (for distribution array access) ---
  111.         cro% = 0: nro% = swid% * 4 'will be swapped after each pixel row
  112.         '--- the matrix values are extended by 16384 to avoid slow floating ---
  113.         '--- point ops and to allow for integer storage in the above arrays ---
  114.         '--- also it's a power of 2, which may be optimized into a bitshift ---
  115.         seven% = 7168 '(7 / 16) * 16384 'X+1,Y+0 error fraction
  116.         three% = 3072 '(3 / 16) * 16384 'X-1,Y+1 error fraction
  117.         five% = 5120 '(5 / 16) * 16384 'X+0,Y+1 error fraction
  118.         one% = 1025 '(1 / 16) * 16384 'X+1,Y+1 error fraction
  119.         '--- if all is good, then start remapping ---
  120.         $CHECKING:OFF
  121.         IF nhan& < -1 AND rhan& < -1 AND ghan& < -1 AND bhan& < -1 THEN
  122.             _COPYPALETTE dhan&, nhan& 'dest palette to new image
  123.             '--- for speed we do direct memory access ---
  124.             DIM sbuf AS _MEM: sbuf = _MEMIMAGE(shan&): soff%& = sbuf.OFFSET
  125.             DIM nbuf AS _MEM: nbuf = _MEMIMAGE(nhan&): noff%& = nbuf.OFFSET
  126.             DIM rbuf AS _MEM: rbuf = _MEMIMAGE(rhan&): roff%& = rbuf.OFFSET
  127.             DIM gbuf AS _MEM: gbuf = _MEMIMAGE(ghan&): goff%& = gbuf.OFFSET
  128.             DIM bbuf AS _MEM: bbuf = _MEMIMAGE(bhan&): boff%& = bbuf.OFFSET
  129.             '--- iterate through pixels ---
  130.             FOR y% = 0 TO shei% - 1
  131.                 FOR x% = 0 TO swid% - 1
  132.                     '--- curr/prev/next pixel offsets ---
  133.                     cpo% = x% * 4: ppo% = cpo% - 4: npo% = cpo% + 4
  134.                     '--- get pixel ARGB value from source ---
  135.                     srgb~& = _MEMGET(sbuf, soff%&, _UNSIGNED LONG)
  136.                     '--- add distributed error, shrink by 16384, clear error ---
  137.                     '--- current pixel X+0, Y+0 (= cro% (current row offset)) ---
  138.                     poff% = cro% + cpo% 'pre-calc full pixel offset
  139.                     sr% = ((srgb~& AND &HFF0000~&) \ 65536) + (_MEMGET(rbuf, roff%& + poff%, LONG) \ 16384) 'red
  140.                     sg% = ((srgb~& AND &HFF00~&) \ 256) + (_MEMGET(gbuf, goff%& + poff%, LONG) \ 16384) 'green
  141.                     sb% = (srgb~& AND &HFF~&) + (_MEMGET(bbuf, boff%& + poff%, LONG) \ 16384) 'blue
  142.                     _MEMPUT rbuf, roff%& + poff%, 0 AS LONG 'clearing each single pixel error using _MEMPUT
  143.                     _MEMPUT gbuf, goff%& + poff%, 0 AS LONG 'turns out even faster than clearing the entire
  144.                     _MEMPUT bbuf, boff%& + poff%, 0 AS LONG 'pixel row using _MEMFILL at the end of the loop
  145.                     '--- find nearest color ---
  146.                     crgb~& = _RGBA32(sr%, sg%, sb%, 0) 'used for fast value clipping + channel merge
  147.                     npen% = _RGB(sr%, sg%, sb%, nhan&)
  148.                     '--- put colormapped pixel to dest ---
  149.                     _MEMPUT nbuf, noff%&, npen% AS _UNSIGNED _BYTE
  150.                     '------------------------------------------
  151.                     '--- Floyd-Steinberg error distribution ---
  152.                     '------------------------------------------
  153.                     '--- You may comment this block out, to see the
  154.                     '--- result without applied FS matrix.
  155.                     '-----
  156.                     '--- get dest palette RGB value, calc error to clipped source ---
  157.                     nrgb~& = _PALETTECOLOR(npen%, nhan&)
  158.                     er% = ((crgb~& AND &HFF0000~&) - (nrgb~& AND &HFF0000~&)) \ 65536
  159.                     eg% = ((crgb~& AND &HFF00~&) - (nrgb~& AND &HFF00~&)) \ 256
  160.                     eb% = (crgb~& AND &HFF~&) - (nrgb~& AND &HFF~&)
  161.                     '--- distribute error according to FS matrix ---
  162.                     IF x% > 0 THEN
  163.                         '--- X-1, Y+1 (= nro% (next row offset)) ---
  164.                         poff% = nro% + ppo% 'pre-calc full pixel offset
  165.                         _MEMPUT rbuf, roff%& + poff%, _MEMGET(rbuf, roff%& + poff%, LONG) + (er% * three%) AS LONG 'red
  166.                         _MEMPUT gbuf, goff%& + poff%, _MEMGET(gbuf, goff%& + poff%, LONG) + (eg% * three%) AS LONG 'green
  167.                         _MEMPUT bbuf, boff%& + poff%, _MEMGET(bbuf, boff%& + poff%, LONG) + (eb% * three%) AS LONG 'blue
  168.                     END IF
  169.                     '--- X+0, Y+1 (= nro% (next row offset)) ---
  170.                     poff% = nro% + cpo% 'pre-calc full pixel offset
  171.                     _MEMPUT rbuf, roff%& + poff%, _MEMGET(rbuf, roff%& + poff%, LONG) + (er% * five%) AS LONG 'red
  172.                     _MEMPUT gbuf, goff%& + poff%, _MEMGET(gbuf, goff%& + poff%, LONG) + (eg% * five%) AS LONG 'green
  173.                     _MEMPUT bbuf, boff%& + poff%, _MEMGET(bbuf, boff%& + poff%, LONG) + (eb% * five%) AS LONG 'blue
  174.                     IF x% < (swid% - 1) THEN
  175.                         '--- X+1, Y+0 (= cro% (current row offset)) ---
  176.                         poff% = cro% + npo% 'pre-calc full pixel offset
  177.                         _MEMPUT rbuf, roff%& + poff%, _MEMGET(rbuf, roff%& + poff%, LONG) + (er% * seven%) AS LONG 'red
  178.                         _MEMPUT gbuf, goff%& + poff%, _MEMGET(gbuf, goff%& + poff%, LONG) + (eg% * seven%) AS LONG 'green
  179.                         _MEMPUT bbuf, boff%& + poff%, _MEMGET(bbuf, boff%& + poff%, LONG) + (eb% * seven%) AS LONG 'blue
  180.                         '--- X+1, Y+1 (= nro% (next row offset)) ---
  181.                         poff% = nro% + npo% 'pre-calc full pixel offset
  182.                         _MEMPUT rbuf, roff%& + poff%, _MEMGET(rbuf, roff%& + poff%, LONG) + (er% * one%) AS LONG 'red
  183.                         _MEMPUT gbuf, goff%& + poff%, _MEMGET(gbuf, goff%& + poff%, LONG) + (eg% * one%) AS LONG 'green
  184.                         _MEMPUT bbuf, boff%& + poff%, _MEMGET(bbuf, boff%& + poff%, LONG) + (eb% * one%) AS LONG 'blue
  185.                     END IF
  186.                     '------------------------------------------
  187.                     '--- End of FS ----------------------------
  188.                     '------------------------------------------
  189.                     noff%& = noff%& + 1 'next dest pixel
  190.                     soff%& = soff%& + 4 'next source pixel
  191.                 NEXT x%
  192.                 tmp% = cro%: cro% = nro%: nro% = tmp% 'exchange distribution array row offsets
  193.             NEXT y%
  194.             '--- memory cleanup ---
  195.             _MEMFREE bbuf
  196.             _MEMFREE gbuf
  197.             _MEMFREE rbuf
  198.             _MEMFREE nbuf
  199.             _MEMFREE sbuf
  200.             '--- set result ---
  201.             RemapImageFS& = nhan&
  202.             nhan& = -1 'avoid freeing below
  203.         END IF
  204.         $CHECKING:ON
  205.         '--- remapping done or error, cleanup remains ---
  206.         IF bhan& < -1 THEN _FREEIMAGE bhan&
  207.         IF ghan& < -1 THEN _FREEIMAGE ghan&
  208.         IF rhan& < -1 THEN _FREEIMAGE rhan&
  209.         IF nhan& < -1 THEN _FREEIMAGE nhan&
  210.         IF than& < -1 THEN _FREEIMAGE than&
  211.     END IF
  212.  
  213. SUB SaveBMP (filename$, image&, x1%, y1%, x2%, y2%)
  214.     'Super special STEVE-Approved BMP Export routine for use with any QB64 graphic mode.
  215.     IF x2% = _WIDTH(image&) THEN x2% = x2% - 1
  216.     IF y2% = _HEIGHT(image&) THEN y2% = y2% - 1
  217.  
  218.     IF _PIXELSIZE(image&) = 0 THEN
  219.         IF SaveTextAs256Color THEN
  220.             tempimage& = TextScreenToImage256&(image&)
  221.         ELSE
  222.             tempimage& = TextScreenToImage32&(image&)
  223.         END IF
  224.         F = _FONT(image&)
  225.         FW = _FONTWIDTH(F): FH = _FONTHEIGHT(F)
  226.         SaveBMP filename$, tempimage&, x1% * FW, y1% * FH, x2% * FW, y2% * FH
  227.         _FREEIMAGE tempimage&
  228.         EXIT FUNCTION
  229.     END IF
  230.  
  231.     TYPE BMPFormat
  232.         ID AS STRING * 2
  233.         Size AS LONG
  234.         Blank AS LONG
  235.         Offset AS LONG
  236.         Hsize AS LONG
  237.         PWidth AS LONG
  238.         PDepth AS LONG
  239.         Planes AS INTEGER
  240.         BPP AS INTEGER
  241.         Compression AS LONG
  242.         ImageBytes AS LONG
  243.         Xres AS LONG
  244.         Yres AS LONG
  245.         NumColors AS LONG
  246.         SigColors AS LONG
  247.     END TYPE
  248.  
  249.  
  250.     DIM BMP AS BMPFormat
  251.     DIM x AS LONG, y AS LONG
  252.     DIM temp AS STRING ', t AS STRING * 1
  253.  
  254.     DIM n AS _MEM, o AS _OFFSET, m AS _MEM
  255.     m = _MEMIMAGE(image&)
  256.  
  257.     IF x1% > x2% THEN SWAP x1%, x2%
  258.     IF y1% > y2% THEN SWAP y1%, y2%
  259.     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
  260.     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
  261.  
  262.     s& = _SOURCE
  263.     _SOURCE image&
  264.  
  265.     BMP.PWidth = (x2% - x1%) + 1
  266.     BMP.PDepth = (y2% - y1%) + 1
  267.     BMP.ID = "BM"
  268.     BMP.Blank = 0
  269.     BMP.Hsize = 40
  270.     BMP.Planes = 1
  271.     BMP.Compression = 0
  272.     BMP.Xres = 0
  273.     BMP.Yres = 0
  274.  
  275.     BMP.SigColors = 0
  276.  
  277.     SELECT CASE _PIXELSIZE(image&)
  278.         CASE 1
  279.             temp = SPACE$(x2% - x1% + 1)
  280.             OffsetBITS& = 54 + 1024 'add palette in 256 color modes
  281.             BMP.BPP = 8
  282.             IF BMP.PWidth MOD 4 THEN ZeroPAD$ = SPACE$(4 - (BMP.PWidth MOD 4))
  283.             ImageSize& = (BMP.PWidth + LEN(ZeroPAD$)) * BMP.PDepth
  284.             BMP.ImageBytes = ImageSize&
  285.             BMP.NumColors = 256
  286.             BMP.Size = ImageSize& + OffsetBITS&
  287.             BMP.Offset = OffsetBITS&
  288.         CASE 4
  289.             temp = SPACE$(3)
  290.             OffsetBITS& = 54 'no palette in 24/32 bit
  291.             BMP.BPP = 24
  292.             IF ((BMP.PWidth * 3) MOD 4) THEN ZeroPAD$ = SPACE$(4 - ((BMP.PWidth * 3) MOD 4))
  293.             ImageSize& = (BMP.PWidth + LEN(ZeroPAD$)) * BMP.PDepth
  294.             BMP.ImageBytes = ImageSize&
  295.             BMP.NumColors = 0
  296.             BMP.Size = ImageSize& * 3 + OffsetBITS&
  297.             BMP.Offset = OffsetBITS&
  298.     END SELECT
  299.  
  300.     n = _MEMNEW(BMP.Size)
  301.     _MEMPUT n, n.OFFSET, BMP
  302.     o = n.OFFSET + 54
  303.     zp& = LEN(ZeroPAD$)
  304.  
  305.     IF BMP.BPP = 8 THEN 'Store the Palette for 256 color mode
  306.         FOR c& = 0 TO 255 ' read BGR color settings from JPG image + 1 byte spacer(CHR$(0))
  307.             cv& = _PALETTECOLOR(c&, image&) ' color attribute to read.
  308.             b$ = CHR$(_BLUE32(cv&)) + CHR$(_GREEN32(cv&)) + CHR$(_RED32(cv&)) + CHR$(0) 'spacer byte
  309.             _MEMPUT n, o, b$
  310.             o = o + 4
  311.         NEXT
  312.         y = y2% + 1
  313.         w& = _WIDTH(image&)
  314.         x = x2% - x1% + 1
  315.         DO
  316.             y = y - 1
  317.             _MEMGET m, m.OFFSET + (w& * y + x1%), temp
  318.             _MEMPUT n, o, temp
  319.             o = o + x
  320.             _MEMPUT n, o, ZeroPAD$
  321.             o = o + zp&
  322.         LOOP UNTIL y = y1%
  323.     ELSE
  324.         y = y2% + 1
  325.         w& = _WIDTH(image&)
  326.         DO
  327.             y = y - 1: x = x1% - 1
  328.             DO
  329.                 x = x + 1
  330.                 _MEMGET m, m.OFFSET + (w& * y + x) * 4, temp
  331.                 _MEMPUT n, o, temp
  332.                 o = o + 3
  333.             LOOP UNTIL x = x2%
  334.             _MEMPUT n, o, ZeroPAD$
  335.             o = o + zp&
  336.         LOOP UNTIL y = y1%
  337.     END IF
  338.     F = FREEFILE
  339.     OPEN filename$ FOR BINARY AS #F
  340.     t1$ = SPACE$(BMP.Size)
  341.     _MEMGET n, n.OFFSET, t1$
  342.     PUT #F, , t1$
  343.     CLOSE #F
  344.     _SOURCE s&
  345.     _MEMFREE m
  346.     _MEMFREE n
  347.  

https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: 8 bit graphics (continued from Off-Topic because of attachments)
« Reply #3 on: November 05, 2020, 12:53:19 am »
And here's a demo of how to load & convert a 256-color image with the same routines for use with your own programs.

Let's start with a 256 color image:
  [ You are not allowed to view this attachment ]  

And let's write a simple QB64 demo program to show how to work with that image:

Code: QB64: [Select]
  1. image1 = _LOADIMAGE("parrot.png", 32) 'load the 256 color image as a 32-bit image
  2. image2 = Image32To256(image1) 'convert it to a 256 color image
  3.  
  4. SCREEN image1 'show the image as a 32-bit image
  5. PRINT "32-BIT"
  6. SCREEN image2 'show the image as a 256-color image
  7. PRINT "256 COLOR"
  8.  
  9. 'As you can see, we have successfully reproduced our 256-color image
  10.  
  11.  
  12.  
  13. SLEEP 'now convert it to a 256 color image, using QB64's standard color palette
  14. DIM SHARED ConvertToStandard256Palette AS LONG 'The shared variable (or CONST) to say "Let's use QB64's standard palette!"
  15. ConvertToStandard256Palette = -1 'Set this to TRUE (or -1)
  16. image3 = Image32To256(image1) 'and convert
  17. SCREEN image3 'and you can see how we look a little bit different than we did before
  18. PRINT "256-QB64 COLOR"
  19.  
  20.  
  21.  
  22. FUNCTION Image32To256 (image&)
  23.     'This routine can benefit/be altered if the user sets a CONST or DIM SHARED variable name ConvertToStandard256Palette, as so:
  24.     '     CONST ConvertToStandard256Palette = -1
  25.     '           Set the value to 0 (FALSE) to preseve the color information perfectly, using its default palette.
  26.     '           If the CONST is set (TRUE), then we convert our colors to as close of a match as possible, while
  27.     '           preserving the standard QB64 256-color palette.
  28.     DIM o AS _OFFSET
  29.     DIM t AS _UNSIGNED LONG, color256 AS _UNSIGNED LONG
  30.     DIM index256 AS _UNSIGNED LONG
  31.     TYPE Pal_type
  32.         c AS _UNSIGNED LONG 'color index
  33.         n AS LONG 'number of times it appears
  34.     END TYPE
  35.     DIM Pal(255) AS _UNSIGNED LONG
  36.     I256 = _NEWIMAGE(_WIDTH(image&), _HEIGHT(image&), 256)
  37.     DIM m(1) AS _MEM: m(0) = _MEMIMAGE(image&): m(1) = _MEMIMAGE(I256)
  38.     DO 'get the palette and number of colors used
  39.         _MEMGET m(0), m(0).OFFSET + o, t 'Get the colors from the original screen
  40.         FOR i = 0 TO colors 'check to see if they're in the existing palette we're making
  41.             IF Pal(i) = t THEN EXIT FOR
  42.         NEXT
  43.         IF i > colors THEN
  44.             Pal(colors) = t
  45.             colors = colors + 1 'increment the index for the new color found
  46.             IF colors > 256 THEN 'no need to check any further; it's not a normal QB64 256 color image
  47.                 Image32To256 = RemapImageFS(image&, I256)
  48.                 _FREEIMAGE I256
  49.                 _MEMFREE m()
  50.                 EXIT FUNCTION 'and we're done, with 100% image compatability saved
  51.             END IF
  52.         END IF
  53.         o = o + 4
  54.     LOOP UNTIL o >= m(0).SIZE
  55.  
  56.     '  we might be working with a standard qb64 256 color screen
  57.     '  check for that first
  58.     colors = colors - 1 'back up one, as we found our limit and aren't needing to set another
  59.     FOR i = 0 TO colors 'comparing palette against QB64 256 color palette
  60.         t = Pal(i)
  61.         index256 = _RGBA(_RED32(t), _GREEN32(t), _BLUE32(t), _ALPHA32(t), I256)
  62.         color256 = _RGBA32(_RED(index256, I256), _GREEN(index256, I256), _BLUE(index256, I256), _ALPHA(index256, I256))
  63.         IF t <> color256 THEN NSCU = -1: EXIT FOR
  64.     NEXT
  65.     IF NSCU THEN 'it's not a standard QB64 256 color palette, but it's still less than 256 total colors.
  66.         IF ConvertToStandard256Palette THEN
  67.             TI256 = RemapImageFS(image&, I256)
  68.             _MEMFREE m(1) 'free the old memory
  69.             _FREEIMAGE I256 'and the old image
  70.             I256 = TI256 'replace with the new image
  71.             m(1) = _MEMIMAGE(I256) 'and point the mem block to the new image
  72.         ELSE
  73.             FOR i = 0 TO colors: _PALETTECOLOR i, Pal(i), I256: NEXT 'set the palette
  74.         END IF
  75.     END IF
  76.     'If we didn't change the palette above, we should work 100% with qb64's internal 256 color palette
  77.     o = 0
  78.     DO 'Get the colors, put them to a 256 color screen, as is
  79.         _MEMGET m(0), m(0).OFFSET + o + 3, a
  80.         _MEMGET m(0), m(0).OFFSET + o + 2, r
  81.         _MEMGET m(0), m(0).OFFSET + o + 1, g
  82.         _MEMGET m(0), m(0).OFFSET + o + 0, b
  83.         _MEMPUT m(1), m(1).OFFSET + o \ 4, _RGBA(r, g, b, a, I256) AS _UNSIGNED _BYTE
  84.         o = o + 4
  85.     LOOP UNTIL o >= m(0).SIZE
  86.     _MEMFREE m()
  87.     Image32To256 = I256
  88.  
  89. FUNCTION RemapImageFS& (ohan&, dhan&) 'Routine written by RhoSigma and used (with permission) for SaveImage Library
  90.     '// +---------------+---------------------------------------------------+
  91.     '// | ###### ###### |     .--. .         .-.                            |
  92.     '// | ##  ## ##   # |     |   )|        (   ) o                         |
  93.     '// | ##  ##  ##    |     |--' |--. .-.  `-.  .  .-...--.--. .-.        |
  94.     '// | ######   ##   |     |  \ |  |(   )(   ) | (   ||  |  |(   )       |
  95.     '// | ##      ##    |     '   `'  `-`-'  `-'-' `-`-`|'  '  `-`-'`-      |
  96.     '// | ##     ##   # |                            ._.'                   |
  97.     '// | ##     ###### | Sources & Documents placed under the MIT License. |
  98.     '// +-------------------------------------------------------------------+
  99.     '// | Done by RhoSigma, R.Heyder, provided AS IS, use at your own risk. |
  100.     '// | Find me in the QB64 Forum or mail to support[member=111]RhoSigma[/member]-cw.net for  |
  101.     '// | any questions or suggestions. Thanx for your interest in my work. |
  102.     '// +-------------------------------------------------------------------+
  103.  
  104.     RemapImageFS& = -1 'so far return invalid handle
  105.     shan& = ohan& 'avoid side effect on given argument
  106.     IF shan& < -1 OR shan& = 0 THEN '0 represents the visible screen
  107.         '--- check/adjust source image & get new 8-bit image ---
  108.         swid% = _WIDTH(shan&): shei% = _HEIGHT(shan&)
  109.         IF _PIXELSIZE(shan&) <> 4 THEN
  110.             than& = _NEWIMAGE(swid%, shei%, 32)
  111.             IF than& >= -1 THEN EXIT FUNCTION
  112.             _PUTIMAGE , shan&, than&
  113.             shan& = than&
  114.         ELSE
  115.             than& = -1 'avoid freeing below
  116.         END IF
  117.         nhan& = _NEWIMAGE(swid%, shei%, 256)
  118.         '--- Floyd-Steinberg error distribution arrays ---
  119.         rhan& = _NEWIMAGE(swid%, 2, 32) 'these are missused as LONG arrays,
  120.         ghan& = _NEWIMAGE(swid%, 2, 32) 'with CHECKING:OFF this is much faster
  121.         bhan& = _NEWIMAGE(swid%, 2, 32) 'than real QB64 arrays
  122.         '--- curr/next row offsets (for distribution array access) ---
  123.         cro% = 0: nro% = swid% * 4 'will be swapped after each pixel row
  124.         '--- the matrix values are extended by 16384 to avoid slow floating ---
  125.         '--- point ops and to allow for integer storage in the above arrays ---
  126.         '--- also it's a power of 2, which may be optimized into a bitshift ---
  127.         seven% = 7168 '(7 / 16) * 16384 'X+1,Y+0 error fraction
  128.         three% = 3072 '(3 / 16) * 16384 'X-1,Y+1 error fraction
  129.         five% = 5120 '(5 / 16) * 16384 'X+0,Y+1 error fraction
  130.         one% = 1025 '(1 / 16) * 16384 'X+1,Y+1 error fraction
  131.         '--- if all is good, then start remapping ---
  132.         $CHECKING:OFF
  133.         IF nhan& < -1 AND rhan& < -1 AND ghan& < -1 AND bhan& < -1 THEN
  134.             _COPYPALETTE dhan&, nhan& 'dest palette to new image
  135.             '--- for speed we do direct memory access ---
  136.             DIM sbuf AS _MEM: sbuf = _MEMIMAGE(shan&): soff%& = sbuf.OFFSET
  137.             DIM nbuf AS _MEM: nbuf = _MEMIMAGE(nhan&): noff%& = nbuf.OFFSET
  138.             DIM rbuf AS _MEM: rbuf = _MEMIMAGE(rhan&): roff%& = rbuf.OFFSET
  139.             DIM gbuf AS _MEM: gbuf = _MEMIMAGE(ghan&): goff%& = gbuf.OFFSET
  140.             DIM bbuf AS _MEM: bbuf = _MEMIMAGE(bhan&): boff%& = bbuf.OFFSET
  141.             '--- iterate through pixels ---
  142.             FOR y% = 0 TO shei% - 1
  143.                 FOR x% = 0 TO swid% - 1
  144.                     '--- curr/prev/next pixel offsets ---
  145.                     cpo% = x% * 4: ppo% = cpo% - 4: npo% = cpo% + 4
  146.                     '--- get pixel ARGB value from source ---
  147.                     srgb~& = _MEMGET(sbuf, soff%&, _UNSIGNED LONG)
  148.                     '--- add distributed error, shrink by 16384, clear error ---
  149.                     '--- current pixel X+0, Y+0 (= cro% (current row offset)) ---
  150.                     poff% = cro% + cpo% 'pre-calc full pixel offset
  151.                     sr% = ((srgb~& AND &HFF0000~&) \ 65536) + (_MEMGET(rbuf, roff%& + poff%, LONG) \ 16384) 'red
  152.                     sg% = ((srgb~& AND &HFF00~&) \ 256) + (_MEMGET(gbuf, goff%& + poff%, LONG) \ 16384) 'green
  153.                     sb% = (srgb~& AND &HFF~&) + (_MEMGET(bbuf, boff%& + poff%, LONG) \ 16384) 'blue
  154.                     _MEMPUT rbuf, roff%& + poff%, 0 AS LONG 'clearing each single pixel error using _MEMPUT
  155.                     _MEMPUT gbuf, goff%& + poff%, 0 AS LONG 'turns out even faster than clearing the entire
  156.                     _MEMPUT bbuf, boff%& + poff%, 0 AS LONG 'pixel row using _MEMFILL at the end of the loop
  157.                     '--- find nearest color ---
  158.                     crgb~& = _RGBA32(sr%, sg%, sb%, 0) 'used for fast value clipping + channel merge
  159.                     npen% = _RGB(sr%, sg%, sb%, nhan&)
  160.                     '--- put colormapped pixel to dest ---
  161.                     _MEMPUT nbuf, noff%&, npen% AS _UNSIGNED _BYTE
  162.                     '------------------------------------------
  163.                     '--- Floyd-Steinberg error distribution ---
  164.                     '------------------------------------------
  165.                     '--- You may comment this block out, to see the
  166.                     '--- result without applied FS matrix.
  167.                     '-----
  168.                     '--- get dest palette RGB value, calc error to clipped source ---
  169.                     nrgb~& = _PALETTECOLOR(npen%, nhan&)
  170.                     er% = ((crgb~& AND &HFF0000~&) - (nrgb~& AND &HFF0000~&)) \ 65536
  171.                     eg% = ((crgb~& AND &HFF00~&) - (nrgb~& AND &HFF00~&)) \ 256
  172.                     eb% = (crgb~& AND &HFF~&) - (nrgb~& AND &HFF~&)
  173.                     '--- distribute error according to FS matrix ---
  174.                     IF x% > 0 THEN
  175.                         '--- X-1, Y+1 (= nro% (next row offset)) ---
  176.                         poff% = nro% + ppo% 'pre-calc full pixel offset
  177.                         _MEMPUT rbuf, roff%& + poff%, _MEMGET(rbuf, roff%& + poff%, LONG) + (er% * three%) AS LONG 'red
  178.                         _MEMPUT gbuf, goff%& + poff%, _MEMGET(gbuf, goff%& + poff%, LONG) + (eg% * three%) AS LONG 'green
  179.                         _MEMPUT bbuf, boff%& + poff%, _MEMGET(bbuf, boff%& + poff%, LONG) + (eb% * three%) AS LONG 'blue
  180.                     END IF
  181.                     '--- X+0, Y+1 (= nro% (next row offset)) ---
  182.                     poff% = nro% + cpo% 'pre-calc full pixel offset
  183.                     _MEMPUT rbuf, roff%& + poff%, _MEMGET(rbuf, roff%& + poff%, LONG) + (er% * five%) AS LONG 'red
  184.                     _MEMPUT gbuf, goff%& + poff%, _MEMGET(gbuf, goff%& + poff%, LONG) + (eg% * five%) AS LONG 'green
  185.                     _MEMPUT bbuf, boff%& + poff%, _MEMGET(bbuf, boff%& + poff%, LONG) + (eb% * five%) AS LONG 'blue
  186.                     IF x% < (swid% - 1) THEN
  187.                         '--- X+1, Y+0 (= cro% (current row offset)) ---
  188.                         poff% = cro% + npo% 'pre-calc full pixel offset
  189.                         _MEMPUT rbuf, roff%& + poff%, _MEMGET(rbuf, roff%& + poff%, LONG) + (er% * seven%) AS LONG 'red
  190.                         _MEMPUT gbuf, goff%& + poff%, _MEMGET(gbuf, goff%& + poff%, LONG) + (eg% * seven%) AS LONG 'green
  191.                         _MEMPUT bbuf, boff%& + poff%, _MEMGET(bbuf, boff%& + poff%, LONG) + (eb% * seven%) AS LONG 'blue
  192.                         '--- X+1, Y+1 (= nro% (next row offset)) ---
  193.                         poff% = nro% + npo% 'pre-calc full pixel offset
  194.                         _MEMPUT rbuf, roff%& + poff%, _MEMGET(rbuf, roff%& + poff%, LONG) + (er% * one%) AS LONG 'red
  195.                         _MEMPUT gbuf, goff%& + poff%, _MEMGET(gbuf, goff%& + poff%, LONG) + (eg% * one%) AS LONG 'green
  196.                         _MEMPUT bbuf, boff%& + poff%, _MEMGET(bbuf, boff%& + poff%, LONG) + (eb% * one%) AS LONG 'blue
  197.                     END IF
  198.                     '------------------------------------------
  199.                     '--- End of FS ----------------------------
  200.                     '------------------------------------------
  201.                     noff%& = noff%& + 1 'next dest pixel
  202.                     soff%& = soff%& + 4 'next source pixel
  203.                 NEXT x%
  204.                 tmp% = cro%: cro% = nro%: nro% = tmp% 'exchange distribution array row offsets
  205.             NEXT y%
  206.             '--- memory cleanup ---
  207.             _MEMFREE bbuf
  208.             _MEMFREE gbuf
  209.             _MEMFREE rbuf
  210.             _MEMFREE nbuf
  211.             _MEMFREE sbuf
  212.             '--- set result ---
  213.             RemapImageFS& = nhan&
  214.             nhan& = -1 'avoid freeing below
  215.         END IF
  216.         $CHECKING:ON
  217.         '--- remapping done or error, cleanup remains ---
  218.         IF bhan& < -1 THEN _FREEIMAGE bhan&
  219.         IF ghan& < -1 THEN _FREEIMAGE ghan&
  220.         IF rhan& < -1 THEN _FREEIMAGE rhan&
  221.         IF nhan& < -1 THEN _FREEIMAGE nhan&
  222.         IF than& < -1 THEN _FREEIMAGE than&
  223.     END IF
  224.  
  225. SUB SaveBMP (filename$, image&, x1%, y1%, x2%, y2%)
  226.     'Super special STEVE-Approved BMP Export routine for use with any QB64 graphic mode.
  227.     IF x2% = _WIDTH(image&) THEN x2% = x2% - 1
  228.     IF y2% = _HEIGHT(image&) THEN y2% = y2% - 1
  229.  
  230.     IF _PIXELSIZE(image&) = 0 THEN
  231.         IF SaveTextAs256Color THEN
  232.             tempimage& = TextScreenToImage256&(image&)
  233.         ELSE
  234.             tempimage& = TextScreenToImage32&(image&)
  235.         END IF
  236.         F = _FONT(image&)
  237.         FW = _FONTWIDTH(F): FH = _FONTHEIGHT(F)
  238.         SaveBMP filename$, tempimage&, x1% * FW, y1% * FH, x2% * FW, y2% * FH
  239.         _FREEIMAGE tempimage&
  240.         EXIT FUNCTION
  241.     END IF
  242.  
  243.     TYPE BMPFormat
  244.         ID AS STRING * 2
  245.         Size AS LONG
  246.         Blank AS LONG
  247.         Offset AS LONG
  248.         Hsize AS LONG
  249.         PWidth AS LONG
  250.         PDepth AS LONG
  251.         Planes AS INTEGER
  252.         BPP AS INTEGER
  253.         Compression AS LONG
  254.         ImageBytes AS LONG
  255.         Xres AS LONG
  256.         Yres AS LONG
  257.         NumColors AS LONG
  258.         SigColors AS LONG
  259.     END TYPE
  260.  
  261.  
  262.     DIM BMP AS BMPFormat
  263.     DIM x AS LONG, y AS LONG
  264.     DIM temp AS STRING ', t AS STRING * 1
  265.  
  266.     DIM n AS _MEM, o AS _OFFSET, m AS _MEM
  267.     m = _MEMIMAGE(image&)
  268.  
  269.     IF x1% > x2% THEN SWAP x1%, x2%
  270.     IF y1% > y2% THEN SWAP y1%, y2%
  271.     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
  272.     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
  273.  
  274.     s& = _SOURCE
  275.     _SOURCE image&
  276.  
  277.     BMP.PWidth = (x2% - x1%) + 1
  278.     BMP.PDepth = (y2% - y1%) + 1
  279.     BMP.ID = "BM"
  280.     BMP.Blank = 0
  281.     BMP.Hsize = 40
  282.     BMP.Planes = 1
  283.     BMP.Compression = 0
  284.     BMP.Xres = 0
  285.     BMP.Yres = 0
  286.  
  287.     BMP.SigColors = 0
  288.  
  289.     SELECT CASE _PIXELSIZE(image&)
  290.         CASE 1
  291.             temp = SPACE$(x2% - x1% + 1)
  292.             OffsetBITS& = 54 + 1024 'add palette in 256 color modes
  293.             BMP.BPP = 8
  294.             IF BMP.PWidth MOD 4 THEN ZeroPAD$ = SPACE$(4 - (BMP.PWidth MOD 4))
  295.             ImageSize& = (BMP.PWidth + LEN(ZeroPAD$)) * BMP.PDepth
  296.             BMP.ImageBytes = ImageSize&
  297.             BMP.NumColors = 256
  298.             BMP.Size = ImageSize& + OffsetBITS&
  299.             BMP.Offset = OffsetBITS&
  300.         CASE 4
  301.             temp = SPACE$(3)
  302.             OffsetBITS& = 54 'no palette in 24/32 bit
  303.             BMP.BPP = 24
  304.             IF ((BMP.PWidth * 3) MOD 4) THEN ZeroPAD$ = SPACE$(4 - ((BMP.PWidth * 3) MOD 4))
  305.             ImageSize& = (BMP.PWidth + LEN(ZeroPAD$)) * BMP.PDepth
  306.             BMP.ImageBytes = ImageSize&
  307.             BMP.NumColors = 0
  308.             BMP.Size = ImageSize& * 3 + OffsetBITS&
  309.             BMP.Offset = OffsetBITS&
  310.     END SELECT
  311.  
  312.     n = _MEMNEW(BMP.Size)
  313.     _MEMPUT n, n.OFFSET, BMP
  314.     o = n.OFFSET + 54
  315.     zp& = LEN(ZeroPAD$)
  316.  
  317.     IF BMP.BPP = 8 THEN 'Store the Palette for 256 color mode
  318.         FOR c& = 0 TO 255 ' read BGR color settings from JPG image + 1 byte spacer(CHR$(0))
  319.             cv& = _PALETTECOLOR(c&, image&) ' color attribute to read.
  320.             b$ = CHR$(_BLUE32(cv&)) + CHR$(_GREEN32(cv&)) + CHR$(_RED32(cv&)) + CHR$(0) 'spacer byte
  321.             _MEMPUT n, o, b$
  322.             o = o + 4
  323.         NEXT
  324.         y = y2% + 1
  325.         w& = _WIDTH(image&)
  326.         x = x2% - x1% + 1
  327.         DO
  328.             y = y - 1
  329.             _MEMGET m, m.OFFSET + (w& * y + x1%), temp
  330.             _MEMPUT n, o, temp
  331.             o = o + x
  332.             _MEMPUT n, o, ZeroPAD$
  333.             o = o + zp&
  334.         LOOP UNTIL y = y1%
  335.     ELSE
  336.         y = y2% + 1
  337.         w& = _WIDTH(image&)
  338.         DO
  339.             y = y - 1: x = x1% - 1
  340.             DO
  341.                 x = x + 1
  342.                 _MEMGET m, m.OFFSET + (w& * y + x) * 4, temp
  343.                 _MEMPUT n, o, temp
  344.                 o = o + 3
  345.             LOOP UNTIL x = x2%
  346.             _MEMPUT n, o, ZeroPAD$
  347.             o = o + zp&
  348.         LOOP UNTIL y = y1%
  349.     END IF
  350.     F = FREEFILE
  351.     OPEN filename$ FOR BINARY AS #F
  352.     t1$ = SPACE$(BMP.Size)
  353.     _MEMGET n, n.OFFSET, t1$
  354.     PUT #F, , t1$
  355.     CLOSE #F
  356.     _SOURCE s&
  357.     _MEMFREE m
  358.     _MEMFREE n
  359.  

Now note, this makes 3 different images for you, and all of them are a little bit different.

image1 is the parrot loaded into QB64 in 32-bit color mode.  WHY _LOADIMAGE only works with 32-bit images, I don't know.  256 color support simply hasn't ever been added properly for it, for whatever reason.  Since we don't have a native way to load 256 color images, we instead load our 256-color image as a 32-bit image.

image2 is that 32-bit image converted back down to its original 256 colors, preserving the original 256 colors perfectly.  As you can tell from the demo, there's absolutely no difference in it and the 32-bit version we loaded.

image3 is that 32-bit image converted down to 256 colors, but using the standard QB64 256-color palette.  Some things are forced to change slightly, but with this, all your text colors and such are going to be the same values as what you're used to working with.  (COLOR 40 is bright red, for example.)



And that's basically how you'd load and convert a 256-color image into QB64, for use.  :)
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: 8 bit graphics (continued from Off-Topic because of attachments)
« Reply #4 on: November 05, 2020, 01:01:01 am »
in various programming environments on my HP laptop - the last two files are really messed up (color-wise).


As for this point, I'd say that's to be expected.  Not every monitor/computer is calibrated the same.  Most graphics drivers have options so the user can tweak things to their personal liking.  My main PC and my laptop have two very different displays when it comes to shades of colors sometimes.  I tend to watch movies with my laptop, so I want a wide range of dynamic colors, with full shades of black.  On my PC, I tend to play a lot of various games, and I tend to keep the contrast, brightness, and gamma turned up quite a few notches higher than normal, so I can find "hidden" items/areas in the maps easier.  Where one screen might have a color which looks vibrantly golden, on the other, it's more of an ochre-orange.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline Richard

  • Seasoned Forum Regular
  • Posts: 364
    • View Profile
Re: 8 bit graphics (continued from Off-Topic because of attachments)
« Reply #5 on: November 05, 2020, 05:16:22 am »
@ Steve

Thanks for program.

Your program (exactly as per the code box) works with the parrot.

BUT

when I change the first line now to read

image1 = _LOADIMAGE("j:\PAINTcolor256.png", 32)

where my image is stored on the J:\  usb stick (MS PAINT was used to create 256color.bmp and then MS PAINT was used to convert 256color.bmp to 256color.png) - is the result as attached below what you would expect?


  [ You are not allowed to view this attachment ]  


Also if

image1 = _LOADIMAGE("j:\PAINTcolor32bit.png)

I get ERROR MESSAGE

Unhandled Error #9
Line 44 (in main module) Subscript out of range

Line 44 =   IF Pal(i) =t THEN EXIT FOR

So I gather that I cannot use the code for a 32.bit image???

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: 8 bit graphics (continued from Off-Topic because of attachments)
« Reply #6 on: November 05, 2020, 09:11:10 am »
I don’t have a clue how MS Paint converts between BMP and PNG formats.  Both are lossless image formats, so you shouldn’t be seeing any loss/alteration of image values, so I have no clue what’s going on there.

As for the error message, add a ,32 to the end of your loadimage and it should go away.

image1 = _LOADIMAGE(“j:\PAINTcolor32bit.png”, 32)

I’d imagine that’ll eliminate your issue.  (The , 32 tells QB64 that the end image loaded is going to be a 32-bit one, and not whatever your current screen mode is.)
« Last Edit: November 05, 2020, 11:11:39 am by SMcNeill »
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: 8 bit graphics (continued from Off-Topic because of attachments)
« Reply #7 on: November 05, 2020, 12:07:40 pm »
Try my program (copied from offtopic thread about 8 bit graphics). Program will draw the parrot for you on a 256 color screen without any damage. So. If you want to make a game with pictures in 256 colors, here is a tool to upload a picture with 256 colors to the screen with 256 colors. However, the condition would be that all images that you use in the same program must have the same color palette (in case they are to be displayed at the same time). OR you can use different images with 256 colors and different palettes, but in that case you have to display it separately, or at the same time in graphics mode 32 (and then you don't need this program).

Code: QB64: [Select]
  1. 'LOADIMAGE256 experimental
  2.  
  3. '1] Load image as 32 bit image
  4. '2] find how much colors image contains. If 256 and less, continue. If more than 256, return -1 as error message. (can be solved with  RhoSigma's ditherring which is a part of SaveImage)
  5. '3] create 8 bit image and color palette
  6.  
  7. '4] BIG ASK IS: If is this image inserted to 8 bit screen, copy image palette to this screen? OR try to do the same palette for both images?
  8.  
  9.  
  10. SCREEN _NEWIMAGE(800, 600, 256)
  11. img8 = LOADIMAGE256("parrot.png")
  12. _PUTIMAGE (0, 0), img8
  13.  
  14.  
  15.  
  16.  
  17. FUNCTION LOADIMAGE256 (img$)
  18.     DEFLNG A-Z
  19.     image = _LOADIMAGE(img$, 32)
  20.  
  21.     DIM m AS _MEM, clr8(255) AS _UNSIGNED LONG, Clr32 AS _UNSIGNED LONG, test AS LONG, s AS LONG
  22.  
  23.     FOR s = 0 TO 255
  24.         clr8(s) = 99999
  25.     NEXT s
  26.  
  27.     m = _MEMIMAGE(image)
  28.     DO UNTIL p& = m.SIZE
  29.         _MEMGET m, m.OFFSET + p&, Clr32~&
  30.  
  31.         test = 0
  32.         'this block prevent for writing the same color more than 1x to palette array
  33.         DO UNTIL test = 255
  34.             IF clr8(test) = Clr32~& THEN GOTO NextColor
  35.             IF clr8(test) = 99999 THEN EXIT DO
  36.             test = test + 1
  37.         LOOP
  38.  
  39.         'if is empty place in palette, save this color as next palette color
  40.         IF test > 255 THEN PRINT "Image contains more than 256 colors, can not be directly copyed as 8 bit image": END
  41.         clr8(test) = Clr32
  42.  
  43.         'color is saved as palette for 8 bit image
  44.         NextColor: p& = p& + 4
  45.     LOOP
  46.  
  47.     image8 = _NEWIMAGE(_WIDTH(image), _HEIGHT(image), 256)
  48.  
  49.     'set palette
  50.     N = _MEMIMAGE(image8)
  51.     FOR palett = 0 TO 255
  52.         _PALETTECOLOR palett, clr8(palett), image8
  53.     NEXT
  54.  
  55.  
  56.     'create 8 bit mask (set colors 0 to 255 to 8 bit image)
  57.     FOR C = 255 TO 0 STEP -1
  58.         clr~& = clr8(C)
  59.         R& = 0
  60.         R8& = 0
  61.         DO UNTIL R& = m.SIZE
  62.             _MEMGET m, m.OFFSET + R&, Clr32
  63.             IF Clr32 = clr~& THEN _MEMPUT N, N.OFFSET + R8&, C
  64.             R& = R& + 4
  65.             R8& = R8& + 1
  66.         LOOP
  67.     NEXT C
  68.  
  69.     LOADIMAGE256 = _COPYIMAGE(image8, 256)
  70.     _MEMFREE m
  71.     _MEMFREE N
  72.     _FREEIMAGE image
  73.     _FREEIMAGE image8
  74.  
  75.  

  [ You are not allowed to view this attachment ]  

Offline Richard

  • Seasoned Forum Regular
  • Posts: 364
    • View Profile
Re: 8 bit graphics (continued from Off-Topic because of attachments)
« Reply #8 on: November 06, 2020, 03:02:24 am »
Just edited to include conversion of Steve's temp.png by SpriggySprings (this conversion use here has not yet been OK and so may be removed by me at anytime

@ Steve thankyou for your replies

Sorry that this reply is going to be a bit long

Results now of my testing your program

As suggested by you, I added the   ,32    at the end of _LOADIMAGE and with my program which is actually 3 copies of your program to show original size of your parrot, a 4x scale up of parrot, and my image being tested (your parrot.png, your temp.png, PAINTcolor256.png, PAINTcolor32bit.png and 16777216colors.png this last file that I downloaded from the internet was used in MS PAINT to create the previous two PAINT....png files). All 5 .png files are included at the end as attachments to make it easier for others to have access to if they wish. A slight modification to your program is that all three of your outputs are simultaneously display on the one screen.

NOTE   file names have been altered to include bit depth information for each file  eg (depth 8) for the parrot

Outputs:-

[depth 8]Parrot.png,32.png
  [ You are not allowed to view this attachment ]  



[depth 24]16777216colors.png,32.png
  [ You are not allowed to view this attachment ]  



[depth 32]PAINTcolor32bit.png,32.png
  [ You are not allowed to view this attachment ]  



[depth 32]PAINTcolor256.png,32.png
  [ You are not allowed to view this attachment ]  



[depth 32]temp.png,32.png
  [ You are not allowed to view this attachment ]  




At the bottom left should idealy be 3 images (as per Steve's program - the Parrot test is trivial since we know it already works). If fewer than 3 images occur it is because of the ERROR

Unhandled error #9
Line ... (in main module)
Subscript out of range

The Line in question is

If Pal(i) = t then EXIT FOR

Refer the code fragment just below to see where this is.

A program line was included to print out i every time this line was called  - the LAST VALUE OF i was always 256 (and then the Error Window popped up)


 
Code fragment from Steve's program above   


Code: QB64: [Select]
  1.     DO 'get the palette and number of colors used
  2.         _MEMGET m(0), m(0).OFFSET + o, t 'Get the colors from the original screen
  3.         FOR i = 0 TO colors 'check to see if they're in the existing palette we're making
  4.             IF Pal(i) = t THEN EXIT FOR
  5.         NEXT
  6.         IF i > colors THEN
  7.             Pal(colors) = t
  8.             colors = colors + 1 'increment the index for the new color found
  9.             IF colors > 256 THEN 'no need to check any further; it's not a normal QB64 256 color image
  10.                 Image32To256 = RemapImageFS(image&, I256)
  11.                 _FREEIMAGE I256
  12.                 _MEMFREE m()
  13.                 EXIT FUNCTION 'and we're done, with 100% image compatability saved
  14.  




@ Petr

Thankyou for your replies

I ran your program as is (with only very minor changes) and the outputs are as follows:-


Petr 800x600x256 (depth 8) parrot.png.PNG
  [ You are not allowed to view this attachment ]  



Petr 800x600x256 (depth 24) 16777216colors.png.png
  [ You are not allowed to view this attachment ]  



Petr 800x600x256 (depth 32) PAINTcolor32bit.png.png
 [ You are not allowed to view this attachment ]  





Petr 800x600x256 (depth 32) PAINTcolor256,png.png
  [ You are not allowed to view this attachment ]  



Petr 800x600x256 (depth 32) Steve's temp.png.png
  [ You are not allowed to view this attachment ]  

 

Petr 800x600x32 (depth 8) Parrot.png.png
  [ You are not allowed to view this attachment ]

 

Petr 800x600x32 (depth 24) 16777216colors.png.png
  [ You are not allowed to view this attachment ]  



Petr 800x600x32 (depth 32) PAINTcolor32bit.png.PNG
  [ You are not allowed to view this attachment ]  



Petr 800x600x32 (depth 32) PAINTcolor256.png.png
  [ You are not allowed to view this attachment ]  



Petr 800x600x32 (depth 32) Steve's temp.png.png
  [ You are not allowed to view this attachment ]  





Error Message

Unhandled Error #5
Line: 19 (in main module)
Illegal function call

The line in question is

_COPYPALETTE img8, _DEST


NOTE   eg   Petr 800x600x256  represents SCREEN _NEWIMAGE(800, 600,256)    img8 is my test file (5 altogether)


I suppose there is nothing really else I could add to this thread - sorry for the long length.





« Last Edit: November 06, 2020, 09:16:36 pm by Richard »

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: 8 bit graphics (continued from Off-Topic because of attachments)
« Reply #9 on: November 06, 2020, 01:01:41 pm »
Of course. It's hard to copy a palette to a 32-bit screen. This program is for 8-bit screens, not others.