Author Topic: Custom Image Format ***with compression***  (Read 5272 times)

0 Members and 1 Guest are viewing this topic.

Offline Colonel_Panic

  • Newbie
  • Posts: 54
    • View Profile
Custom Image Format ***with compression***
« on: December 29, 2021, 09:55:43 pm »
Here's my NOTES I kept fooling around... I am gonna post the couple of sample programs now, I dont know HOW long I will be here (and have internet) before I leave again.

By next time I'm here and I can post again... I should have this "genericized" into a couple of SUBs

anyways, heres my notes I kept...
==================================================
NOTESx

Why?

   Several reasons. First and foremost, I have a recent interest in images and working with them in most of my projects. I have the classic quandary; I can make neat stuff on the screen, creatively reading in and displaying whole and parts of images... but I cant SAVE this cool and novel image.

   Yes, I know, I am aware there are routines developed to save in "one format". And that its a STANDARD format.

   The 'problem' is that I want to TINKER. I thought I was going to read about the "structure" of several popular image file formats, pick one, and start reading it in and writing it out as/when i felt like it.

   This logic, while techincally sound, had one fatal flaw: I'm not on the "same wavelength" with the file format. ANY file format, there are hard ones, and impossible ones... there doesnt seem to be a single "easy" format for me, the programmer.

What can I do about this?

   Well... I simply make up my own image format. I spaghetti-coded a couple of untitled hot mess proof-of-concept programs. I decided I needed a custom image I would recognize... I decided 640x480 was fine for a test.

   A certain number of random lines and random circles, in random colors. HEY, a recognizeable 32 bit "image" on the screen.

640x480 yields exactly 307,200 pixels
they are RIGHT there on my screen, I need each pixels COLOR.
I simply make a big array of the image dimensions, its type ~& for not losing the blue component the manual said I think.
I fill up the array by sampling the pixels with POINT(x,y)
now I have an array filled with color values i can work with.

For now, I just need to utilitize this as best i can.

the original format I called .imap (image map?)
the first 2 lines are read in, how wide and how tall, respectively.
after that? follows (640 x 480) = 307200 lines, each line representing a color
since the Y loop is inside the overall x loop... it gets done by vertical stripes
this could be reversed though I dont see how it matters

each color is represented by 2 hex characters, so 6 hex characters on each line represent the 3 color components of that pixel.

since I used a black background, I decided to use a "0" instead of " 0 0 0" for ZERO color, this made some savings. though file was still huge for its image size.

it WORKS though. the MAKE program makes a sample 640x480 image of random lines and citrcles, and saves it in .imap format

the OPEN program, proves the system works by reading it in, and displaying it. YES, its very slow and more slow given its relatively small 640x480 test size. BUT, I have no "hardware acceleration", I have no "commercial compression", nothing.

so, if it just WORKS at all, I'm happy. If it works just fast enough I can actually sort of use it? great!

next, I need some kind of compression. I dont want ANY loss of any kind, so any strategy canonly be "loss-less". Well, there are a LOT of "0" entries in the file, since it was a black background I painted on.

My basic compresion strategy is as follows:

I sweep through the file. Any time the NEXT LINE is the same as the PRESENT LINE? I keep track of it, and keep reading forward, line by line, until I hit the spot its finally a different color line.

there is NO REASON to have that many identical lines, I decided to make a "postprocessor" character "+", followed by the number of identical lines to follow.
The first 345 lines of my sample image? were zero color. After running POST, the post-processed .imap2 file contains none of the skipped (identical) lines.

My final sweep through, put out to .imap3 file, looks for " 0 0 0" entries and replaces them with the "preprocessor" character "@".

its a big savings, and its completely "lossless" of a format.
All I need now is a .imap3 OPEN demo, and I am golden for a start.

====================================

what can I do with this?

well, I can open any image file, and scale and display it any way I want to.
mirror images, text added, whatever.

now, if i WANT to? I can easily experiment with making some kind of "GIMP filter"
type of deal. This gets me STARTED, allows me to make a sample interface, do whatever I want (crop, go B+W, whatever) and save it out.

Later ON, if i can get more comfortable with any real file structures, I can convert to them. I want to know how to work with stuff, this is the best way for me to learn I figure.

I figure no matter WHAT format I end up maybe getting into? I will STILL need an easy internal representation of what each pixel is doing, this format IS that representation. The fact I can save and load and edit it easily myself is just a side benefit.

