Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
BMP File format
#1
Big Grin Big Grin Big Grin Big Grin

I found a few things that _SaveFile can't do, so I'll add them here gradually. One thing every day. So first thing. Black and white BMP. Yeah. Amazing 1-bit, uncompressed BMP. In this type of BMP, compression is not supported. Maybe the compression can be partially considered the fact that each pixel in the file takes up 1 bit. The advantage of BMP over PCX is that BMP accepts any two colors.

About the program. Of course, it includes the ability to save the file. It can also open the file through its own loader, without LoadImage. There is also a image viewer (I borrowed that from my game Puzzle) and a program for setting the contrast of the input image. When setting the contrast, even thousandths matter and the output image changes rapidly. Then there is a SUB in the program for finding two suitable colors for the mask - but if you want it to be nice, you have to adjust the contrast. Of course, you can also enter the colors manually, there are only two.
Why is there a custom Loader in the program. I had an error in the file header and _LoadImage refused to open it. That's why I thought it simply didn't support it. So I wrote a loader that also smoothed the image. The result is exactly the same image as in the photo viewer. It was only when I wrote my own loader that I figured it out and fixed it. Well, never mind. My loader supports smoothing, _LoadImage doesn't. Unfortunately, smoothing comes at the expense of speed if you use large image sizes.

Code: (Select All)

'SET SOURCE IMAGE NAME (ROW 50)!                                                  BMP 1 bit Example Program

'                                                          **********************************
'                                                            Program pro uložení 1-bitové  BMP
'                                                            Program for saving a 1-bit BMP
'                                                          **********************************

'                                                                --- Struktura pro BMP (File Header + Info Header + 2 maskové záznamy) ---
'                                                                --- Structure for BMP (File Header + Info Header + 2 mask records) ---
Type BW
    ' Header / Záhlaví
    signature As String * 2 '                                        "BM" (konstantní signatura)    "BM" (constant signature)
    FileSize As Long '                                                Velikost souboru v bajtech    File size in bytes
    Res1 As Integer '                                                    Rezervováno, nepoužito    Reserved (not used)
    Res2 As Integer '                                                    Rezervováno, nepoužito    Reserved (not used)
    DataOffset As Long '                    Offset k pixelovým datům (vždy 62 u tohoto typu BMP)    Offset to pixel data (always 62 in this BMP type)

    ' InfoHeader / Informace o obrázku
    SizeOfInfoHeader As Long '                                                    Vždy 40 bajtů    Always 40 bytes
    Width As Long '                                                                Šířka obrázku    Image width
    Height As Long '                                                              Výška obrázku    Image height
    Planes As Integer '                                                      Počet rovin, vždy 1    Number of planes, always 1
    BitsPerPixel As Integer '                                  Hloubka bitů na pixel (zde 1 bit)    Bits per pixel (here 1 bit)
    Compression As Long '                                                  Komprese (0 = žádná)    Compression (0 = none)
    ImageSize As Long '                      Velikost obrázku (u nekomprimovaných obrázků je 0)    Image size (0 for uncompressed)
    XPixels As Long '                                          Horizontální rozlišení (pixely/m)    Horizontal resolution (pixels per meter)
    YPixels As Long '                                            Vertikální rozlišení (pixely/m)    Vertical resolution (pixels per meter)
    ColorsUsed As Long '                                    Použité barvy (0 = všechny z palety)    Colors used (0 means all colors from palette)
    ImportantColors As Long '                                      Důležité barvy (0 = všechny)    Important colors (0 = all)

    '                                                                                Color table    Paleta (2 záznamy pro 2 barvy obrázku)
    ColorA As _Unsigned Long '                                    První barva (obvykle popředí)    First color (usually foreground)
    ColorB As _Unsigned Long '                                      Druhá barva (obvykle pozadí)    Second color (usually background)
End Type

Screen _NewImage(_DesktopWidth, _DesktopHeight, 32)

_FullScreen



'******************************************************
' Hlavní program
' Main program
'******************************************************

' VERY IMPORTANT!!!
' VELMI DŮLEŽITÉ!!!

imageO = _LoadImage("6.jpg", 256) '                                          If you use _LoadImage xxxx.jpg, 32, go to SUB SaveBMP1 and set luminance = (77 * Red + 150 * Green + 29 * Blue) \ 256.
'                                                                            Then set correct Contrast for optimal output.

'                                                                            Načtení obrázku "6.jpg" - ideálně by měl být načten jako 8-bitový obrázek.
'                                                                            Load the image "6.jpg" - best result when loaded as an 8-bit image.
'                                                                            Tento JPG je 32-bitový; QB64PE použije vestavěnou konverzi pro nejlepší kvalitu.
'                                                                            This JPG is 32-bit; QB64PE uses built-in conversion for optimal quality.

Print "Set Contrast..." '                                                    Nastavení kontrastu obrázku    Setting image contrast
SetContrast imageO, 1 '.11 ' 1 is default contrast some imeges needs              Volání funkce SetContrast s hodnotou 1    Call SetContrast function with value 1
'                              contrast higher - try and see
Print "Detect mask colors..." '                                              Detekce maskovacích barev (např. černá a bílá)
'                                                                            Detect mask colors (e.g., black and white) - HERE IS 5 OPTIONS for detecting mask images
If ClrsCnt(imageO) > 2 Then
    DetectMaskColors imageO, 5, backGroundColor~&, foregroundColor~& '      Options in DetectMaskColors: 5 = use default mask color Black and White
    '                                                                                                    4 = Colors with medium brightness
    '                                                                                                    3 = Two most contrating colors
    '                                                                                                    2 = Darkest and brightest colors
    '                                                                                                    1 = Two most frequent colors

    '                                                                        Pokud obrázek obsahuje více než 2 barvy, detekuje maskovací barvy pomocí režimu 5 (černá a bílá).
    '                                                                        If the image has more than 2 colors, detect mask colors using mode 5 (black and white).
End If

Print "Save image..." '                                                      Uložení obrázku jako 1-bit BMP    Saving image as 1-bit BMP
SaveBMP1 imageO, "Bitmap1.bmp", foregroundColor~&, backGroundColor~&
'                                                                            Uloží obrázek imageO do souboru "Bitmap1.bmp" s danými barvami popředí a pozadí.
'                                                                            Save imageO to file "Bitmap1.bmp" with specified foreground and background colors.

Print "Load and make smooth...." '                                          Načtení BMP a aplikace vyhlazení    Load BMP and apply smoothing
image = LoadAndSmoothBMP1Bit("Bitmap1.bmp")
'                                                                            Načte 1-bit BMP pomocí vlastní funkce, protože _LoadImage nepodporuje 1-bitové BMP.
'                                                                            Load 1-bit BMP using a custom function since _LoadImage does not accept 1-bit BMPs.

ViewImage image '                                                            Zobrazení obrázku na obrazovce    Display the image
Print "Press key for "
Print "LoadImage output."
Sleep
_FreeImage image
image = _LoadImage("Bitmap1.bmp")
ViewImage image
Print "Without Smmoothing"
Print "Press key..."
Sleep
_FreeImage imageO
Clear
End



'******************************************************
' Subrutina pro zobrazení obrázku
' Subroutine to display the image (with scaling)
'******************************************************
Sub ViewImage (Img As Long)


    '                                                                      Calculate the difference between image dimensions and desktop dimensions.
    SpcV_DeltaW = Abs(_Width(Img) - _DesktopWidth) '                        Rozdíl šířky obrázku a desktopu    Difference in width between image and desktop
    SpcV_DeltaH = Abs(_Height(Img) - _DesktopHeight) '                      Rozdíl výšky obrázku a desktopu    Difference in height between image and desktop

    ' Vypočítá procentuální rozdíl
    ' Calculate percentage difference
    SpcV_PercW = SpcV_DeltaW / (_Width(Img) / 100) '                        Procentuální rozdíl šířky    Percentage difference in width
    SpcV_PercH = SpcV_DeltaH / (_Height(Img) / 100) '                      Procentuální rozdíl výšky    Percentage difference in height

    ' Volba vyššího procenta
    ' Choose the higher percentage
    If SpcV_PercW > SpcV_PercH Then
        SpcV_P = SpcV_PercW
    Else
        SpcV_P = SpcV_PercH
    End If
    SpcV_P = SpcV_P / 100

    '                                                                      Výpočet konečného poměru pro změnu velikosti obrázku
    '                                                                      Calculate final scaling ratio for the image
    If _Width(Img) > _DesktopWidth And _Height(Img) > _DesktopHeight Then
        FinalRatio = 1 - SpcV_P '                                          Downsizing, pokud je obrázek větší ve všech směrech    Downsizing if image is larger in both dimensions
    End If

    If _Height(Img) < _DesktopHeight And _Width(Img) < _DesktopWidth Then
        FinalRatio = _DesktopHeight / _Height(Img) '                        Upsizing, pokud je obrázek menší než výška desktopu    Upsizing if image is smaller than desktop height
    End If

    If _Height(Img) > _DesktopHeight And _Width(Img) < _DesktopWidth Then
        SpcV_PercH = SpcV_DeltaH / (_Height(Img) / 100)
        SpcV_PercH = SpcV_PercH / 100
        FinalRatio = 1 - SpcV_PercH '                                      Downsizing, pokud je obrázek vyšší než desktop    Downsizing if image height exceeds desktop height
    End If

    If _Height(Img) < _DesktopHeight And _Width(Img) > _DesktopWidth Then
        SpcV_PercW = SpcV_DeltaW / (_Width(Img) / 100)
        SpcV_PercW = SpcV_PercW / 100
        Beep
        FinalRatio = 1 - SpcV_PercW '                                      Downsizing, pokud je obrázek širší než desktop    Downsizing if image width exceeds desktop width
    End If

    If _Height(Img) = _DesktopHeight And _Width(Img) = _DesktopHeight Then
        FinalRatio = 1 '                                                    Pokud jsou rozměry shodné, ponech poměr 1    If dimensions match, keep scale 1
    End If

    '                                                                      Výpočet nových rozměrů a centrování obrázku
    '                                                                      Calculate new dimensions and center the image on the screen
    SpcV_W = FinalRatio * _Width(Img) '                                    Nová šířka obrázku    New image width
    SpcV_H = FinalRatio * _Height(Img) '                                    Nová výška obrázku    New image height
    SpcV_DeltaX = (_DesktopWidth - SpcV_W) \ 2 '                            Horizontální posun pro centrování    Horizontal offset to center the image

    _PutImage (SpcV_DeltaX, 0)-(SpcV_DeltaX + SpcV_W, SpcV_H), Img&, 0 '    Zobrazení obrázku na přepočítané pozici a rozměrech
    '                                                                      Display the image at calculated position and size
