Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Coded Images
#1
Here are a few routines I wrote to store and retrieve a string that can be embedded within an image.

Think of this as writing a description on the back of a photograph. The image itself will contain its own description.

The embedded string can be anything; text, another image, even another file. There are limits on the string size though (see comments in code).

The code below includes sample code that will load 9 photos that have already had string embedded into them. The photos will display a caption that was decoded from the embedded string. The 9 photos are in the ZIP file below.

This code is just a proof on concept for me. It's highly inefficient but extremely fast. Go ahead and see what you can do, or modify, with it.

Code: (Select All)
'
' Encode/Decode Routines
' by Terry Ritchie 02/23/24
'
'+-----------------------------------------------------------------------------------------------+
'| Routines to encode and decode a string within an image.                                       |
'|                                                                                               |
'| Possible uses:                                                                                |
'|                                                                                               |
'| - Embed a description of the image into the image, like writing on the back of a photograph.  |
'| - Secret spy stuff, pass messages embedded in images to friends.                              |
'| - Embed another file or image within an image.                                                |
'|                                                                                               |
'| Notes:                                                                                        |
'|                                                                                               |
'| - These routines only work with 32bit images.                                                 |
'| - It's best to use images that are opague (all alpha values = 255 such as photographs)        |
'| - The formula to determine the maximum string length an image can hold is:                    |
'|                                                                                               |
'|              String_Size = (Image_Width x Image_Height \ 8) - 6                               |
'|                                                                                               |
'+-----------------------------------------------------------------------------------------------+

OPTION _EXPLICIT '          declare those variables!

CONST SWIDTH = 800 '        screen width
CONST SHEIGHT = 600 '       screen height
DIM Image AS LONG '         image to load
DIM DecodedText AS STRING ' decoded string from image
DIM p AS INTEGER '          photo counter

'**
'** BEGIN EXAMPLE CODE: cycle through 9 photos that have encoded strings within them
'**

SCREEN _NEWIMAGE(SWIDTH, SHEIGHT, 32)

FOR p = 1 TO 9
    Image = _LOADIMAGE("Photo" + _TRIM$(STR$(p)) + ".png", 32) ' load the image
    DecodedText = DecodeImage(Image) '                           decode string inside image
    Display_Image Image, DecodedText, 1 '                        show image and decoded caption
    _FREEIMAGE Image '                                           free the image
NEXT p
SYSTEM

SUB Display_Image (i AS LONG, s AS STRING, p AS INTEGER)

    CLS
    _PUTIMAGE ((SWIDTH - _WIDTH(i)) \ 2, (SHEIGHT - _HEIGHT(i)) \ 2), i
    LOCATE 2, ((SWIDTH \ 8) - LEN(s)) \ 2
    PRINT s;
    IF p THEN
        LOCATE (SHEIGHT \ 16) - 1, ((SWIDTH \ 8) - 11) \ 2
        PRINT "PRESS A KEY";
        SLEEP
    END IF

END SUB

'**
'** END EXAMPLE CODE
'**

'**
'** EXAMPLE: Saving an entire file within an image.
'**

'ff = FREEFILE '                                    get a free file handle
'OPEN "readme.md" FOR BINARY AS #ff '               open text file
'Text$ = SPACE$(LOF(ff)) '                          create a string the size of file
'GET #ff, , Text$'                                  get text as one string
'CLOSE #ff '                                        close text file
'Image& = _LOADIMAGE("photo.png", 32) '             load image to encode string into
'EncodedImage& = EncodeImage(Image&, Text$) '       encode string within image
'_SAVEIMAGE "EncodedPhoto.png", EncodedImage& '     save encoded image (use a non lossy format!)
'_FREEIMAGE Image& '                                remove image from memory
'_FREEIMAGE EncodedImage& '                         remove encoded image from memory