SIZES @ image size 640x480:
.imap  =  2.5MB     ;raw file, zero compression
.imap2 =  20.2 kB  ;compression by duplication skip-tracking
.imap3 =  17.9 kB  ;every instance " 0 0 0" replaced with "@"


NOTE: this is 100% loss-less compression. not one pixel, not one color, has been molested from the original.
NOTE: if i draw less or more random lines and circles? the sizes of the compressed files inches up and down with it. Reason why being, a few less lines and circles, means bigger and longer "zero gaps" of black background, thatget replaced bya single entry at a time. The more single color back ground showing, the smaller the compression gets.
NOTE: I chose " 0 0 0" (black) to switch to "@" on final compression pass, simply because it was the background color and a lot of it.
in the future, i will probably add a line in the file up front, indicating what color is to be replaced by the @.

EG, if you know your background is for instance WHITE, then, obviously you would want to replace THAT color with the "@" shortener symbol.

=========================================================================

As a sample image, I switched over from "some lines and circles" to "giant text font".
In this case? the "compression" numbers are actually pretty great !

no matter WHAT the image is? its ALWAYS 2.5MB for the .imap file, it has no choice. If i write out the colors to every pixel? Thats simply "the size" and thats all there is to it.

20k and 17k are "very respectable" I feel, as rolled-at-home compression alogrithms, given that it is 100 percent "no loss"
* IMap.zip (Filesize: 2.51 MB, Downloads: 217)
« Last Edit: December 29, 2021, 10:07:17 pm by Colonel_Panic »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Custom Image Format ***with compression***
« Reply #1 on: December 29, 2021, 10:02:37 pm »
The easiest custom format looks like this:

DIM M AS _MEM
M = _MEMIMAGE(Desired_Screen_Handle)
raw$ = SPACE$(M.SIZE)
_MEMGET M, M.OFFSET, raw$
compress$ = _DEFLATE$(raw$)


That's it!  You just pointed a mem block at your screen image, downloaded it into raw$, and then compressed it.

Now, just save to disk, along with image dimensions if necessary.

To load, just repeat the process in reverse.  ;)
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline Colonel_Panic

  • Newbie
  • Posts: 54
    • View Profile
Re: Custom Image Format ***with compression***
« Reply #2 on: December 29, 2021, 10:11:10 pm »
is "desired screen handle" the... image& handle? as in...

 img&=_newimage(640,480,32)

Offline Colonel_Panic

  • Newbie
  • Posts: 54
    • View Profile
Re: Custom Image Format ***with compression***
« Reply #3 on: December 29, 2021, 10:18:29 pm »
well, even if its all completely useless...

imapMAKE
imapMAKealpha

are both programs that simply create a 640x480 32 bit color image and save it to the file format. MAKE just makes a number of random colored lines and circles. the "alpha" does the same thing? but, it makes a big font "QB64" instead.

either program, you run first... they each create a file "BetaImage.imap"

==================================

at this point, you can "prove" the image file was created, and that you can read it in and display it, by running

imapOPEN

after you are done being (not) astonished, you then run...

imapPOST

this is the "compression" program, and it produces two other files...

"BetaImage.imap2"
"BetaImage.imap3"

and these are the 2 "compressed" formats. imap3 is slightly smaller than imap2.
naturally, you have to finish off your tour by running:

imapOPEN3

which will open and display ANY of the 3 formats.

Offline Colonel_Panic

  • Newbie
  • Posts: 54
    • View Profile
Re: Custom Image Format ***with compression***
« Reply #4 on: December 29, 2021, 11:03:22 pm »
hey STEVE, thanks ! (I checked out the commands in your sample code)

pretty cool, I inserted that code snippet into my "make" program and plopped an END statement after a single PRINT to a test file "foo.bar"

the compressed file size was almost exactly HALF of my ".imap3" format

I went and looked at MY algoriithm...
I am using 2 bytes to represent the 2 hex characters of each color
if i replaced each 2 hex chars color with a SINGLE BYTE that has the CHR$() value of 0 thru 255...

it would represent 0-255 and be half the size... which makes me wonder what the algorithm of "string compression" is, although i really dont CARE given its a lot faster.

EDITORS NOTE:
now that Steve McNeil has pointed out that I do not have to:
1) invent an image format
2) invent a viable compression algorithm