End Sub



'******************************************************
' Subrutina pro nastavení kontrastu obrázku
' Subroutine to adjust image contrast
'******************************************************
Sub SetContrast (handle As Long, value)
    '                                                                      handle: identifikátor obrázku    image handle
    '                                                                      value: hodnota kontrastu (0 až 5; 5 = 500% kontrastu)    value in range 0 to 5; 5 means 500% contrast

    Dim m As _MEM
    Dim a As Long
    Dim As _Unsigned Long newC
    Dim As _Unsigned _Byte r, g, b, c, NewR, NewG, NewB

    m = _MemImage(handle) '                                                  Získání paměťové struktury obrázku    Get the memory structure of the image

    Select Case _PixelSize(handle)
        Case 1 '                                                            Pro 8-bitový obrázek (paletový)  For 8 bit image
            Do Until a = m.SIZE
                _MemGet m, m.OFFSET + a, c '                                Načtení indexu palety    Retrieve palette index

                r = _Red32(_PaletteColor(c, handle))
                g = _Green32(_PaletteColor(c, handle))
                b = _Blue32(_PaletteColor(c, handle))

                '                                                            Aplikace kontrastu na jednotlivé barevné kanály
                '                                                            Apply contrast adjustment on each channel
                NewR = (r - 128) * value + 128
                NewG = (g - 128) * value + 128
                NewB = (b - 128) * value + 128

                '                                                            Ošetření přetečení a podtečení (hranice 0-255)
                '                                                            Clamp values to 0-255 range
                If NewR > 255 Then NewR = 255
                If NewR < 0 Then NewR = 0
                If NewG > 255 Then NewG = 255
                If NewG < 0 Then NewG = 0
                If NewB > 255 Then NewB = 255
                If NewB < 0 Then NewB = 0

                newC = _RGB32(NewR, NewG, NewB)
                _PaletteColor c, newC, handle

                a = a + 1
            Loop

        Case 4 '                                                              Pro 32-bitový obrázek  For 32 bit image
            Do Until a = m.SIZE
                _MemGet m, m.OFFSET + a, b
                _MemGet m, m.OFFSET + a + 1, g
                _MemGet m, m.OFFSET + a + 2, r

                NewR = (r - 128) * value + 128
                NewG = (g - 128) * value + 128
                NewB = (b - 128) * value + 128

                If NewR > 255 Then NewR = 255
                If NewR < 0 Then NewR = 0
                If NewG > 255 Then NewG = 255
                If NewG < 0 Then NewG = 0
                If NewB > 255 Then NewB = 255
                If NewB < 0 Then NewB = 0

                _MemPut m, m.OFFSET + a, NewB
                _MemPut m, m.OFFSET + a + 1, NewG
                _MemPut m, m.OFFSET + a + 2, NewR

                a = a + 4
            Loop
    End Select
End Sub



'******************************************************                      Speed - up updated function - from PCX thread
' Funkce pro spočítání počtu barev v obrázku
' Function to count the number of colors in the image (8-bit and 32-bit)
'******************************************************
Function ClrsCnt (handle As Long)
    '                                                                        Vrátí počet unikátních barev v obrázku
    '                                                                        Returns the count of unique colors in the image
    Dim As _Unsigned _Byte r, g, b
    Dim As _MEM m
    Dim As Long a, Clrscn
    m = _MemImage(handle)

    If _PixelSize(handle) > 1 Then
        Dim c(255, 255, 255) As _Unsigned _Byte
        Do Until a = m.SIZE
            _MemGet m, m.OFFSET + a, b
            _MemGet m, m.OFFSET + a + 1, g
            _MemGet m, m.OFFSET + a + 2, r
            a = a + 4
            If c(r, g, b) = 0 Then
                Clrscn = Clrscn + 1
                c(r, g, b) = 1
            End If
        Loop
        ClrsCnt = Clrscn
    Else
        Dim d(255) As _Byte
        Do Until a = m.SIZE
            index = _MemGet(m, m.OFFSET + a, _Unsigned _Byte)
            If d(index) = 0 Then
                d(index) = 1
                Clrscn = Clrscn + 1
            End If
            a = a + 1
        Loop
        ClrsCnt = Clrscn
    End If
End Function



'******************************************************
' Subrutina pro detekci maskovacích barev
' Subroutine to detect mask colors based on a given mode
'******************************************************
Sub DetectMaskColors (handle As Long, mode As Integer, color1 As _Unsigned Long, color2 As _Unsigned Long)
    '                                                                                                            Detekuje maskovací barvy podle zvoleného režimu
    '                                                                                                            Detects mask colors according to the selected mode
    Dim m As _MEM
    Dim a As Long
    Dim As _Unsigned _Byte r, g, b, c, brightness
    Dim colorCount(255) As Long '                                                                                Histogram pro paletový obrázek    Histogram for paletted image
    Dim brightnessHist(255) As Long '                                                                            Histogram světlosti    Histogram for brightness
    Dim totalBrightness As Long
    Dim totalPixels As Long
    Dim isPaletted As _Unsigned _Byte

    m = _MemImage(handle)

    If _PixelSize(handle) = 1 Then
        isPaletted = 1 '                                                                                          8-bitový obrázek (paletový)    8-bit paletted image
        '                                                                                                        Projdeme paletové barvy
        '                                                                                                        Loop through palette colors
        a = 0
        Do Until a >= m.SIZE
            _MemGet m, m.OFFSET + a, c '                                                                          Načtení indexu palety    Get palette index
            brightness = (0.3 * _Red32(_PaletteColor(c, handle)) + 0.59 * _Green32(_PaletteColor(c, handle)) + 0.11 * _Blue32(_PaletteColor(c, handle)))
            brightnessHist(brightness) = brightnessHist(brightness) + 1
            colorCount(c) = colorCount(c) + 1
            totalBrightness = totalBrightness + brightness
            totalPixels = totalPixels + 1
            a = a + 1
        Loop
    End If
    _MemFree m

    If totalPixels = 0 Then totalPixels = 1 '                                                                        Ochrana proti dělení nulou    Prevent division by zero

    Select Case mode
        Case 1 '                                                                                                    Nejčastější dvě barvy    Two most frequent colors
            Dim max1 As Long, max2 As Long, idx1 As _Unsigned _Byte, idx2 As _Unsigned _Byte
            For a = 0 To 255
                If colorCount(a) > max1 Then
                    max2 = max1
                    idx2 = idx1
                    max1 = colorCount(a)
                    idx1 = a
                ElseIf colorCount(a) > max2 Then
                    max2 = colorCount(a)
                    idx2 = a
                End If
            Next
            color1 = _PaletteColor(idx1, handle)
            color2 = _PaletteColor(idx2, handle)

        Case 2 '                                                                                                      Nejtmavší a nejsvětlejší barva    Darkest and brightest colors
            Dim minIdx As _Unsigned _Byte, maxIdx As _Unsigned _Byte
            For a = 0 To 255
                If brightnessHist(a) > 0 Then
                    minIdx = a
                    Exit For
                End If
            Next
            For a = 255 To 0 Step -1
                If brightnessHist(a) > 0 Then
                    maxIdx = a
                    Exit For
                End If
            Next
            color1 = _PaletteColor(minIdx, handle)
            color2 = _PaletteColor(maxIdx, handle)

        Case 3 '                                                                                                        Nejkontrastnější dvě barvy    Two most contrasting colors
            Dim best1 As _Unsigned _Byte, best2 As _Unsigned _Byte, maxContrast As Long
            For a = 0 To 255
                For b = a + 1 To 255
                    Dim contrast As Long
                    contrast = Abs(a - b)
                    If contrast > maxContrast Then
                        maxContrast = contrast
                        best1 = a
                        best2 = b
                    End If
                Next
            Next
            color1 = _PaletteColor(best1, handle)
            color2 = _PaletteColor(best2, handle)

        Case 4 '                                                                                                            Barvy se střední světlostí    Colors with medium brightness
            Dim middleBrightness As Long
            middleBrightness = totalBrightness \ totalPixels
            Dim closest1 As _Unsigned _Byte, closest2 As _Unsigned _Byte, minDiff1 As Long, minDiff2 As Long
            minDiff1 = 256
            minDiff2 = 256
            For a = 0 To 255
                Dim diff As Long
                diff = Abs(a - middleBrightness)
                If diff < minDiff1 Then
                    minDiff2 = minDiff1
                    closest2 = closest1
                    minDiff1 = diff
                    closest1 = a
                ElseIf diff < minDiff2 Then
                    minDiff2 = diff
                    closest2 = a
                End If
            Next
            color1 = _PaletteColor(closest1, handle)
            color2 = _PaletteColor(closest2, handle)

        Case 5 ' P                                                                                                            evně nastavené: Černá a bílá    Fixed mode: Black and White
            color1 = _RGB32(0, 0, 0)
            color2 = _RGB32(255, 255, 255)
    End Select
End Sub



