Author Topic: loading a 256 color image  (Read 4325 times)

0 Members and 1 Guest are viewing this topic.

Offline ironwolfe

  • Newbie
  • Posts: 9
    • View Profile
loading a 256 color image
« on: April 12, 2019, 11:01:15 am »
I'm trying to load a 256 color picture into a 1289,720,256 screen but i keep getting "illegal function call" when i _putimage. I suspect its the picture itself, what is the best way to convert images to 256 colors so they are compatible with QB64.

here is a copy of the code.

DIM pic&

SCREEN _NEWIMAGE(1280, 720, 256)





temp


SUB temp


    pic& = _LOADIMAGE("demon.bmp")
    '_COPYPALETTE backgrnd1, 0
    _PUTIMAGE (3, 3), pic&



    SLEEP

END SUB



Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: loading a 256 color image
« Reply #1 on: April 12, 2019, 12:27:51 pm »
Hi. This is a known (and long-term) limitation of the LOADIMAGE command. Do you expect that if you load an image on your 256 color screen, will it change its color palette? There is a way despite the limitations of LOADIMAGE to get a 256-color image on a 256 color screen. It's called the Floyd-Steinberg method, Ashish once wrote a beautiful sample and beautifully functional program that translates it from 32 bits to 256 colors (8 bit) or more, from 256 colors (8 bit) to 16 colors (4 bit).


This what I give here, is for images that are already converted to 256 colors!

Code: QB64: [Select]
  1. a = _LOADIMAGE("cat.bmp", 256)
  2. PRINT "As you see, LOADIMAGE return -1, this is invalid handle error flag."
  3. PRINT "Try using my nethod: (press key)"
  4.  
  5. SCREEN _NEWIMAGE(1024, 768, 256)
  6. i32to256 "cat.bmp", 100, 100 'filename, X position, Y position
  7.  
  8.  
  9.  
  10.  
  11. SUB i32to256 (image AS STRING, x AS INTEGER, y AS INTEGER) '     this is already on the .NET forum writed by me. As example how show pictures in 256 colors.
  12.     IF _FILEEXISTS(image$) THEN
  13.         image& = _LOADIMAGE(image$, 32) '                       256 colors image can be loaded as 32 bit image
  14.         TYPE colors
  15.             ClrVal AS LONG '                                    this contais color number in long format (_RGB32)
  16.             ClrNmbr AS LONG '                                   this contais number for color. How much is this one color used in picture. Is for future use, if 32bit image contais more than 256 colors, then
  17.         END TYPE '                                               i will use the most used only.
  18.         REDIM colors(256) AS colors
  19.         REDIM scn AS LONG, col AS LONG, scan AS LONG, control AS LONG, TotalColors AS LONG
  20.         REDIM m AS _MEM
  21.         m = _MEMIMAGE(image&)
  22.  
  23.         FOR scan = 0 TO (_WIDTH(image&) * _HEIGHT(image&) * 4) - 4 STEP 4 ' use 32 bit, step is 4 byt * 8 bit = 32 bit, i read 4 bytes (LONG) in one loop, so STEP 4
  24.             _MEMGET m, m.OFFSET + scan, col&
  25.             FOR control = 0 TO TotalColors&
  26.                 IF col& = colors(control).ClrVal THEN colors(control).ClrNmbr = colors(control).ClrNmbr + 1: col& = 0: EXIT FOR
  27.             NEXT
  28.             IF col& <> 0 THEN colors(control + 1).ClrVal = col&: colors(control + 1).ClrNmbr = 1: TotalColors& = TotalColors& + 1: col& = 0
  29.             IF TotalColors& > 255 THEN EXIT FOR
  30.         NEXT scan
  31.         IF TotalColors& <= 256 THEN
  32.             image256& = _NEWIMAGE(_WIDTH(image&), _HEIGHT(image&), 256)
  33.             _DEST image256&
  34.             DIM m2 AS _MEM
  35.             m2 = _MEMIMAGE(image256&)
  36.             FOR MESecam = 255 - TotalColors& TO 255
  37.                 _DEST 0
  38.                 _PALETTECOLOR MESecam, colors(255 - MESecam).ClrVal
  39.             NEXT
  40.  
  41.             REDIM SelectColor AS _UNSIGNED _BYTE
  42.             FOR scan = 0 TO (_WIDTH(image&) * _HEIGHT(image&) * 4) - 4 STEP 4
  43.                 _MEMGET m, m.OFFSET + scan, Value&
  44.                 FOR SelectColor = 255 - TotalColors& TO 255
  45.                     IF colors(255 - SelectColor).ClrVal& = Value& THEN _MEMPUT m2, m2.OFFSET + position256, SelectColor
  46.                 NEXT SelectColor
  47.                 position256 = position256 + 1
  48.             NEXT scan
  49.             _PUTIMAGE (x, y), image256&, 0
  50.             _MEMFREE m: _MEMFREE m2: _FREEIMAGE image&: _FREEIMAGE image256&
  51.         ELSE PRINT "Image contains more than 256 colors."
  52.         END IF
  53.     ELSE PRINT "File "; image$; " not exists.": SLEEP 5
  54.     END IF
  55.  