' ______________________________________________________________________________________________________
'/                                                                                                      \
FUNCTION EncodeImage& (i AS LONG, st AS STRING) '                                          EncodeImage& |
    ' __________________________________________________________________________________________________|____
    '/                                                                                                       \
    '| Embeds a string within an image.                                                                      |
    '|                                                                                                       |
    '| i  - image to encode                                                                                  |
    '| st - string to encode within image                                                                    |
    '|                                                                                                       |
    '| Returns: handle of new encoded image (-2 or less)                                                     |
    '|          -1 if an error occurred                                                                      |
    '|                                                                                                       |
    '| Note: Only works with 32 bit images                                                                   |
    '|                                                                                                       |
    '| The string is converted to a series of 1's and 0's that will be used to determine the alpha level of  |
    '| each pixel within the image. Therefore, each character in the string (a byte) will need 8 pixels to   |
    '| store the equivalent binary value. A binary value of 1 will set a pixel's alpha level to 255 and a    |
    '| binary value of 0 will set a pixel's alpha level to 254. This very slight variation in alpha levels   |
    '| will be imperceivable to the naked eye when viewing the image.                                        |
    '| A header and footer of 3 bytes is added to beginning and end of the string data. The header is used   |
    '| to identify that encoded information is contained within the image. The footer identifies the end of  |
    '| the string data contained within the image.                                                           |
    '|                                                                                                       |
    '| The size of an image will determine the maximum size of the encoded string it can hold.               |
    '|                                                                                                       |
    '| String_Size = (Image_Width x Image_Height \ 8) - 6                                                    |
    '\_______________________________________________________________________________________________________/

    DIM m AS _MEM '               memory block of image
    DIM em AS _MEM '              memory block of image to encode
    DIM ei AS LONG '              copy of image to encode
    DIM s AS STRING '             string to encode within image
    DIM p AS LONG '               position within string
    DIM o AS _OFFSET '            pixel offset within memory block
    DIM c AS _UNSIGNED _BYTE '    single character value within string
    DIM a AS _UNSIGNED _BYTE '    pixel alpha value to write
    DIM b AS _BYTE '              bit counter
    DIM b(7) AS _UNSIGNED _BYTE ' place value of bit counter
    DIM HeadFoot AS STRING * 3 '  string header and footer

    '+-------------------------------------------------------------------------------------------------------+
    '| Check for a valid image before proceeding.                                                            |
    '| ==========================================                                                            |
    '+------------------------------+                                                                        |
    EncodeImage& = -1 '             | assume this image is invalid                                           |
    IF i < -1 THEN '                | is this a valid image handle?                                          |
        IF _PIXELSIZE(i) = 4 THEN ' | is this a 32 bit color image?                                          |
            '                       +------------------------------------------------------------------------+
            '+-----------------------------------------------------------------------------------------------+
            '| Store binary place holder values                                                              |
            '| ================================                                                              |
            '+-----------+                                                                                   |
            b(0) = 1 '   |  define 8 bit binary place values                                                 |
            b(1) = 2 '   |                                                                                   |
            b(2) = 4 '   |                                                                                   |
            b(3) = 8 '   |                                                                                   |
            b(4) = 16 '  |                                                                                   |
            b(5) = 32 '  |                                                                                   |
            b(6) = 64 '  |                                                                                   |
            b(7) = 128 ' |                                                                                   |
            '            +-----------------------------------------------------------------------------------+
            '+-----------------------------------------------------------------------------------------------+
            '| Add an identifying header and footer to string        Note: The possibility of this header/   |
            '| ==============================================              footer combination found in a     |
            '+-------------------------------+                             string will be very low but not   |
            HeadFoot = "U" + CHR$(0) + "U" ' | 010101010000000001010101    a zero chance. May want to scan   |
            s = HeadFoot + st + HeadFoot '   | add header and footer       before proceeding. ( use INSTR )  |
            '                                +---------------------------------------------------------------+
            '+-----------------------------------------------------------------------------------------------+
            '| Use image memory manipulation for speed                                                       |
            '| =======================================                                                       |
            '+-----------------+                                                                             |
            m = _MEMIMAGE(i) ' | create image memory block                                                   |
            '                  +-----------------------------------------------------------------------------+
            '+-----------------------------------------------------------------------------------------------+
            '| Ensure that the string will fit inside the image                                              |
            '| ================================================                                              |
            '+-----------------------------+                                                                 |
            IF LEN(s) > m.SIZE \ 32 THEN ' | will string fit into image?                                     |
                _MEMFREE m '               | no, free image memory block                                     |
                s = "" '                   | clear variable                                                  |
            ELSE '                         | Yes, the string will fit                                        |
                '                          +-----------------------------------------------------------------+
                '+-------------------------------------------------------------------------------------------+
                '| Turn error checking off for speed                                                         |
                '+-------------------------------------------------------------------------------------------+
                $CHECKING:OFF
                '+-------------------------------------------------------------------------------------------+
                '| Use image memory manipulation for speed                                                   |
                '| =======================================                                                   |
                '+-------------------+                                                                       |
                ei = _COPYIMAGE(i) ' | create image to encode                                                |
                em = _MEMIMAGE(ei) ' | create image to encode memory block                                   |
                '                    +-----------------------------------------------------------------------+
                '+-------------------------------------------------------------------------------------------+
                '| Endcode string into image                                                                 |
                '| =========================                                                                 |
                '+------------------------------------------------+                                          |
                p = 1 '                                           | start at text position 1                 |
                o = 0 '                                           | reset pixel offset location              |
                DO '                                              | begin encoding loop                      |
                    c = ASC(s, p) '                               | get next character value in string       |
                    b = 0 '                                       | reset bit counter                        |
                    DO '                                          | begin bit identification loop            |
                        IF c AND b(b) THEN a = 255 ELSE a = 254 ' | 255 = 1, 254 = 0                         |
                        _MEMPUT em, em.OFFSET + o + 3, a '        | adjust alpha value in encoded image      |
                        o = o + 4 '                               | next pixel position in memory block      |
                        b = b + 1 '                               | next bit in character                    |
                    LOOP UNTIL b = 8 '                            | leave when all 8 bits processed          |
                    p = p + 1 '                                   | next character in string                 |
                LOOP UNTIL p > LEN(s) '                           | leave when string exhausted              |
                _MEMFREE m '                                      | free image memory block                  |
                _MEMFREE em '                                     | free encoded image memory block          |
                '                                                 +------------------------------------------+
                '+-------------------------------------------------------------------------------------------+
                '| Turn error checking back on                                                               |
                '+-------------------------------------------------------------------------------------------+
                $CHECKING:ON
                '+-------------------------------------------------------------------------------------------+
                '| Return handle of encoded image                                                            |
                '| ==============================                                                            |
                '+------------------+                                                                        |
                EncodeImage& = ei ' | return handle of encoded image                                         |
                '                   +------------------------------------------------------------------------+
            END IF
        END IF
    END IF