'*********************************************************************************************
' Subrutina pro uložení 1-bit BMP souboru
' Subroutine to save a 1-bit BMP file (uncompressed), 1Bit BMP do not support RLE compression.
'*********************************************************************************************
Sub SaveBMP1 (imageRef As Long, fileName As String, Fgc As _Unsigned Long, Bgc As _Unsigned Long)
    ' Parametry:
    ' imageRef - identifikátor obrázku    image handle
    ' fileName - název souboru    output file name
    ' Fgc - barva popředí (foreground)    foreground color
    ' Bgc - barva pozadí (background)    background color


    Dim W As Long, H As Long, Wo As Long
    Wo = _Width(imageRef) '              Původní šířka obrázku    Original image width
    H = _Height(imageRef) '                      Výška obrázku    Image height

    '                                  Uprav šířku, aby byla dělitelná 32 (nutné pro řádkové zarovnání BMP)
    '                                  Adjust width to be divisible by 32 (required for BMP row alignment)
    Do Until Wo Mod 32 = 0
        Wo = Wo + 1
    Loop
    W = Wo

    '                                  Vytvoř nový obrázek s upravenou šířkou
    '                                  Create a new image with adjusted width
    Dim newImage As Long
    newImage = _NewImage(W, H, 32)
    Dim clr As _Unsigned Long
    clr~& = &HFFFFFFFF '              Barva pozadí (např. bílá)    Background color (e.g., white)
    _Dest newImage
    Cls , clr~&

    '                                  Zkopíruj původní obrázek do nového s novými rozměry
    '                                  Copy original image into new image with adjusted dimensions
    _PutImage (0, 0), imageRef, newImage, (0, H)-(W, 0)

    '                                (Volitelně) Uvolni původní obrázek, pokud již není potřeba
    '                                  Optionally free the original image if no longer needed:
    _FreeImage imageRef

    '                                Vypočítej celkovou velikost BMP souboru (62 bajtů = velikost záhlaví)
    '                                Calculate total file size (header size is 62 bytes)
    Dim Size As Long
    Size = _Ceil(W * H / 8) + 62

    '                                Naplň strukturu BMP hlavičky
    '                                Fill in BMP header structure
    Dim BMP1 As BW
    BMP1.signature = "BM"
    BMP1.FileSize = Size
    BMP1.DataOffset = 62
    BMP1.SizeOfInfoHeader = 40
    BMP1.Width = W
    BMP1.Height = H
    BMP1.Planes = 1 '
    BMP1.BitsPerPixel = 1 '
    BMP1.Compression = 0
    BMP1.ImageSize = Size - 62
    BMP1.XPixels = 0
    BMP1.YPixels = 0
    BMP1.ColorsUsed = 0
    BMP1.ImportantColors = 0
    BMP1.ColorA = Fgc '                  Foreground barva    Foreground color
    BMP1.ColorB = Bgc '                  Background barva    Background color

    '                                    Převod obrázku na řádky 1-bitové bitmapy (každý byte reprezentuje 8 pixelů)
    '                                    Convert the image into 1-bit bitmap data (each byte represents 8 pixels)
    Dim m As _MEM
    m = _MemImage(newImage)

    Dim BW_Image(m.SIZE \ 8) As _Unsigned _Byte
    Dim i As Long, j As Long, px As Long
    i& = 0: j = 0

    Do Until i& >= m.SIZE
        Dim Nibble As _Unsigned _Byte
        Nibble = 0
        For px = 0 To 7
            If i& + px + 4 > m.SIZE Then Exit Do
            Dim Red As _Unsigned _Byte, Green As _Unsigned _Byte, Blue As _Unsigned _Byte
            Red = _MemGet(m, m.OFFSET + i& + 3 + px * 4, _Unsigned _Byte)
            Green = _MemGet(m, m.OFFSET + i& + 2 + px * 4, _Unsigned _Byte)
            Blue = _MemGet(m, m.OFFSET + i& + 1 + px * 4, _Unsigned _Byte)

            Dim luminance As Long
            luminance = (77 * Red + 150 * Green + 29 * Blue) And 2048 'modified!

            If luminance < 128 Then
                Nibble = _SetBit(Nibble, 7 - px)
            End If
        Next
        BW_Image(j) = Nibble
        i& = i& + 8 * 4
        j = j + 1
    Loop

    '                                  Odstranění existujícího souboru, pokud již existuje
    '                                  Delete the file if it already exists
    If _FileExists(fileName) Then Kill fileName

    '                                  Uložení BMP souboru do disku
    '                                  Write the BMP file to disk
    Open fileName For Binary As #1
    Put #1, 1, BMP1
    Put #1, 63, BW_Image()
    Close #1

    '                                  Uvolnění prostředků
    '                                  Free resources
    ReDim BW_Image(0)
    _FreeImage newImage
End Sub



'******************************************************
' Definice typů pro BMP formát
' Definitions for BMP format types
'******************************************************

Type BMPHEADER
    signature As String * 2 '            "BM" – signatura souboru    "BM" – file signature
    filesize As Long '                    Velikost souboru v bajtech    File size in bytes
    reserved1 As Integer '                Rezervováno    Reserved (16-bit)
    reserved2 As Integer '                Rezervováno    Reserved (16-bit)
    dataoffset As Long '    Offset k pixelovým datům    Offset to pixel data
End Type

Type BMPINFOHEADER
    headersize As Long '    záhlaví (obvykle 40 bajtů)    Header size (usually 40 bytes)
    width As Long '                      Šířka obrázku    Image width
    height As Long '                      Výška obrázku    Image height
    planes As Integer '            Počet rovin (vždy 1)    Number of planes (always 1)
    bitcount As Integer '        Hloubka bitů na pixel    Bits per pixel
    compression As Long '          Komprese (0 = žádná)    Compression (0 = none)
    imagesize As Long '                Velikost obrázku    Image size
    xpixels As Long '            Horizontální rozlišení    Horizontal resolution
    ypixels As Long '              Vertikální rozlišení    Vertical resolution
    colorsused As Long '          Počet barev v paletě    Colors used in the palette
    importantcolors As Long '            Důležité barvy    Important colors
End Type

Type BMPColor
    blue As _Unsigned _Byte '              Modrá složka    Blue component
    green As _Unsigned _Byte '            Zelená složka    Green component
    red As _Unsigned _Byte '            Červená složka    Red component
    reserved As _Unsigned _Byte '          Rezervováno    Reserved
End Type



'******************************************************
' Funkce pro načtení 1-bit BMP souboru
' Function to load a 1-bit BMP file
'******************************************************
Function LoadBMP1Bit& (fileName As String)
    Dim header As BMPHEADER
    Dim info As BMPINFOHEADER
    Dim pal(1) As BMPColor

    Open fileName For Binary As #1

    '                              Načtení BMP hlavičky (14 bajtů)
    '                              Read BMP file header (14 bytes)
    Get #1, , header
    If header.signature <> "BM" Then
        Print "Chyba: Soubor není BMP." ' Error: File is not a BMP.
        Close #1
        LoadBMP1Bit = 0
        Exit Function
    End If

    '                              Načtení BITMAPINFOHEADER (40 bajtů)
    '                              Read BITMAPINFOHEADER (40 bytes)
    Get #1, , info
    If info.bitcount <> 1 Then
        Print "Chyba: BMP není 1bitový." ' Error: BMP is not 1-bit.
        Close #1
        LoadBMP1Bit = 0
        Exit Function
    End If

    '                                    Načtení palety (2 barvy)
    '                                    Read the color palette (2 colors)
    For i = 0 To 1
        Get #1, , pal(i)
    Next i

    '                                    Výpočet velikosti jednoho řádku (včetně paddingu na 4 bajty)
    '                                    Calculate the size of one row (with 4-byte padding)
    Dim bytesPerRow As Long
    bytesPerRow = (info.width + 7) \ 8
    Dim rowSize As Long
    rowSize = ((bytesPerRow + 3) \ 4) * 4

    Dim totalBytes As Long
    totalBytes = rowSize * info.height

    '                                  Načtení pixelových dat
    '                                  Read pixel data
    ReDim ddata(totalBytes - 1) As _Unsigned _Byte
    Seek #1, header.dataoffset '        Nastavení pozice na začátek pixelových dat    Set file pointer to pixel data offset
    Get #1, , ddata()
    Close #1

    '                                  Vytvoření 32-bitového obrázku pro výstup
    '                                  Create a 32-bit image for output
    Dim img As Long
    img = _NewImage(info.width, info.height, 32)

    '                                  Vytvoření pole pro výsledné pixely
    '                                  Create an array for the resulting pixels
    ReDim pixels(info.width * info.height - 1) As _Unsigned Long

    '                                  Definice masky bitů (od MSB po LSB)
    '                                  Define bit masks (from MSB to LSB)
    Dim bitMasks(7) As _Unsigned _Byte
    bitMasks(0) = &H80
    bitMasks(1) = &H40
    bitMasks(2) = &H20
    bitMasks(3) = &H10
    bitMasks(4) = &H08
    bitMasks(5) = &H04
    bitMasks(6) = &H02
    bitMasks(7) = &H01

    '                                  Rozložení pixelových dat do pole pixelů
    '                                  Decompose pixel data into pixel array
    Dim y As Long, b As Long, bit As Long
    Dim rowIndex As Long, rowOffset As Long, x As Long, pixelIndex As Long
    Dim currentByte As _Byte
    Dim col As _Unsigned Long

    For y = 0 To info.height - 1
        rowIndex = info.height - 1 - y ' BMP data jsou uložena zdola nahoru    BMP stores rows from bottom to top
        rowOffset = rowIndex * rowSize
        For b = 0 To bytesPerRow - 1
            currentByte = ddata(rowOffset + b)
            For bit = 0 To 7
                x = b * 8 + bit
                If x >= info.width Then Exit For
                pixelIndex = y * info.width + x

                If (currentByte And bitMasks(bit)) <> 0 Then
                    col = _RGB32(pal(1).red, pal(1).green, pal(1).blue)
                Else
                    col = _RGB32(pal(0).red, pal(0).green, pal(0).blue)
                End If
                pixels(pixelIndex) = col
            Next bit
        Next b
    Next y

    ' Přenos pixelů do vytvořeného obrázku
    ' Copy pixel data into the image
    Dim m As _MEM, n As _MEM
    m = _MemImage(img)
    Dim numBytes As Long
    numBytes = info.width * info.height * 4
    n = _Mem(pixels())
    _MemCopy n, n.OFFSET, numBytes To m, m.OFFSET
    _MemFree n
    _MemFree m
    LoadBMP1Bit = img
End Function