now I can "play ghetto GIMP" with a LOT less work and coding, and just come up with some kind of "structure" for my "filters"

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Custom Image Format ***with compression***
« Reply #5 on: December 30, 2021, 01:20:20 am »
If it's any help Colonal, you can also just plug in my SaveImage library and save as a BMP, PNG, GIF, or JPG image.  It's not much more complex and offers a lot more options like screen dithering, partial image captures, converting text screens to images, ect...

Typical program looks like:

'$INCLUDE:'SaveImage.BI'

SCREEN _NEWIMAGE(x, y, mode) ' as desired
'do and draw stuff

result = SaveFullImage("MySavedImage.BMP", 0) 'to save the full screen as a valid BMP image.  Change that extension to JPG, GIF, PNG to export in those formats.

'$INCLUDE:'SaveImage.BM'

https://qb64forum.alephc.xyz/index.php?topic=1651.0
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Custom Image Format ***with compression***
« Reply #6 on: December 30, 2021, 01:27:32 am »
is "desired screen handle" the... image& handle? as in...

 img&=_newimage(640,480,32)

It is, or else it's 0 for the active screen default.

SCREEN _NEWIMAGE(640, 480, 32)
DIM M AS _MEM
M = _MEMIMAGE(0) 'the zero here defaults to active display
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline Colonel_Panic

  • Newbie
  • Posts: 54
    • View Profile
Re: Custom Image Format ***with compression***
« Reply #7 on: December 30, 2021, 04:24:46 am »
mcneil...

i tried it out. I thought it wasnt doing anything, then I went to
"hit anmy key to quit" and tapping hte spacebar put it thru its paces

the page you sent me to, sent me to an updated page...
so i got the latest one w/the update.

that page had a note something like "I only tested this in windoze, anyone tests it in LINUX let me know"

so, I'm running Linux Mint (tara) and it looks like it worked fine
I just noticed you "re-scaled" the images bigger and saved them bigger. most cool!

(I'm particularly happy about the PNG)

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Custom Image Format ***with compression***
« Reply #8 on: December 30, 2021, 05:13:53 am »
Aye.  If you want to scale an image, just use NEWIMAGE and PUTIMAGE to make an image whatever size you want.

Example in pseudocode since I'm on my phone ATM...

'Do stuff, load your image...
image = _LOADIMAGE("original_image.whatever_extension_it_is", 32)

'And to scale it

scaled_image = _NEWIMAGE(ScaledX, ScaledY, 32)
_PUTIMAGE ,scaled_image, image

'Then just SaveImage the scaled image at the resolution you want.



There's a lot of stuff in the SaveImage library.  Before using it, I'd suggest opening the two files and reading the remarks in the BI and BM files.  They document the error codes you might see (such as for a file already existing of that name, or bad screen coordinates), a few SHARED VARIABLES which can toggle modes and various routine options, and explain what the various parameters are for.

I'm glad you can get some use out of it.  ;)
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Custom Image Format ***with compression***
« Reply #9 on: December 30, 2021, 12:56:16 pm »
@Colonel_Panic
It's interesting. I also thought (before) about my own ways of compression. So let me introduce you  my own method and add familiar BMP methods:

The first step is always: count the number of colors actually used in the image.
Let's say you only use 16 colors. What does it mean? This means that you write 16 color values ​​of the _Unsigned Long type at the beginning of the file. Good. And now you make an array with index 1 to 16 in the program. Each of these array indexes contains exactly one specific value of type Unsigned Long. So you can now write the individual pixels of the image with the index number of this field (ie the number 1 to 16).

This means that each pixel will have a number from 1 to 16. 16 can be written using 4 bites, so that the color information of two pixels can be stored in one byte.
I just described the principle of BMP format in 16 colors.

My solution was:
1) count the number of colors
2) Make a record of the number of colors in the file and the resolution
3) make the appropriate number of unsigned long entries
4) write the index number of the color used (first pixel)
5) write the number of pixels that contain this color the same as it counts when using the MEM command, so for 4 rows and 7 columns, it's 4 * _width + 7 for example

points 4 and 5 were repeated until the end of the figure. It's possible that this compression has a name, I don't know, I didn't study it.

Another example. Same as the described BMP compression but for 64 or less colors - the same principle, only the color index number is written to 6 bites (2 ^ 6)

For a two-color image, this can be written bit by bit. In the end, you can shrink the result with _DEFLATE $ and expand with _INFLATE $.
0 = color 1, 1 = color 2.

I'm definitely glad he shared his own image compression design.