QB64Official / qb64

The official home for the QB64 source code and wiki.
https://qb64.com
Other
160 stars 24 forks source link

256 color image artifacts (dots and transparency) #26

Open grymmjack opened 2 years ago

grymmjack commented 2 years ago

QB64 Version: v2.1 OS: Windows 11 Pro 21H2 (OS Build 22000.856) (but it also is confirmed to happen on MacOS Monterey too)

Issues:

  1. Image artifacts with little dots
  2. Transparency not working

Using _LOADIMAGE with a 256 indexed color image and using _PUTIMAGE to blit it onto a 32 bit image renders visible artifacts in the resulting image consisting of little dots. image

Moreover, the transparency isn't working, the source image has a index 0 of pure black, but observe in the screenshots it is some different color not black. image

Attempting the work-around mentioned by @a740g in discord resulted in some weird artifacts:

You can get better results if you specify changing that like to img& = _LOADIMAGE("STARFIGHTER-VGA.gif", 256 + 1) or img& = _LOADIMAGE("STARFIGHTER-VGA.gif", 257) image

As discussed on discord, @a740g mentioned:

Well, once the image goes through stb_image there is no palette to begin with because it is all 32bpp. I could leave index 0 unmapped and map the rest when doing the palette mapping This should help cases where we assume index 0 to be black But again that is based on assumptions.

Source:

CANVAS& = _NEWIMAGE(800, 600, 32) ' I have also tried with 256 - the same issues occur
SCREEN CANVAS&

w = 512
h = 256
x = (800 - w) \ 2
y = (600 - h) \ 2

img& = _LOADIMAGE("STARFIGHTER-VGA.png", 256)

_PUTIMAGE (x,y), img&, CANVAS&

Screenshots Here is the image displayed with artifacts: image

Here is the source image: STARFIGHTER-VGA

To Reproduce Steps to reproduce the behavior:

  1. Copy above source into new file, and run.
  2. See little dots
  3. See image is not transparent

Expected behavior

  1. No image artifacts (no dots)
  2. Transparency working with index 0 - but as discussed would be preferable to specify transparent color.

Attaching the PNG as a zip just in case save for web modifies it. STARFIGHTER-VGA.zip

grymmjack commented 2 years ago

@a740g created a QB64-PE issue here: https://github.com/QB64-Phoenix-Edition/QB64pe/issues/175

Thank you @a740g regardless of where it gets fixed :)

grymmjack commented 2 years ago

As a work-around until this bug is fixed, we can use this approach (again thanks @a740g for the example):

CANVAS& = _NEWIMAGE(800, 600, 32)
SCREEN CANVAS&

speed = 7
limit = 30

w = 512
h = 256
x = (800-w) \ 2
y = (600-h) \ 2

img& = _LOADIMAGE("STARFIGHTER-RGB32b.png", 32)
_PUTIMAGE (x,y), img&, CANVAS&

DO
    _LIMIT limit
    FOR i = &H75 TO &HFF STEP speed
        oldC& = _RGB32(i, i, i)
        iStep = i+speed
        IF iStep > &HFE THEN iStep = &HFF
        newC& = _RGB32(iStep, iStep, iStep)
        ReplaceColorInBitmap CANVAS&, oldC&, newC&
        _PRINTSTRING (0, 500), HEX$(oldC&) + " -> " + HEX$(newC&), CANVAS&
    NEXT i
    FOR i = &HFF TO &H75 STEP -speed
        oldC& = _RGB32(i, i, i)
        iStep = i-speed
        IF iStep < &H76 THEN iStep = &H75
        newC& = _RGB32(iStep, iStep, iStep)
        ReplaceColorInBitmap CANVAS&, oldC&, newC&
        _PRINTSTRING (0, 500), HEX$(oldC&) + " -> " + HEX$(newC&), CANVAS&
    NEXT i
LOOP UNTIL _KEYHIT = 27

SUB ReplaceColorInBitmap (img&, srcColor&, destColor&)
    bpp = _PIXELSIZE(img&) : w = _WIDTH(img&) : h = _HEIGHT(img&)

    ' Only 32bpp images allowed
    IF bpp <> 4 THEN EXIT SUB 

    ' Setup buffer and offset
    DIM buffer AS _MEM
    buffer = _MEMIMAGE(img&)
    DIM AS _OFFSET o, oLast
    o = buffer.OFFSET                   ' Start here
    oLast = buffer.OFFSET + w * h * bpp ' Stop here

    ' s = Source, c = Check, d = Destination
    DIM AS _UNSIGNED _BYTE sR, sG, sB, cR, cG, cB, dR, dG, dB

    ' Source color RGB
    sR = _RED(srcColor&)
    sG = _GREEN(srcColor&)
    sB = _BLUE(srcColor&)

    ' Destination color RGB
    dR = _RED(destColor&)
    dG = _GREEN(destColor&)
    dB = _BLUE(destColor&)

    ' Check every color in the image
    DO
        ' Get colors from image
        cB = _MEMGET(buffer, o, _UNSIGNED _BYTE) : o = o + 1
        cG = _MEMGET(buffer, o, _UNSIGNED _BYTE) : o = o + 1
        cR = _MEMGET(buffer, o, _UNSIGNED _BYTE) : o = o + 1

        ' Check if they match and...
        IF (sR = cR AND sG = cG AND sB = cB) THEN
            ' ...replace if they do
            o = o - 3
            _MEMPUT buffer, o, dB AS _UNSIGNED _BYTE : o = o + 1
            _MEMPUT buffer, o, dG AS _UNSIGNED _BYTE : o = o + 1
            _MEMPUT buffer, o, dR AS _UNSIGNED _BYTE : o = o + 1
        END IF
        o = o + 1
    LOOP UNTIL o = oLast
    _MEMFREE buffer
END SUB