'******************************************************
' Funkce pro načtení 1-bit BMP a jeho vyhlazení
' Function to load a 1-bit BMP and apply smoothing (Gaussian blur)
'******************************************************
Function LoadAndSmoothBMP1Bit& (fileName As String)
    Dim img As Long
    img = LoadBMP1Bit(fileName) ' Načtení 1-bit BMP pomocí vlastní funkce
    ' Load 1-bit BMP using custom loader

    If img = 0 Then
        Print "Chyba při načítání BMP!" ' Error loading BMP!
        Print "Error loading BMP!"
        Exit Function
    End If

    Dim width As Long, height As Long
    width = _Width(img)
    height = _Height(img)

    ' Vytvoření nového obrázku pro vyhlazení
    ' Create a new image for the smoothed output
    Dim smoothedImg As Long
    smoothedImg = _NewImage(width, height, 32)

    ' Přístup k pixelovým datům
    ' Access pixel data of both images
    Dim m As _MEM, n As _MEM, jj As _MEM
    m = _MemImage(img)
    n = _MemImage(smoothedImg)

    ' Načtení pixelových dat do pole
    ' Copy pixels into an array for processing
    ReDim pixels(width * height - 1) As _Unsigned Long
    jj = _Mem(pixels())
    _MemCopy m, m.OFFSET, m.SIZE To jj, jj.OFFSET
    _MemFree jj

    ' Vyhlazení obrázku pomocí 3×3 Gaussova filtru
    ' Apply smoothing using a 3x3 Gaussian filter
    Dim x As Long, y As Long, i As Long, j As Long
    ReDim newPixels(width * height - 1) As _Unsigned Long

    ' Přibližný 3×3 Gaussův filtr
    ' Approximate 3x3 Gaussian filter weights
    Dim filter(2, 2) As Single
    filter(0, 0) = 1 / 16: filter(0, 1) = 2 / 16: filter(0, 2) = 1 / 16
    filter(1, 0) = 2 / 16: filter(1, 1) = 4 / 16: filter(1, 2) = 2 / 16
    filter(2, 0) = 1 / 16: filter(2, 1) = 2 / 16: filter(2, 2) = 1 / 16
    Dim rSum As Single, gSum As Single, bSum As Single
    Dim index As Long
    Dim pixelColor As _Unsigned Long
    Dim r As _Unsigned _Byte, g As _Unsigned _Byte, b As _Unsigned _Byte
    Dim newCol As _Unsigned Long

    ' Procházení obrazu (vynecháme okraje)
    ' Process the image excluding the borders
    For y = 1 To height - 2
        For x = 1 To width - 2
            rSum = 0: gSum = 0: bSum = 0
            ' Aplikace filtru 3×3
            ' Apply 3x3 filter
            For i = -1 To 1
                For j = -1 To 1
                    index = (y + i) * width + (x + j)
                    pixelColor = pixels(index)
                    r = _Red32(pixelColor)
                    g = _Green32(pixelColor)
                    b = _Blue32(pixelColor)
                    rSum = rSum + r * filter(i + 1, j + 1)
                    gSum = gSum + g * filter(i + 1, j + 1)
                    bSum = bSum + b * filter(i + 1, j + 1)
                Next j
            Next i
            ' Uložení vyhlazeného pixelu
            ' Save the smoothed pixel
            newCol = _RGB32(rSum, gSum, bSum)
            newPixels(y * width + x) = newCol
        Next x
    Next y

    ' Kopírování vyhlazených pixelů zpět do obrázku
    ' Copy the smoothed pixels back into the image
    Dim jjj As _MEM
    jjj = _Mem(newPixels())
    _MemCopy jjj, jjj.OFFSET, jjj.SIZE To n, n.OFFSET
    _MemFree jjj
    ' Uvolnění paměti
    ' Free memory
    _MemFree m
    _MemFree n
    _FreeImage img
    ' Výstup vyhlazeného obrázku
    ' Return the smoothed image
    LoadAndSmoothBMP1Bit = smoothedImg
End Function


In attachments is output using _LoadImage (not smooth) and second is with my loder (smooth). Would you say it's just two colors?


Attached Files Image(s)
       


Reply
#2
4 bite BMP

So it's time for two more posts. I had problems with the second program, I finally solved it/didn't solve it - but now it works correctly even if it's not completely according to the specification.

The first program is a simple thing, saving and loading an uncompressed image into BMP in 4 bits, the number of colors for the image is a maximum of 16. The number of colors in the input image is not monitored. However, there is a function directly in the program for that, which does not monitor this, it just prints the number of colors after loading the created image.
So the first program: Uncompressed BMP 4 Bit, 16 colors:

Code: (Select All)

'---------------------------------------------------                  --------------------------------------------------
'Uloží obrázek s 16 barvami jako nekomprimovaný BMP                  Save image in max 16 colors as uncompressed bitmap
'---------------------------------------------------                  --------------------------------------------------

Screen _NewImage(1024, 768, 32)

Dim img16 As Long
img16 = _NewImage(800, 600, 256)
_Dest img16 '                        create some image
For f = 0 To 15
    Line (0 + 20 * f, 0 + 20 * f)-(800 - 20 * f, 600 - 20 * f), f, BF
Next
_Dest 0

outFile$ = "16-4-not_compressed.bmp"
Print "Creating uncompressed 4 bit bitmap with 16 colors..."
SaveAs4BitBMP img16, outFile$
_FreeImage img16

i = _LoadImage(outFile$, 256)
_PutImage , i
Print "File "; outFile$; " saved. _LoadImage support this format."
Print "Image use: "; ClrsCnt(i); "colors." '                                                                                            Výpis informací o obrázku      Print image details
Print "Image width: "; _Width(i); "Image height: "; _Height(i); "Image size: "; GetSze("outfile$"); "B Image PixelSize:"; _PixelSize(i)
Sleep
_FreeImage i
End

Function GetSze (file As String) '                                                                                                Vrací velikost souboru v bajtech      Returns file size in bytes
    ff = FreeFile
    Open file For Binary As ff
    GetSze = LOF(ff)
    Close ff
End Function

Sub SaveAs4BitBMP (sourceImg As Long, outputFile$) '                                                                        Uložit nekomprimovaný BMP formát (4 bit)      save uncompressed BMP format (4 bit)
    '                                                                                                          Vstup: 8bitový obrázek, maximálně 16 unikátních barev.      Input: 8 bit image with max 16 colors
    '                                                                                                              Výstup: BMP soubor ve 4bitovém režimu (16 barev).      Output: 4 bit image with max 16 colors

    Type BMP4BitHeader
        signature As String * 2
        fileSize As Long
        reserved1 As Integer
        reserved2 As Integer
        dataOffset As Long
        infoHeaderSize As Long
        width As Long
        height As Long
        planes As Integer
        bitsPerPixel As Integer
        compression As Long
        imageSize As Long
        xPelsPerMeter As Long
        yPelsPerMeter As Long
        colorsUsed As Long
        importantColors As Long
        'colorTable(15)  AS _UNSIGNED LONG                                                                                          16 barev (4 bajty na jednu barvu)      Color palette contains 4 byte to 1 color
    End Type

    '===== Krok 1: Zjistíme rozměry obrázku =====      Determine image dimensions
    Dim W As Long, H As Long
    W = _Width(sourceImg)
    H = _Height(sourceImg)

    '===== Krok 2: Zjistíme, které paletové indexy se v obrázku používají =====      Determine which palette indices are used in the image
    Dim memSrc As _MEM
    memSrc = _MemImage(sourceImg)
    Dim totalPixels As Long
    totalPixels = memSrc.SIZE

    '        Pomocné pole – pro každý index 0..255 (0 = nepoužito, 1 = použit)      Helper array – for each index 0..255 (0 = unused, 1 = used)
    Dim used(0 To 255) As _Byte
    Dim i As Long
    Dim pixVal As _Unsigned _Byte
    For i = 0 To totalPixels - 1
        pixVal = _MemGet(memSrc, memSrc.OFFSET + i, _Unsigned _Byte)
        used(pixVal) = 1
    Next i

    '        Sestavíme finální paletu: pole finPal obsahuje všechny (použité) indexy      Build final palette: the finPal array contains all (used) indices
    Dim finPal(0 To 15) As _Unsigned _Byte
    Dim usedCount As Long: usedCount = 0
    Dim k As Long
    For k = 0 To 255
        If used(k) <> 0 Then
            finPal(usedCount) = k
            usedCount = usedCount + 1
            If usedCount > 16 Then
                Print "Input image contains more than 16 colors."
                End
            End If
        End If
    Next k

    '===== Krok 3:                                        Načteme barvy palety pomocí _PaletteColor      Load palette colors using _PaletteColor
    '              Vytvoříme pole ColorTable, kde pro každý ze 16 indexů bude uložena 32bitová barva.      Create ColorTable array, where for each of the 16 indices, a 32-bit color is stored.
    Dim ColorTable(0 To 15) As _Unsigned Long
    For i = 0 To 15
        If i < usedCount Then
            ColorTable(i) = _PaletteColor(finPal(i), sourceImg)
        Else
            ColorTable(i) = 0
        End If
    Next i

    '===== Krok 4:                                          Připravíme hlavičku BMP pro 4bitový obrázek      Prepare BMP header for 4-bit image
    '                        Definice typu BMP4BitHeader musí být již deklarována (viz váš původní kód).      The BMP4BitHeader type definition must already be declared (see your original code).
    Dim bmp As BMP4BitHeader
    bmp.signature = "BM"
    bmp.reserved1 = 0
    bmp.reserved2 = 0
    bmp.infoHeaderSize = 40
    bmp.width = W
    bmp.height = H
    bmp.planes = 1
    bmp.bitsPerPixel = 4
    bmp.compression = 0
    bmp.xPelsPerMeter = 0
    bmp.yPelsPerMeter = 0
    bmp.colorsUsed = 16
    bmp.importantColors = 0

    '                                V BMP se data ukládají jako řádky, kde každý pixel = 4 bity.      In BMP, data is stored in rows, with each pixel equal to 4 bits.
    '                    Počet bajtů na řádek = CEILING(W/2). Každý řádek se zarovnává na 4 bajty.      Number of bytes per row = CEILING(W/2). Each row is aligned to 4 bytes.
    Dim bytesPerRow As Long
    bytesPerRow = (W + 1) \ 2 ' (W+1)\2 dává počet bajtů (správně funguje pro lichou i sudou šířku)
    If (bytesPerRow Mod 4) <> 0 Then
        bytesPerRow = bytesPerRow + (4 - (bytesPerRow Mod 4))
    End If
    bmp.imageSize = bytesPerRow * H
    bmp.dataOffset = 14 + 40 + (16 * 4) '14 = FileHeader, 40 = InfoHeader, 64 = palette
    bmp.fileSize = bmp.dataOffset + bmp.imageSize

    '===== Krok 5:                      Převod pixelových dat z 8bitového formátu do 4bitového      Convert pixel data from 8-bit format to 4-bit format.
    '                    Vstupní obrázek obsahuje pro každý pixel jeden bajt – index do palety.      Input image contains one byte per pixel – palette index.
    '                V BMP 4bit formátu je každý bajt složen ze dvou 4bitových hodnot (nibble).      In 4-bit BMP format, each byte consists of two 4-bit values (nibbles).
    '                                        Proto potřebujeme vytvořit buffer pro pixel data.      Therefore we need to create a buffer for pixel data.
    Dim pixelData As String
    pixelData = String$(bmp.imageSize, Chr$(0))

    '                    Připravíme remapování – vstupní index › nový index (0 až usedCount-1)      Prepare remapping – input index to new index (0 to usedCount-1)
    Dim remap(0 To 255) As _Unsigned _Byte
    For i = 0 To 255
        remap(i) = 255 'inicializace (neplatná hodnota)
    Next i
    For i = 0 To usedCount - 1
        remap(finPal(i)) = i
    Next i

    '                                        Budeme číst obrázek po řádcích.      We will read the image row by row.
    'BMP ukládá řádky zdola nahoru, zatímco paměť obrázku je obvykle odshora.      BMP stores rows from bottom to top, while image memory is usually top-down.
    Dim outPos As Long: outPos = 0
    Dim rowStr As String
    Dim nibbleByte As _Unsigned _Byte
    Dim x As Long, y As Long
    For y = 0 To H - 1
        rowStr = String$(bytesPerRow, Chr$(0))
        Dim lineY As Long
        lineY = H - 1 - y '                          řádek v paměti obrázku      Image row in memory
        Dim rowOffset As Long
        rowOffset = lineY * W '                      protože 1 bajt na pixel
        nibbleByte = 0
        For x = 0 To W - 1
            Dim srcIndex As Long
            srcIndex = rowOffset + x
            Dim pix8 As _Unsigned _Byte
            pix8 = _MemGet(memSrc, memSrc.OFFSET + srcIndex, _Unsigned _Byte)
            '                        Přemapování: získáme nový 4bitový index      Remapping: obtain new 4-bit index
            Dim newIndex As _Unsigned _Byte
            newIndex = remap(pix8)
            If (x Mod 2) = 0 Then
                'Horní nibble      Upper nibble
                nibbleByte = _ShL(newIndex, 4)
            Else
                'Dolní nibble      Lower nibble
                nibbleByte = nibbleByte Or (newIndex And &HF)
                '                    Uložíme bajt do řádku (pozice: (x\2)+1)      Save byte into row (position: (x\2)+1)
                Mid$(rowStr, (x \ 2) + 1, 1) = Chr$(nibbleByte)
                nibbleByte = 0
            End If
        Next x
        '                      Pokud je šířka lichá, uložíme poslední nibble:      If the width is odd, store the last nibble:
        If (W Mod 2) = 1 Then
            Mid$(rowStr, (W \ 2) + 1, 1) = Chr$(nibbleByte)
        End If
        '                                      Zkopírujeme řádek do pixelData      Copy the row into pixelData.
        Mid$(pixelData, outPos + 1, Len(rowStr)) = rowStr
        outPos = outPos + bytesPerRow
    Next y

    '===== Krok 6:                                          Zápis BMP souboru      Write BMP file.
    If _FileExists(outputFile$) Then Kill outputFile$
    Open outputFile$ For Binary As #1
    'FileHeader (14 bajtů)      FileHeader (14 bytes)
    Put #1, , bmp.signature
    Put #1, , bmp.fileSize
    Put #1, , bmp.reserved1
    Put #1, , bmp.reserved2
    Put #1, , bmp.dataOffset

    'InfoHeader (40 bajtů)      InfoHeader (40 bytes)
    Put #1, , bmp.infoHeaderSize
    Put #1, , bmp.width
    Put #1, , bmp.height
    Put #1, , bmp.planes
    Put #1, , bmp.bitsPerPixel
    Put #1, , bmp.compression
    Put #1, , bmp.imageSize
    Put #1, , bmp.xPelsPerMeter
    Put #1, , bmp.yPelsPerMeter
    Put #1, , bmp.colorsUsed
    Put #1, , bmp.importantColors

    'Paleta: 16 barev, každý 4 bajty      Palette: 16 colors, each 4 bytes
    For i = 0 To 15
        Put #1, , ColorTable(i)
    Next i

    'Pixelová data      Pixel data
    Put #1, , pixelData
    Close #1

    'Uvolnění paměťového bloku zdrojového obrázku (nebo jej ponechte, pokud se dále používá)      Release the memory block of the source image (or keep it if used further)
    _MemFree memSrc