END FUNCTION
' ______________________________________________________________________________________________________
'/                                                                                                      \
FUNCTION DecodeImage$ (i AS LONG) '                                                        DecodeImage$ |
    ' __________________________________________________________________________________________________|____
    '/                                                                                                       \
    '| Extracts a coded string from within an image.                                                         |
    '|                                                                                                       |
    '| i - image to decode                                                                                   |
    '|                                                                                                       |
    '| Returns: string extracted from image                                                                  |
    '|          null if no coded string was found within image or an error occurred                          |
    '|                                                                                                       |
    '| Note: Only works with 32 bit images                                                                   |
    '\_______________________________________________________________________________________________________/

    DIM m AS _MEM '               memory block of image
    DIM e AS _OFFSET '            end of memory block
    DIM s AS STRING '             string containing decoded data
    DIM c AS _UNSIGNED _BYTE '    single character value
    DIM o AS _OFFSET '            pixel offset within memory block
    DIM a AS _UNSIGNED _BYTE '    pixel alpha value
    DIM b AS _BYTE '              bit counter
    DIM b(7) AS _UNSIGNED _BYTE ' place value of bit counter
    DIM HeadFoot AS STRING * 3 '  string header and footer
    DIM Done AS _BYTE '           finished processing flag

    '+-------------------------------------------------------------------------------------------------------+
    '| Check for a valid image before proceeding.                                                            |
    '| ==========================================                                                            |
    '+------------------------------+                                                                        |
    s = "" '                        | assume this image is invalid                                           |
    IF i < -1 THEN '                | is this a valid image handle?                                          |
        IF _PIXELSIZE(i) = 4 THEN ' | is this a 32 bit color image?                                          |
            '                       +------------------------------------------------------------------------+
            '+-----------------------------------------------------------------------------------------------+
            '| Store binary place holder values                                                              |
            '| ================================                                                              |
            '+-----------+                                                                                   |
            b(0) = 1 '   |  define 8 bit binary place values                                                 |
            b(1) = 2 '   |                                                                                   |
            b(2) = 4 '   |                                                                                   |
            b(3) = 8 '   |                                                                                   |
            b(4) = 16 '  |                                                                                   |
            b(5) = 32 '  |                                                                                   |
            b(6) = 64 '  |                                                                                   |
            b(7) = 128 ' |                                                                                   |
            '            +-----------------------------------------------------------------------------------+
            '+-----------------------------------------------------------------------------------------------+
            '| Use image memory manipulation for speed                                                       |
            '| =======================================                                                       |
            '+----------------------+                                                                        |
            m = _MEMIMAGE(i) '      | create image memory block                                              |
            e = m.OFFSET + m.SIZE ' | end of memory block                                                    |
            '                       +------------------------------------------------------------------------+
            '+-----------------------------------------------------------------------------------------------+
            '| Turn error checking off for speed                                                             |
            '+-----------------------------------------------------------------------------------------------+
            $CHECKING:OFF
            '+-----------------------------------------------------------------------------------------------+
            '| Extract string from image                                                                     |
            '| =========================                                                                     |
            '+---------------------------------------+                                                       |
            HeadFoot = "U" + CHR$(0) + "U" '         | 010101010000000001010101 string header and footer     |
            Done = 0 '                               | reset finished flag                                   |
            s = "" '                                 | reset string                                          |
            o = 0 '                                  | reset pixel offset                                    |
            DO '                                     | cycle through image pixels                            |
                b = 0 '                              | reset bit count                                       |
                c = 0 '                              | reset character value                                 |
                DO '                                 | cycle through character bits                          |
                    _MEMGET m, m.OFFSET + o + 3, a ' | get alpha value of pixel                              |
                    IF a = 255 THEN c = c + b(b) '   | if 1 then add place value                             |
                    b = b + 1 '                      | increment bit counter                                 |
                    o = o + 4 '                      | increment to next image pixel                         |
                LOOP UNTIL b = 8 '                   | leave when 8 bits examined                            |
                s = s + CHR$(c) '                    | add character to string                               |
                '+-----------------------------------+                                                       |
                '| Search for string header                                                                  |
                '| ========================                                                                  |
                '+------------------------------------+                                                      |
                IF o = 96 THEN '                      | first 3 characters extracted                         |
                    IF s <> HeadFoot THEN Done = -1 ' | report encoded string not found if no header         |
                    s = "" '                          | remove header (null return for no header found)      |
                ELSE '                                | beyond first 3 characters                            |
                    '+--------------------------------+                                                      |
                    '| Search for string footer                                                              |
                    '| ========================                                                              |
                    '+--------------------------------+                                                      |
                    IF RIGHT$(s, 3) = HeadFoot THEN ' | check for footer (end of string)                     |
                        Done = -1 '                   | report encoded string found                          |
                        s = LEFT$(s, LEN(s) - 3) '    | remove footer                                        |
                    END IF '                          |                                                      |
                END IF '                              |                                                      |
            LOOP UNTIL (o = e) OR Done '              | leave at end of memory block or done processing      |
            _MEMFREE m '                              | free memory block                                    |
            '                                         +------------------------------------------------------+
            '+-----------------------------------------------------------------------------------------------+
            '| Set string to null if a footer was not found (image corruption perhaps?)                      |
            '| ============================================                                                  |
            '+------------------------+                                                                      |
            IF Done = 0 THEN s = "" ' | a footer was not found                                               |
            '                         +----------------------------------------------------------------------+
            '+-----------------------------------------------------------------------------------------------+
            '| Turn error checking back on                                                                   |
            '+-----------------------------------------------------------------------------------------------+
            $CHECKING:ON
        END IF
    END IF
    '+-------------------------------------------------------------------------------------------------------+
    '| Return string found                                                                                   |
    '| ===================                                                                                   |
    '+-----------------+                                                                                     |
    DecodeImage$ = s ' | return string                                                                       |
    '                  +-------------------------------------------------------------------------------------+