Offline RhoSigma

  • QB64 Developer
  • Forum Resident
  • Posts: 565
    • View Profile
Re: loading a 256 color image
« Reply #2 on: April 12, 2019, 12:34:21 pm »
1. _LOADIMAGE currently always loads images in 32-bits mode, even 256 color images (256 color loading is disabled since a while, as it didn't work reliable since the transition from SDL to OpenGL back in 2012/13). You cannot _PUTIMAGE a 32-bits image to a 256 (8-bits) SCREEN, obviously.

2. Are you sure you want a 256 colors SCREEN? If it's only to be in line with the image's colordepth, then forget it, simply use a 32-bits SCREEN instead, then you can _PUTIMAGE to it as is.

3. If you really want a 256 colors SCREEN, then let me know and i'll provide you with my Floyd-Steinberg remapper function, which can reduce any image to a given target palette.

BTW  - Just see, Petr was faster than me, but the example he posted is NOT Floyd-Steinberg, it's a simple quantitative color reduction, which gives much less display quality than real F-S remapping. See the screen shot pictures here: https://www.qb64.org/forum/index.php?topic=809.msg100182#msg100182, that's real F-S quality.

« Last Edit: April 12, 2019, 12:49:39 pm by RhoSigma »
My Projects:   https://qb64forum.alephc.xyz/index.php?topic=809
GuiTools - A graphic UI framework (can do multiple UI forms/windows in one program)
Libraries - ImageProcess, StringBuffers (virt. files), MD5/SHA2-Hash, LZW etc.
Bonus - Blankers, QB64/Notepad++ setup pack

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: loading a 256 color image
« Reply #3 on: April 12, 2019, 01:40:22 pm »
Here is Floyd - Steinberg dithering by Vince: https://www.qb64.org/forum/index.php?topic=338.msg2271#msg2271


As you can see, the resulting image is stored on a 32-bit screen. To save it after converting to 256 color screen, you need to set 256 color screen to the correct color palette.
« Last Edit: April 12, 2019, 01:43:55 pm by Petr »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: loading a 256 color image
« Reply #4 on: April 12, 2019, 02:20:08 pm »
Aren’t you guys overthinking this?  If you load a 256 color image onto a 32-bit screen (which is what _LOADIMAGE current does), then all you need to do is a simple read-and-convert loop to put it on a 256 color screen.  No need for dithering, or anything fancy...  Just (pseudocode follows as I’m not at my PC currently)

Load the 256 color image to a 32-bit screen.
Use the 32-bit screen as a source, a 256 color screen as a destination
DIM Palette(255) ‘to hold the 255 color image palette
FOR x = 0 TO _WIDTH - 1
    FOR y = 0 TO _HEIGHT -1
        p = POINT(x,y)
        FOR i = 0 to 255
             IF p = Palette(i) THEN
                  PSET (x,y), i
                  EXIT FOR
             ELSEIF Palette(i) = 0 THEN ‘new palette color found
                   _PALETTECOLOR i, p
                   Palette(i) = p ‘store the new color
                   PSET (x,y), i
                   EXIT FOR
             END IF
         NEXT
    NEXT
NEXT
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline RhoSigma

  • QB64 Developer
  • Forum Resident
  • Posts: 565
    • View Profile
Re: loading a 256 color image
« Reply #5 on: April 12, 2019, 02:31:49 pm »
Aren’t you guys overthinking this?  If you load a 256 color image onto a 32-bit screen (which is what _LOADIMAGE current does), then all you need to do is a simple read-and-convert loop to put it on a 256 color screen.  No need for dithering, or anything fancy...  Just (pseudocode follows as I’m not at my PC currently)

In fact, you are true here. We are thinking to far according to our own skills and experiences. If we limit the whole thing to 256 color images, as the original question was about, then no dithering or color reduction is needed, as 256 colors always remain to be 256 colors, even if put to a 32-bit screen. Thanks that you focus us back to the original question.
My Projects:   https://qb64forum.alephc.xyz/index.php?topic=809
GuiTools - A graphic UI framework (can do multiple UI forms/windows in one program)
Libraries - ImageProcess, StringBuffers (virt. files), MD5/SHA2-Hash, LZW etc.
Bonus - Blankers, QB64/Notepad++ setup pack

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: loading a 256 color image
« Reply #6 on: April 12, 2019, 02:56:47 pm »
Quote
Aren’t you guys overthinking this?  If you load a 256 color image onto a 32-bit screen (which is what _LOADIMAGE current does), then all you need to do is a simple read-and-convert loop to put it on a 256 color screen.  No need for dithering, or anything fancy...  Just (pseudocode follows as I’m not at my PC currently)

:-D Hi. About which condition i write in first reply? How works my source? Dithering is need for images, which use more than 256 colors. I add here Dithering link just for interest.

Offline Raven_Singularity

  • Forum Regular
  • Posts: 158
    • View Profile
Re: loading a 256 color image
« Reply #7 on: April 12, 2019, 03:21:37 pm »
It would be nice if QB64 supported loading 8bit images to an 8bit screen.  The two simplest ways to do this are adopting the palette of the image, or when loading the image rematching the palette to the closest colour that already exists in the screen palette.  These require minimal coding.

There's also 7, 6, 5, 4, 3, 2, 1bit images, which could leave part of the screen palette alone.

That said, I can't imagine why a new programmer like ironwolfe is wanting to use a 256 colour palette screen on a modern PC.  ironwolfe, just use a 32bit screen and be done with it!  :-)

Offline Cobalt

  • QB64 Developer
  • Forum Resident
  • Posts: 878
  • At 60 I become highly radioactive!
    • View Profile
Re: loading a 256 color image
« Reply #8 on: April 12, 2019, 10:36:06 pm »
It would be nice if QB64 supported loading 8bit images to an 8bit screen.  The two simplest ways to do this are adopting the palette of the image, or when loading the image rematching the palette to the closest colour that already exists in the screen palette.  These require minimal coding.

There's also 7, 6, 5, 4, 3, 2, 1bit images, which could leave part of the screen palette alone.

That said, I can't imagine why a new programmer like ironwolfe is wanting to use a 256 colour palette screen on a modern PC.  ironwolfe, just use a 32bit screen and be done with it!  :-)

there are a few old skool tricks you can't do with 32bit, like palette shifting for one.
Granted after becoming radioactive I only have a half-life!

Offline Raven_Singularity

  • Forum Regular
  • Posts: 158
    • View Profile
Re: loading a 256 color image
« Reply #9 on: April 12, 2019, 11:57:58 pm »
Palette shifting is the only advantage I know of, but ironwolfe was not trying to do that.

Offline moises1953

  • Newbie
  • Posts: 55
    • View Profile
Re: loading a 256 color image
« Reply #10 on: April 13, 2019, 05:20:21 pm »
There is another posible solution: map the 32 bit colors to a 256 color sorted palette,
so no need to store readed colors, and can load full coloured images (more or less).
In this example the 0-15 color remains untouched for compatibility with old VGA mode 12.
Code: QB64: [Select]
  1. CONST resx = 1024, resy = 768
  2. scr& = _NEWIMAGE(resx, resy, 256)
  3. SCREEN scr&
  4. CALL ImgCreate8bitPalette
  5. imgfile$ = "D:\FQB64\QB64.PNG"
  6. px1 = 384: py1 = 80
  7. IF ImgLOAD(imgfile$, scr&, px1, py1) = 0 THEN PRINT "Can't load "; imgfile$
  8.  
  9. FUNCTION ImgLOAD% (file$, scr&, px, py)
  10.   tmp& = _LOADIMAGE(file$, 32)
  11.   IF tmp& >= -1 THEN
  12.     ImgLOAD = 0
  13.   ELSE
  14.     ImgLOAD = -1
  15.     _SOURCE tmp&
  16.     '_DEST scr&
  17.     FOR ix = 0 TO _WIDTH(tmp&) - 1
  18.       FOR iy = 0 TO _HEIGHT(tmp&) - 1
  19.         p = POINT(ix, iy)
  20.         r = _RED32(p)
  21.         g = _GREEN32(p)
  22.         b = _BLUE32(p)
  23.         IF r OR g OR b THEN
  24.           map = (b + 25) \ 51 + ((g + 25) \ 51) * 6 + ((r + 25) \ 51) * 36 ' map to sorted palette
  25.           ipal = map + 16
  26.         ELSE
  27.           ipal = 0
  28.         END IF
  29.         PSET (px + ix, py + iy), ipal
  30.       NEXT iy
  31.     NEXT ix
  32.     _SOURCE scr&
  33.     _FREEIMAGE tmp&
  34.   END IF
  35.  
  36. SUB ImgCreate8bitPalette
  37.   '.standard 16 colors VGA palette untouched (0-15)
  38.   '.Map 256->6 colors for 6^3=216 new colors, spaced 255\5=51: 0,51,102,153,204,255
  39.   '.Final palette: 15 + 216 = 231 last palette color
  40.   i = 15
  41.   FOR ir = 0 TO 255 STEP 51
  42.     FOR ig = 0 TO 255 STEP 51
  43.       FOR ib = 0 TO 255 STEP 51
  44.         i = i + 1
  45.         _PALETTECOLOR i, _RGB32(ir, ig, ib)
  46.       NEXT
  47.     NEXT
  48.   NEXT
  49.  
« Last Edit: April 13, 2019, 05:29:30 pm by moises1953 »