End Sub

Function ClrsCnt (handle As Long)
    'Vrátí počet unikátních barev v obrázku      Returns the count of unique colors in the image
    Dim As _Unsigned _Byte r, g, b
    Dim As _MEM m
    Dim As Long a, Clrscn
    m = _MemImage(handle)

    If _PixelSize(handle) > 1 Then
        Dim c(255, 255, 255) As _Unsigned _Byte
        Do Until a = m.SIZE
            _MemGet m, m.OFFSET + a, b
            _MemGet m, m.OFFSET + a + 1, g
            _MemGet m, m.OFFSET + a + 2, r
            a = a + 4
            If c(r, g, b) = 0 Then
                Clrscn = Clrscn + 1
                c(r, g, b) = 1
            End If
        Loop
        ClrsCnt = Clrscn
    Else
        Dim d(255) As _Byte
        Do Until a = m.SIZE
            index = _MemGet(m, m.OFFSET + a, _Unsigned _Byte)
            If d(index) = 0 Then
                d(index) = 1
                Clrscn = Clrscn + 1
            End If
            a = a + 1
        Loop
        ClrsCnt = Clrscn
    End If
End Function

Well, here's the second program. It creates an RLE - compressed 4-bit BMP file with a maximum of 16 colors. Since this format is not supported by the _LoadImage function, the program also includes a loader that loads and displays this format. The output file remains on disk, so you can check its compatibility, for example, in a photo viewer. Note the significant difference in the size of the output file compared to the previous program.

Above, I mentioned that there was a problem with the program that I solved/did not solve. If RLE encounters a point that has a different color than the points around it, it should switch to the so-called absolute encoding. The problem is that this implementation caused me to lose a part of image. Simply, after switching from RLE to absolute encoding, the rest of the image remained black. For this reason, I would like to point out that the program runs only in RLE mode, so an image that has poor content, unsuitable for RLE (that is, the image has few single-color areas and contains many small dots), the resulting size can paradoxically be much larger than in the uncompressed format. But then again, there is an option, if we know that the uncompressed version has a size of approximately (width * height)/2, then compare this number with the LOF of the resulting BMP and choose the saving method accordingly. When the problem is solved, I will update the program here and write a warning.

Code: (Select All)

'BMP - RLE4 (16 colors) for qb64pe in cooperation. Create image. Save as RLE format. Load it. Show it.

Const SCR_WIDTH = 800 '                            Nastavení šířky obrazovky                    Set screen width
Const SCR_HEIGHT = 600 '                            Nastavení výšky obrazovky                    Set screen height
Const DEBUG_MODE = 0 'allow = 1                    Povolení ladicího režimu                      Enable debug mode (now is disabled)

Dim Shared debugFileNum As Integer '                Sdílená proměnná pro číslo logovacího souboru Shared variable for debug file number
If DEBUG_MODE Then '                                Pokud je ladicí režim zapnutý                If debug mode is enabled
    debugFileNum = FreeFile '                      Získání volného čísla souboru                Get free file number
    Open "debug.log" For Output As #debugFileNum '  Otevření logovacího souboru pro výstup        Open debug.log for output
    Print #debugFileNum, "=== Debug Log - Start ===" ' Zápis začátku logu                        Print debug log header
End If '                                              Konec ladicí podmínky                      End debug mode block

Dim img16 As Long '                                Deklarace proměnné pro obrázek                Declare variable for image
img16 = _NewImage(SCR_WIDTH, SCR_HEIGHT, 256) '    Vytvoření nového obrázku s 256 barvami        Create a new image with 256 colors
_Dest img16 '                                      Nastavení cílového obrázku  '                Set destination image
Cls , 4 '                                          Vyčištění obrazovky s barvou 4                Clear screen with color 4

Locate 10, 1 '                                      Nastavení pozice kurzoru                      Set cursor position
For f = 0 To 15 '                                  Smyčka přes 16 barev                          Loop over 16 colors
    Line (0 + 20 * f, 0 + 20 * f)-(800 - 20 * f, 600 - 20 * f), f, BF
Next '                                              Konec smyčky                                  End loop
_PrintMode _KeepBackground '                        Nastavení režimu tisku tak, aby se zachovalo pozadí  Set print mode to keep background
Color 0 '                                          Nastavení barvy textu na 0                    Set text color to 0
Print '                                            Vytisknutí prázdného řádku                    Print blank line
Print "                Hi QB64PE Team. I am your first RLE - compressed 16 colors bitmap!"
Print "                  Because _LoadImage can't load my format, is used own loader!"
_Dest 0
Print "Saving image to file 'testRLE4.bmp'"
Sleep 2
SaveAs4BitRLEBMP img16, "testRLE4.bmp"
Dim loadedImg As Long
loadedImg = _LoadImage("testRLE4.bmp", 256) ' Load image using built-in _LoadImage (always failure, but you can test bmp file with windows photo viewer)
Screen _NewImage(800, 600, 32)
Print "Hm... Returned by _LoadImage: "; loadedImg
Sleep 2
image& = Load4BitRLEBMP("testRLE4.bmp") '            Načtení obrázku pomocí vlastního loaderu    Load image using custom loader
_PutImage , image& '                                Zobrazení načteného obrázku                Display the loaded image
Print "So use own loader..." '
Print "Image width: "; _Width(image&); "Image height: "; _Height(image&); "Image size: "; GetSze("testRLE4.bmp"); "B Image PixelSize:"; _PixelSize(image&) ' Výpis informací o obrázku  ' Print image details
Sleep

If DEBUG_MODE Then
    Print #debugFileNum, "=== Debug Log - Konec ===" '    Výpis konce logu                          Print debug log end
    Close #debugFileNum '                                Zavření logovacího souboru                Close debug file