END FUNCTION
' ______________________________________________________________________________________________________
'/                                                                                                      \
FUNCTION EncodedStringExists% (i AS LONG) '                                        EncodedStringExists% |
    ' __________________________________________________________________________________________________|____
    '/                                                                                                       \
    '| Tests an image for an encoded string.                                                                 |
    '|                                                                                                       |
    '| i - image to test for encoded string                                                                  |
    '|                                                                                                       |
    '| Returns:  0 if no encoded string found                                                                |
    '|          -1 if an encoded string was found                                                            |
    '\_______________________________________________________________________________________________________/

    DIM m AS _MEM '               memory block of image
    DIM e AS _OFFSET '            end of memory block
    DIM s AS STRING '             string containing decoded data
    DIM c AS _UNSIGNED _BYTE '    single character value
    DIM o AS _OFFSET '            pixel offset within memory block
    DIM a AS _UNSIGNED _BYTE '    pixel alpha value
    DIM b AS _BYTE '              bit counter
    DIM b(7) AS _UNSIGNED _BYTE ' place value of bit counter
    DIM HeadFoot AS STRING * 3 '  string header and footer

    '+-------------------------------------------------------------------------------------------------------+
    '| Check for a valid image before proceeding.                                                            |
    '| ==========================================                                                            |
    '+------------------------------+                                                                        |
    EncodedStringExists% = 0 '      | assume this image is invalid                                           |
    IF i < -1 THEN '                | is this a valid image handle?                                          |
        IF _PIXELSIZE(i) = 4 THEN ' | is this a 32 bit color image?                                          |
            '                       +------------------------------------------------------------------------+
            '+-----------------------------------------------------------------------------------------------+
            '| Turn error checking off for speed                                                             |
            '+-----------------------------------------------------------------------------------------------+
            $CHECKING:OFF
            '+-----------------------------------------------------------------------------------------------+
            '| Store binary place holder values                                                              |
            '| ================================                                                              |
            '+-----------+                                                                                   |
            b(0) = 1 '   |  define 8 bit binary place values                                                 |
            b(1) = 2 '   |                                                                                   |
            b(2) = 4 '   |                                                                                   |
            b(3) = 8 '   |                                                                                   |
            b(4) = 16 '  |                                                                                   |
            b(5) = 32 '  |                                                                                   |
            b(6) = 64 '  |                                                                                   |
            b(7) = 128 ' |                                                                                   |
            '            +-----------------------------------------------------------------------------------+
            '+-----------------------------------------------------------------------------------------------+
            '| Use image memory manipulation for speed                                                       |
            '| =======================================                                                       |
            '+----------------------+                                                                        |
            m = _MEMIMAGE(i) '      | create image memory block                                              |
            e = m.OFFSET + m.SIZE ' | end of memory block                                                    |
            '                       +------------------------------------------------------------------------+
            '+-----------------------------------------------------------------------------------------------+
            '| Extract header from image                                                                     |
            '| =========================                                                                     |
            '+---------------------------------------+                                                       |
            HeadFoot = "U" + CHR$(0) + "U" '         | 010101010000000001010101 string header and footer     |
            s = "" '                                 | reset string                                          |
            o = 0 '                                  | reset pixel offset                                    |
            DO '                                     | cycle through image pixels                            |
                b = 0 '                              | reset bit count                                       |
                c = 0 '                              | reset character value                                 |
                DO '                                 | cycle through character bits                          |
                    _MEMGET m, m.OFFSET + o + 3, a ' | get alpha value of pixel                              |
                    IF a = 255 THEN c = c + b(b) '   | if 1 then add place value                             |
                    b = b + 1 '                      | increment bit counter                                 |
                    o = o + 4 '                      | increment to next image pixel                         |
                LOOP UNTIL b = 8 '                   | leave when 8 bits examined                            |
                s = s + CHR$(c) '                    | add character to string                               |
            LOOP UNTIL (o = e) OR (o = 96) '         | leave at end of memory block or 3 characters retrieved|
            _MEMFREE m '                             | free memory block                                     |
            '                                        +-------------------------------------------------------+
            '+-----------------------------------------------------------------------------------------------+
            '| Turn error checking back on                                                                   |
            '+-----------------------------------------------------------------------------------------------+
            $CHECKING:ON
            '+-----------------------------------------------------------------------------------------------+
            '| Return status of string within image                                                          |
            '| ====================================                                                          |
            '+-----------------------------------------------+                                               |
            IF s = HeadFoot THEN EncodedStringExists% = -1 ' | return -1 if header found                     |
            '                                                +-----------------------------------------------+
        END IF
    END IF

END FUNCTION


Attached Files
.zip   photos.zip (Size: 6.01 MB / Downloads: 18)
New to QB64pe? Visit the QB64 tutorial to get started.
QB64 Tutorial
Reply


Messages In This Thread
Coded Images - by TerryRitchie - 02-23-2024, 05:25 PM
RE: Coded Images - by a740g - 02-23-2024, 05:31 PM
RE: Coded Images - by TerryRitchie - 02-23-2024, 05:44 PM
RE: Coded Images - by SMcNeill - 02-23-2024, 06:40 PM
RE: Coded Images - by SMcNeill - 02-23-2024, 07:50 PM
RE: Coded Images - by Dimster - 02-23-2024, 07:56 PM
RE: Coded Images - by SMcNeill - 02-23-2024, 07:58 PM
RE: Coded Images - by Dimster - 02-23-2024, 09:15 PM
RE: Coded Images - by NakedApe - 02-24-2024, 12:37 AM
RE: Coded Images - by Dimster - 02-24-2024, 01:56 PM
RE: Coded Images - by Pete - 02-25-2024, 07:25 AM
RE: Coded Images - by OldMoses - 02-27-2024, 02:47 AM
RE: Coded Images - by a740g - 02-27-2024, 03:10 AM
RE: Coded Images - by TerryRitchie - 02-27-2024, 03:13 AM
RE: Coded Images - by Pete - 02-28-2024, 09:07 PM



Users browsing this thread: 4 Guest(s)