End If '                                                  Konec ladicí podmínky                      End debug mode block

' ============================================================
' Typ BMP4BitHeader  ' BMP header type definition
' ============================================================
Type BMP4BitHeader '                                      Definice struktury BMP hlavičky          Define BMP header structure
    signature As String * 2 '                              Podpis BMP souboru ("BM")                BMP file signature ("BM")
    fileSize As Long '                                    Celková velikost souboru                  Total file size
    reserved1 As Integer '                                Rezervované pole                          Reserved field 1
    reserved2 As Integer '                                Rezervované pole                          Reserved field 2
    dataOffset As Long '                                  Offset, kde začínají obrazová data        Data offset from file start
    infoHeaderSize As Long '                              Velikost informační hlavičky              Info header size
    width As Long '                                        Šířka obrázku                            Image width
    height As Long '                                      Výška obrázku                            Image height
    planes As Integer '                                    Počet rovin (vždy 1)                      Number of planes (always 1)
    bitsPerPixel As Integer '                              Bity na pixel                            Bits per pixel
    compression As Long '                                  Typ komprese (pro RLE4: 2)                Compression type (RLE4: 2)
    imageSize As Long '                                    Velikost obrazových dat                  Image data size
    xPelsPerMeter As Long '                                Horizontální rozlišení                    Horizontal resolution
    yPelsPerMeter As Long '                                Vertikální rozlišení                      Vertical resolution
    colorsUsed As Long '                                  Počet použitých barev                    Colors used
    importantColors As Long '                              Počet důležitých barev                    Important colors
End Type '                                                Konec definice BMP4BitHeader              End BMP4BitHeader definition

' ============================================================
' Funkce: GetSze
' ============================================================
Function GetSze (file As String) '                        Vrací velikost souboru v bajtech          Returns file size in bytes
    ff = FreeFile
    Open file For Binary As ff
    GetSze = LOF(ff)
    Close ff '
End Function '

' ============================================================
' SUB: SaveAs4BitRLEBMP  ' Sub: SaveAs4BitRLEBMP
' ============================================================
Sub SaveAs4BitRLEBMP (sourceImg As Long, outputFile$) '    Uloží obrázek ve formátu 4-bit BMP s RLE4 kompresí  Save image in 4-bit BMP with RLE4 compression
    Dim w As Long, h As Long '                              Deklarace proměnných pro rozměry obrázku            Declare image dimension variables
    w = _Width(sourceImg) '                                Získání šířky obrázku                                Get image width
    h = _Height(sourceImg) '                                Získání výšky obrázku                                Get image height

    Dim totalPixels As Long '                              Celkový počet pixelů                                Total number of pixels
    totalPixels = w * h '                                  Výpočet celkového počtu pixelů                      Calculate total pixels

    Dim memSrc As _MEM '                                    Paměťová oblast zdrojového obrázku                  Source image memory block
    memSrc = _MemImage(sourceImg) '                        Získání paměťové oblasti                            Get image memory block

    Dim used(0 To 255) As _Unsigned _Byte '                Pole pro použití barev                              Array to track used colors
    Dim i As Long
    For i = 0 To 255 '                                      Inicializace pole pro 256 barev                      Initialize used array for 256 colors
        used(i) = 0 '                                      Nastavení hodnoty na 0                              Set to 0
    Next i
    Dim tVal As _Unsigned _Byte
    For i = 0 To totalPixels - 1 '                          Pro každý pixel v obrázku                            For each pixel in image
        tVal = _MemGet(memSrc, memSrc.OFFSET + i, _Unsigned _Byte) ' Načtení hodnoty pixelu                      Get pixel value
        used(tVal) = 1 '                                    Označení, že barva byla použita                    Mark color as used
    Next i

    Dim finPal(0 To 15) As _Unsigned _Byte '                Finální paleta (max 16 barev)                      Final palette (max 16 colors)
    Dim usedCount As Long: usedCount = 0 '                  Počet použitých barev                              Count of used colors
    Dim c As Long
    For c = 0 To 255 '                                      Pro každou barvu                                    For each color
        If used(c) <> 0 Then '                              Pokud je barva použita                              If color is used
            finPal(usedCount) = c '                          Uložení barvy do finální palety                    Save color to final palette
            usedCount = usedCount + 1 '                      Zvýšení počtu použitých barev                      Increment used color count
            If usedCount > 16 Then '                        Pokud je více než 16 barev                          If more than 16 colors
                Print "Input image has more than 16 colors!" ' Chybová hláška                                    Error message
                End ' Ukončení programu  ' End program
            End If
        End If
    Next c

    Dim remap(0 To 255) As _Unsigned _Byte '          Remapovací pole pro změnu indexů barev                      Remapping array for color indices
    For i = 0 To 255
        remap(i) = 255 '                              Inicializace remapovacího pole                              Initialize remap array
    Next i
    For i = 0 To usedCount - 1 '                      Pro každou použitou barvu                                  For each used color
        remap(finPal(i)) = i '                        Přiřazení nového indexu                                    Assign new index
    Next i

    Dim ColorTable(0 To 15) As _Unsigned Long '      Tabulka barev pro BMP                                      Color table for BMP
    For i = 0 To 15
        If i < usedCount Then
            ColorTable(i) = _PaletteColor(finPal(i), sourceImg) ' Načtení barvy z palety zdroje                  Get color from source palette
        Else
            ColorTable(i) = 0 '                                  Nepoužité barvy nastavit na 0                  Set unused colors to 0
        End If
    Next i

    Dim bmp As BMP4BitHeader '                                  Deklarace struktury BMP hlavičky                  Declare BMP header structure
    bmp.signature = "BM" '                                      Nastavení podpisu BMP                            Set BMP signature
    bmp.reserved1 = 0 '                                        Rezervované pole                                  Reserved field 1
    bmp.reserved2 = 0 '                                        Rezervované pole                                  Reserved field 2
    bmp.infoHeaderSize = 40 '                                  Velikost informační hlavičky                      Info header size
    bmp.width = w '                                            Šířka obrázku                                    Image width
    bmp.height = h '                                            Výška obrázku                                    Image height
    bmp.planes = 1 '                                            Počet rovin                                      Number of planes
    bmp.bitsPerPixel = 4 '                                      Bity na pixel                                    Bits per pixel
    bmp.compression = 2 '                                      RLE4 komprese                                    RLE4 compression
    bmp.xPelsPerMeter = 0 '                                    Horizontální rozlišení                            Horizontal resolution
    bmp.yPelsPerMeter = 0 '                                    Vertikální rozlišení                              Vertical resolution
    bmp.colorsUsed = 16 '                                      Počet barev v paletě                              Number of colors used
    bmp.importantColors = 0 '                                  Všechny barvy jsou důležité                      All colors are important

    Dim rowPitch As Long '                                      Výpočet délky řádku v bajtech                    Calculate row pitch in bytes
    rowPitch = ((w + 3) \ 4) * 4 '                              Zarovnání řádku na 4 bajty                        Align row to 4 bytes

    Dim indexArray(0 To totalPixels - 1) As _Unsigned _Byte '  Pole indexů pixelů                                Array for pixel indices
    Dim pixPos As Long: pixPos = 0 '                            Počáteční pozice v indexArray                    Starting index position
    Dim y As Long, x As Long
    For y = 0 To h - 1 '                                        Smyčka přes všechny řádky                        Loop through all rows
        Dim srcY As Long
        srcY = (h - 1) - y '                                    BMP řádky jsou uloženy odspodu nahoru            BMP rows are stored bottom-up
        Dim rowOff As Long
        rowOff = srcY * rowPitch '                              Výpočet offsetu řádku v paměti                    Calculate row offset in memory
        For x = 0 To w - 1 '                                    Smyčka přes všechny sloupce                      Loop through all columns
            Dim p8 As _Unsigned _Byte
            p8 = _MemGet(memSrc, memSrc.OFFSET + rowOff + x, _Unsigned _Byte) ' Načtení pixelu ze zdrojového obrázku  Get pixel from source image
            indexArray(pixPos) = remap(p8) '                                    Remapování původního indexu na nový    Remap original pixel index
            pixPos = pixPos + 1 '                                              Posun v indexArray                    Increment index position
        Next x
    Next y

    Dim rleData As String: rleData = "" '                        Inicializace řetězce pro RLE data                  Initialize string for RLE data
    Dim rowOfs As Long: rowOfs = 0 '                            Offset pro každý řádek v indexArray                Row offset in indexArray
    For y = 1 To h '                                            Smyčka přes každý řádek                            Loop for each row
        Dim rowStr As String
        rowStr = CompressRowRLE4(indexArray(), rowOfs, w) '      Komprimace řádku do RLE4                          Compress row using RLE4
        rleData = rleData + rowStr '                            Přidání komprimovaného řádku do výsledného řetězce Append compressed row data
        rleData = rleData + Chr$(0) + Chr$(0) '                  Zápis konec řádku (0,0)                            Write end-of-line marker (0,0)
        rowOfs = rowOfs + w '                                    Posun na další řádek v indexArray                  Move to next row in index array
    Next y
    rleData = rleData + Chr$(0) + Chr$(1) '                      Zápis ukončovacího příkazu (0,1)                  Write end-of-bitmap marker (0,1)

    bmp.imageSize = Len(rleData) '                              Nastavení velikosti obrazových dat                Set image data size
    bmp.dataOffset = 14 + 40 + (16 * 4) '                        Výpočet offsetu dat (hlavička + paleta)            Calculate data offset (header + palette)
    bmp.fileSize = bmp.dataOffset + bmp.imageSize '              Výpočet celkové velikosti souboru                  Calculate total file size

    _MemFree memSrc '                                            Uvolnění paměti zdrojového obrázku                Free memory of source image

    If _FileExists(outputFile$) Then Kill outputFile$ '          Smazání existujícího souboru, pokud existuje      Delete existing file if any
    Dim fileNum As Integer: fileNum = FreeFile '                Získání volného čísla souboru pro zápis            Get free file number for output
    Open outputFile$ For Binary As #fileNum '                    Otevření souboru pro binární zápis                Open output file for binary writing
    Put #fileNum, , bmp.signature '                              Zápis podpisu BMP do souboru                      Write BMP signature to file
    Put #fileNum, , bmp.fileSize '                              Zápis celkové velikosti souboru                    Write total file size
    Put #fileNum, , bmp.reserved1 '                              Zápis rezervovaných bajtů                          Write reserved field 1
    Put #fileNum, , bmp.reserved2 '                              Zápis rezervovaných bajtů                          Write reserved field 2
    Put #fileNum, , bmp.dataOffset '                            Zápis offsetu dat                                  Write data offset
    Put #fileNum, , bmp.infoHeaderSize '                        Zápis velikosti informační hlavičky                Write info header size
    Put #fileNum, , bmp.width '                                  Zápis šířky obrázku                                Write image width
    Put #fileNum, , bmp.height '                                Zápis výšky obrázku                                Write image height
    Put #fileNum, , bmp.planes '                                Zápis počtu rovin                                  Write number of planes
    Put #fileNum, , bmp.bitsPerPixel '                          Zápis bitů na pixel                                Write bits per pixel
    Put #fileNum, , bmp.compression '                            Zápis typu komprese                                Write compression type
    Put #fileNum, , bmp.imageSize '                              Zápis velikosti obrazových dat                    Write image data size
    Put #fileNum, , bmp.xPelsPerMeter '                          Zápis horizontálního rozlišení                    Write horizontal resolution
    Put #fileNum, , bmp.yPelsPerMeter '                          Zápis vertikálního rozlišení                      Write vertical resolution
    Put #fileNum, , bmp.colorsUsed '                            Zápis počtu použitých barev                        Write number of colors used
    Put #fileNum, , bmp.importantColors '                        Zápis počtu důležitých barev                      Write number of important colors
    For i = 0 To 15 '                                            Smyčka pro zápis palety                            Loop to write palette
        Put #fileNum, , ColorTable(i) '                          Zápis barvy z palety                              Write palette color
    Next i
    Put #fileNum, , rleData '                                    Zápis RLE4 dat                                    Write RLE4 compressed data
    Close #fileNum '                                            Zavření souboru                                    Close file
End Sub

' ============================================================  ' ============================================================
' Funkce: CompressRowRLE4 – s okamžitým flushováním, když runLen=1  ' Function: CompressRowRLE4 – immediate flush when runLen=1
' ============================================================  ' ============================================================
Function CompressRowRLE4$ (rowNibbles() As _Unsigned _Byte, start As Long, rowWidth As Long)
    Dim result As String: result = "" '                                                          Inicializace výsledného řetězce                Initialize result string
    Dim maxIndex As Long: maxIndex = UBound(rowNibbles) '                                        Zjištění maximálního indexu v poli              Get maximum index of array
    Dim i As Long: i = 0 '                                                                      Počáteční index  '                            Initialize index to 0
    If DEBUG_MODE Then Print #debugFileNum, "=== Zpracování řádku, start=", start, " rowWidth=", rowWidth ' Debug: start row processing          Debug: row processing start
    Do While i < rowWidth '                                                                                Smyčka přes pixely v řádku          Loop through pixels in row
        If (start + i) > maxIndex Then Exit Do '                                                        Pokud jsme mimo pole, ukončíme          Exit if index exceeds array bounds
        Dim currentVal As _Unsigned _Byte: currentVal = rowNibbles(start + i) '                          Načtení aktuální hodnoty nibble        Get current nibble value
        If DEBUG_MODE Then Print #debugFileNum, "i=", i, " currentVal=", currentVal '                    Debug: tisk aktuální hodnoty            Debug: print current value

        Dim runLen As Long: runLen = 1 '                                                                Inicializace délky opakování            Initialize run length
        Dim j As Long: j = i + 1 '                                                                  Nastavení dalšího indexu pro porovnání      Set index for comparison
        Do While (j < rowWidth) And ((start + j) <= maxIndex)
            If rowNibbles(start + j) <> currentVal Then Exit Do '                                    Pokud se hodnota liší, ukončíme smyčku      Exit if nibble differs
            runLen = runLen + 1 '                                                                    Zvýšení délky opakování                    Increment run length
            If runLen >= 255 Then Exit Do '                                                          Limit délky opakování na 255                Limit run length to 255
            j = j + 1 ' Posun indexu  ' Increment index
        Loop
        If DEBUG_MODE Then Print #debugFileNum, "i=", i, " Detekován run s currentVal=", currentVal, " runLen=", runLen ' Debug: tisk zjištěného runu  Debug: print run detected

        ' Zpracování kódovaného (run) bloku
        If runLen >= 1 Then
            Dim remain As Long: remain = runLen '                                                            N astavení zbývající délky          Set remaining run length
            Do While remain > 255
                result = result + Chr$(255) + Chr$(_ShL(currentVal, 4) Or currentVal) '                  Zápis bloku s 255 opakováními          Write block of 255 repeats
                If DEBUG_MODE Then Print #debugFileNum, "Zapsán run blok: délka=255, currentVal=", currentVal ' Debug: tisk zapsaného bloku      Debug: print block written
                remain = remain - 255 ' Odečtení 255 opakování  ' Subtract 255 from run length
            Loop
            result = result + Chr$(remain) + Chr$(_ShL(currentVal, 4) Or currentVal) '                          Zápis zbývajícího run bloku        Write remaining run block
            If DEBUG_MODE Then Print #debugFileNum, "Zapsán run blok: délka=", remain, " currentVal=", currentVal ' Debug: tisk posledního bloku  Debug: print last block
            i = i + runLen '                                                                                        Posun indexu o délku runu      Increment index by run length
        End If
    Loop
    If DEBUG_MODE Then Print #debugFileNum, "=== Konec zpracování řádku ===" '                                    Debug: konec zpracování řádku  Debug: end of row processing
    CompressRowRLE4 = result '                                                                                    Vrácení komprimovaného řádku    Return compressed row string
End Function

' ============================================================
' Funkce: FlushAbsoluteBlock
' ============================================================
Function FlushAbsoluteBlock$ (absData As String, absCount As Long)
    Dim ut As String: ut = "" '                                                                              Inicializace výstupního řetězce      Initialize output string
    ut = ut + Chr$(0) + Chr$(absCount) '                                                              Zápis značky absolutního bloku a délky      Write absolute block marker and length
    Dim tmp As String: tmp = "" '                                                                      Dočasný řetězec pro kombinaci nibblů        Temporary string for combined nibbles
    Dim n As Long: n = 1 '                                                                            Počáteční index                            Initialize index to 1
    Do While n <= Len(absData) '                                                                      Smyčka přes absolutní data                  Loop through absolute data
        Dim nib1 As _Unsigned _Byte: nib1 = Asc(Mid$(absData, n, 1)) '                                Načtení prvního nibble                      Get first nibble
        Dim nib2 As _Unsigned _Byte: nib2 = 0 '                                                        Inicializace druhého nibble                Initialize second nibble
        If (n + 1) <= Len(absData) Then nib2 = Asc(Mid$(absData, n + 1, 1)) '                          Načtení druhého nibble, pokud existuje      Get second nibble if available
        Dim combined As _Unsigned _Byte: combined = _ShL((nib1 And &HF), 4) Or (nib2 And &HF) '        Kombinace dvou nibblů do jednoho bajtu      Combine two nibbles into one byte
        tmp = tmp + Chr$(combined) '                                                        Přidání kombinovaného bajtu do dočasného řetězce      Append combined byte to temporary string
        n = n + 2 '                                                                                    Posun indexu o 2                            Increment index by 2
    Loop
    ut = ut + tmp '                                                                        Připojení kombinovaných bajtů k výstupnímu řetězci    Append combined bytes to output
    Dim byteCount As Long: byteCount = (absCount + 1) \ 2 '                                            Výpočet počtu bajtů v absolutním bloku    Calculate number of bytes in absolute block
    If (byteCount Mod 2) = 1 Then ut = ut + Chr$(0) '                                      Přidání padovacího bajtu, pokud je počet bajtů lichý    Add padding byte if odd number of bytes
    FlushAbsoluteBlock = ut '                                                                              Vrácení výsledného absolutního bloku    Return absolute block string
End Function

' ============================================================
' Funkce: Load4BitRLEBMP
' ============================================================
' Načte BMP soubor s RLE4 kompresí, který byl vytvořen pomocí našeho SaveAs4BitRLEBMP.
' POZN.: Tento loader používá stejnou “podmínku”, jakou má náš save routine – tedy vždy, když je bajt count nenulový,
'        je to kódovaný blok (run block), i kdyby count=1, což není úplně podle standardní specifikace - ale funguje správnš.

' Loads a BMP file with RLE4 compression produced by our save routine.
' NOTE: This loader uses the same condition as our save routine – if the count byte is nonzero,
'      it treats the block as a run block (even if count=1), which is non-standard - but works correctly.

Function Load4BitRLEBMP& (fileName$)
    ' Otevře BMP soubor, načte hlavičku, paletu a RLE4 data a dekóduje je do nového obrázku.
    ' Opens the BMP file, reads header, palette, and RLE4 data, and decodes them into a new image.
    Dim fileNum As Integer: fileNum = FreeFile '                                                            Získání volného čísla souboru      Get free file number
    Open fileName$ For Binary As #fileNum '                                                        Otevření BMP souboru pro binární čtení      Open BMP file for binary reading

    ' Načtení hlavičky (14 bajtů)
    Dim signature As String * 2 '                                                                                                BMP podpis    BMP signature
    Dim fileSize As Long, reserved1 As Integer, reserved2 As Integer, dataOffset As Long '                                  Hlavičková data    Header data
    Get #fileNum, , signature '                                                                                              Čtení podpisu    Read signature
    If signature <> "BM" Then '                                                                                            Kontrola podpisu    Verify signature
        Print "Není to BMP soubor!" '                                                                                        Chybová zpráva    Error: Not a BMP file
        Close #fileNum '                                                                                                    Zavření souboru    Close file
        Load4BitRLEBMP = 0 '                                                                                          Vrácení 0 jako chyba    Return 0 as error
        Exit Function
    End If
    Get #fileNum, , fileSize '                                                                              Čtení celkové velikosti souboru    Read total file size
    Get #fileNum, , reserved1 '                                                                                    Čtení rezervovaných bajtů    Read reserved field 1
    Get #fileNum, , reserved2 '                                                                                    Čtení rezervovaných bajtů    Read reserved field 2
    Get #fileNum, , dataOffset '                                                                                          Čtení offsetu dat    Read data offset

    ' Načtení BITMAPINFOHEADER (40 bajtů)
    Dim infoHeaderSize As Long, width As Long, height As Long '                                                        Data hlavičky obrázku    Image header data
    Dim planes As Integer, bitsPerPixel As Integer, compression As Long '                                              Další hlavičková data    Additional header info
    Dim imageSize As Long, xPelsPerMeter As Long, yPelsPerMeter As Long '                                          Velikost dat a rozlišení    Image size and resolution
    Dim colorsUsed As Long, importantColors As Long '                                                    Počet použitých a důležitých barev    Colors used and important colors
    Get #fileNum, , infoHeaderSize '                                                                    Čtení velikosti informační hlavičky    Read info header size
    Get #fileNum, , width '                                                                                              Čtení šířky obrázku    Read image width
    Get #fileNum, , height '                                                                                            Čtení výšky obrázku    Read image height
    Get #fileNum, , planes '                                                                                              Čtení počtu rovin    Read number of planes
    Get #fileNum, , bitsPerPixel '                                                                                      Čtení bitů na pixel    Read bits per pixel
    Get #fileNum, , compression '                                                                                        Čtení typu komprese    Read compression type
    Get #fileNum, , imageSize '                                                                              Čtení velikosti obrazových dat    Read image data size
    Get #fileNum, , xPelsPerMeter '                                                                          Čtení horizontálního rozlišení    Read horizontal resolution
    Get #fileNum, , yPelsPerMeter '                                                                            Čtení vertikálního rozlišení    Read vertical resolution
    Get #fileNum, , colorsUsed '                                                                                Čtení počtu použitých barev    Read number of colors used
    Get #fileNum, , importantColors '                                                                          Čtení počtu důležitých barev    Read number of important colors

    If bitsPerPixel <> 4 Then '                                                                          Kontrola, zda se jedná o 4-bit BMP    Verify image is 4-bit
        Print "Nejedná se o 4-bit BMP!" '                                                                                    Chybová zpráva    Error: Not a 4-bit BMP
        Close #fileNum '                                                                                                    Zavření souboru    Close file
        Load4BitRLEBMP = 0 '                                                                                            Vrácení 0 jako chybu    Return 0 as error
        Exit Function
    End If

    ' Načtení palety – 16 barev, každý 4 bajty (B, G, R, 0)
    Dim pal(0 To 15) As _Unsigned Long '                                                                        Deklarace palety pro 16 barev  Declare palette for 16 colors
    Dim i As Long
    For i = 0 To 15 '                                                                                                    Smyčka pro 16 barev    Loop for 16 colors
        Dim blue As _Unsigned _Byte, green As _Unsigned _Byte, red As _Unsigned _Byte, reserved As _Unsigned _Byte
        Get #fileNum, , blue '                                                                                          Načtení modré složky    Read blue component
        Get #fileNum, , green '                                                                                        Načtení zelené složky    Read green component
        Get #fileNum, , red '                                                                                          Načtení červené složky    Read red component
        Get #fileNum, , reserved '                                                                                Načtení rezervovaného bajtu    Read reserved byte
        pal(i) = red * 65536 + green * 256 + blue '                                                    Sestavení barvy ve formátu &H00RRGGBB    Construct color as &H00RRGGBB
    Next i

    '                                                                                        Přesunutí čtecí pozice na začátek obrazových dat  Seek to start of image data
    Seek #fileNum, dataOffset + 1 '                                                                Použití dataOffset + 1 (kvůli 1-indexování)  Use dataOffset + 1 for 1-indexing

    '                                                                                                                          Načtení RLE dat  Read RLE data
    Dim rleData As String
    rleData = Space$(imageSize) '                                                                            Inicializace řetězce pro RLE data  Initialize RLE data string
    Get #fileNum, , rleData '                                                                                      Načtení RLE dat do řetězce  Read RLE data
    Close #fileNum '                                                                                                          Zavření souboru  Close file

    '                                                                                        Vytvoření nového obrázku s rozměry width x height  Create new image with dimensions from header
    Dim img As Long
    img = _NewImage(width, height, 256) '                                                                      Vytvoření 256barevného obrázku  Create a 256-color image
    For i = 0 To 15 '                                                                                              Smyčka pro nastavení palety  Loop to set palette
        _PaletteColor i, pal(i), img '                                                                                Nastavení palety obrázku  Set image palette color
    Next i

    '                                                                                                  Získání paměťové oblasti nového obrázku  Get memory block for image
    Dim memImg As _MEM
    memImg = _MemImage(img)

    '                                                                                                          Výpočet řádkové délky v bajtech  Calculate row pitch in bytes
    Dim rowPitch As Long
    rowPitch = ((width + 3) \ 4) * 4 '                                                                              Zarovnání řádků na 4 bajty  Align rows to 4 bytes

    '                                                                                      Dekódování RLE dat – BMP ukládá řádky odspodu nahoru  Decode RLE data – BMP rows stored bottom-up
    Dim curRow As Long: curRow = 0 '                                                                                            Počáteční řádek  Initialize current row to 0
    Dim curCol As Long: curCol = 0 '                                                                                          Počáteční sloupec  Initialize current column to 0
    Dim poss As Long: poss = 1 '                                                                                  Počáteční pozice v RLE datech  Start position in RLE data
    Dim dataLen As Long: dataLen = Len(rleData) '                                                                        Celková délka RLE dat  Total length of RLE data

    Do While poss <= dataLen '                                                                                            Smyčka přes RLE data  Loop through RLE data
        Dim countByte As _Unsigned _Byte, dataByte As _Unsigned _Byte
        countByte = Asc(Mid$(rleData, poss, 1)) '                                                                          Načtení count bajtu  Read count byte
        poss = poss + 1 '                                                                                                        Posun o 1 bajt  Increment position by 1
        If poss > dataLen Then Exit Do
        dataByte = Asc(Mid$(rleData, poss, 1)) '                                                                        Načtení datového bajtu  Read data byte
        poss = poss + 1 '                                                                                                        Posun o 1 bajt  Increment position by 1

        If countByte = 0 Then '                                                                                              Speciální příkazy    Special commands
            If dataByte = 0 Then '                                                                                                  Konec řádku    End of line
                curRow = curRow + 1 '                                                                                            Zvýšení řádku    Increment row
                curCol = 0 '                                                                                                      Reset sloupce    Reset column
            ElseIf dataByte = 1 Then '                                                                                            Konec bitmapy    End of bitmap
                Exit Do '                                                                                                  Ukončení dekódování    Exit decoding loop
            ElseIf dataByte = 2 Then '                                                                                    Delta příkaz (posun)    Delta command (shift)
                If poss + 1 > dataLen Then Exit Do
                Dim dx As _Unsigned _Byte, dy As _Unsigned _Byte
                dx = Asc(Mid$(rleData, poss, 1)) '                                                                            Delta – posun v x    Delta shift in x
                dy = Asc(Mid$(rleData, poss + 1, 1)) '                                                                        Delta – posun v y    Delta shift in y
                poss = poss + 2 '                                                                                              Posun o 2 bajty    Increment position by 2
                curCol = curCol + dx '                                                                                      Aktualizace sloupce    Update column
                curRow = curRow + dy '                                                                                        Aktualizace řádku    Update row
            Else '                                                                                                              Absolutní blok    Absolute block
                Dim absCount As Long: absCount = dataByte '                                                    Počet nibble v absolutním bloku    Number of nibbles in absolute block
                Dim byteCount As Long: byteCount = (absCount + 1) \ 2 '                                          Počet bajtů v absolutním bloku    Number of bytes in absolute block
                Dim absData As String
                absData = Mid$(rleData, poss, byteCount) '                                                              Načtení absolutních dat    Read absolute block data
                poss = poss + byteCount '                                                                              Posun za absolutní data    Move position past absolute data
                Dim k As Long
                For k = 1 To absCount '                                                                  Smyčka přes nibble v absolutním bloku    Loop through each nibble in absolute block
                    Dim currentNibble As _Unsigned _Byte
                    Dim currentByte As _Unsigned _Byte: currentByte = Asc(Mid$(absData, ((k + 1) \ 2), 1))
                    If (k Mod 2) = 1 Then
                        currentNibble = currentByte \ 16 '                                                                          Horní nibble    Upper nibble
                    Else
                        currentNibble = currentByte And &HF '                                                                      Dolní nibble    Lower nibble
                    End If
                    _MemPut memImg, memImg.OFFSET + (((height - curRow - 1) * rowPitch) + curCol), currentNibble As _UNSIGNED _BYTE ' Zápis pixelu    Write pixel to image memory
                    curCol = curCol + 1 '                                                                                            Posun sloupce    Increment column
                    If curCol >= width Then Exit For '                                                          Pokud konec řádku, ukončit smyčku    Exit loop if end of row
                Next k
            End If
        Else '                                                                                                            Kódovaný režim (run mode)    Encoded (run) mode
            Dim j As Long
            For j = 1 To countByte '                                                                                    Smyčka přes počet opakování    Loop for count repetitions
                Dim pixel As _Unsigned _Byte
                If (j Mod 2) = 1 Then
                    pixel = dataByte \ 16 '                                                                                            Horní nibble    Upper nibble
                Else
                    pixel = dataByte And &HF '                                                                                        Dolní nibble    Lower nibble
                End If
                _MemPut memImg, memImg.OFFSET + (((height - curRow - 1) * rowPitch) + curCol), pixel As _UNSIGNED _BYTE ' Zápis pixelu do obrázku      Write pixel to image memory
                curCol = curCol + 1 '                                                                                              Posun sloupce      Increment column
                If curCol >= width Then Exit For '                                                      Ukončení smyčky při dosažení konce řádku      Exit loop if end of row reached
            Next j
        End If

        ' Automatický posun řádku se zde neprovádí, protože konec řádku je explicitně signalizován (0,0 nebo delta)
        If curRow >= height Then Exit Do '                                                    Pokud jsou všechny řádky načteny, ukončíme dekódování    Exit loop if all rows processed
    Loop
    Load4BitRLEBMP = img '                                                                                                Vrácení načteného obrázku    Return the loaded image
End Function


Reply




Users browsing this thread: 1 Guest(s)