Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
Tags

16-color dithered?

A topic by artfluids created Feb 18, 2023 Views: 1,982 Replies: 23
Viewing posts 1 to 8

Ok, so I figured out that I can go into the listener and type: read["image"].encoded to load a color image and spit out the 16-color opaque string of that image. But it's just doing a basic quantize of the 16 colors. Could you possibly add a hint to dither the image?

Like: read["image" "dithered"].encoded

Also, it would be nice if images could be resources, just like sounds. Maybe this is already possible and I don't know. It would be nice if any of those opaque strings could be imported as a resource.

Also I seem to have a weird bug with the desktop version of Decker and Lilt. When I read in an image I just get back "?PNG\n?\n"

But if I do it in the browser version I get the image.

Developer (2 edits)

A read[] hint for loading colored dithered images is certainly possible, and is on my roadmap for some unspecified point in the future.

Currently, images are not "transportable" resources like sounds, fonts, patterns, and modules, but I'm very close to releasing a new feature that may handle the use cases you have in mind for that sort of functionality; stay tuned.

The read[] function in native-Decker and Lilt presently only supports GIF images; the response you're seeing is probably an attempt at reading a PNG file as a text document. Lilt has this limitation out of a desire to keep its dependency footprint as minimal as possible and therefore make it extremely portable, but I will be fixing the read[] of native-Decker to handle BMP/PNG/JPG soon. Hopefully web-decker or converting your files to GIF is acceptable as a stopgap for the time being.

ah, that makes sense. for now I can just use the browser version to generate the image strings.

Developer

I thought it might be useful to provide some details on how 16-color backgrounds can be imported as of Decker v1.12, which includes fixes and tweaks for a few minor but annoying stumbling blocks. There are many tools available for dithering images, and many algorithms and settings to choose from. In these examples I'll be using the command-line image manipulation utility imagemagick, because it is free, available on all popular operating systems, and easily automated.

Decker has an internal 16-color palette based on the 16-color Macintosh palette, with convenient named constants for each color in the global "colors" dictionary:


We'll need a reference image describing this palette in order to remap a full-color image. The easiest way to obtain one is to ask in Decker's listener. Execute this and save the result as "lut.gif":

r:image[16,1]
each c k i in colors r[i,0]:c end
write[r]

Then, choose an image of something beautiful, like a chicken:


Next we'll use the imagemagick "convert" utility from our operating system's command line. If we just "remap" our input image, we get a posterized result:

$convert gally.jpg -resize 512x342 -remap lut.gif output1.gif


A Floyd-Steinberg dither is much smoother:

$convert gally.jpg -resize 512x342 -dither FloydSteinberg -remap lut.gif output2.gif


An ordered dither is much grainier, but might be desirable if you specifically want to evoke a 90s aesthetic. I found experimentally that this image needs some contrast tweaks to avoid a washed-out result:

$convert gally.jpg -brightness-contrast -10 -resize 512x342 -ordered-dither o4x4 -remap lut.gif output3.gif


And of course there are many, many more parameters available to tweak.

Now that we have a dithered image, we can import it into Decker and splat it onto the current card background with the listener:

card.image.paste[read["image"]]


If our converted image doesn't exactly match the size of a card, we can go a step further by filling the card with black and then centering our image, for a nice letterbox effect:

i:read["image"]
card.image.map[() 1]
card.image.paste[i .5*card.size-i.size]


Now let's say we have a whole directory of wonderful chicken pictures (and who doesn't, really?) that we want to turn into a series of cards. We could use the above steps to prepare each one individually, but we could also use Lilt, the command-line counterpart of Decker, to automate the whole process, including invoking imagemagick:


What's particularly nice about this approach is that it's repeatable: at any time, you can re-run the script to regenerate backgrounds and add cards as necessary, while leaving any widgets, scripts, or other deck customizations intact.


Hope that helps!

Developer(+1)(-1)

A brief followup: v1.20 slightly modified the behavior of "range", requiring an adjustment to the above script:

When looking up a card by index, instead of

deck.cards[(range deck.cards)[index]]

The "range" operator can now be used more directly:

(range deck.cards)[index]
(+1)

thanks for the amendment 

(+2)

Small notes for anyone being lazy, (Like me)

If you fit one of the dimensions it will center fine, so if you have a whole bunch of taller than wide photos, just scale to width and let the code center it.


You can also reduce the colors any way you want, and it will still work fine. 

i:read["image"] card.image.map[() 1] card.image.paste[i .5*card.size-i.size]

Try importing random photos without doing any color reduction for neat effects

How can you save something after using the Listener ? Like, I paste the code into the listener ? And then, how can I save it into "lut.gif" ? Thanks a lot !

Developer (2 edits)

The "write[]" function prompts the user to save a file. If you call write[] with an image interface, for example, it will prompt the user to save that image as a .GIF image file.

After you paste code into the listener, don't forget that you need to press shift+enter to evaluate it! The reference manual section for the listener can be found here: https://beyondloom.com/decker/decker.html#thelistener

(+1)

I see, thanks !

(+1)

wow, that's awesome! this is a great guide. thanks for the help!

(+1)

I think as time has gone on, I think it's ok that Decker doesn't dither color images built-in. It makes sense to have the Bill Atkinson algorithm for the black and white images. But I've been having fun using ImageMagick to tweak dithering to my liking. And there's many algorithms and methods. So I guess I'm saying there wouldn't necessarily be a best one-size-fits-all algorithm anyway, except maybe FloydSteinberg mapped to the 16 Macintosh colors. But even then, it's nice to have the tweakability of ImageMagick. 

(4 edits)

I'm probably going to make a little alternative IDE for Decker as an OpenXTalk stack, and by that I mean I already started.
On mac,win,linux platforms OXT can call out to shell commands for stuff like imageMagick and ffmpeg.
It can also use embedded web ImageMagick (WASM) port to do image manipulation inside a Browser View Widget.
If running on macOS, OXT additionally has a wrapper library for some NSImage stuff with CoreImage filtering.
If nothing else it could expedite or offer fine controls for the lossy conversion to lookup palette images. 



Having Decker running in a browser view allows for tinkering around with the Decker html payload and then reloading it to test any modifications.

Also due to OpenXTalk having its roots in a Hyper-clone called MetaCard that dates  back to the early 1990s on Unix boxes, it also contains (still) a bunches of 16bit icon assets, as well as a set of 1-bit HC icons that a community member converted (I also made some SVG Path string versions of a few of those),  could add to the whole retro-ness.

That is some hardcore icon harvesting.  Rad!

(1 edit)

Yeah it is! 
Tinkering around with Apples NSNamed Images I found that modern macOS still includes icons from when Mac OS (OS X) was NeXT step, including the NeXT logo, gave me a little Easter-Egg finding chuckle.

Played around with 16 color images a little more, it's more frustrating than trying to make GIFs for a website in 1993, gifs have bigger color palettes and you could adapt the color table based on the original image. But this is restricted to only the 16 colors from 1987 Mac II, which here is a list of the RGB values of the Mac II system palette anyone is interested:
0,0,202
0,151,255
0,168,0
0,101,0
0,0,0
54,0,151
69,69,69
101,54,0
134,134,134
151,101,54
185,185,185
220,0,0
255,255,255
255,255,0
255,101,0
255,0,151

(1 edit)

And if anyone is using LiveCode or OpenXTalk IDE to mess around with Decker here's script for converting an image control contents to another image control with the required Mac II color palette:

on mouseUp
    export image "Original" to myVariable as gif with palette getDeckerMacIIPalette()
    --  set the text of another image control to myVariable to preview:
    set the text of image "16ColorVersion" to myVariable
    --  then you can save the new gif to a file with:
    --  where tFileName is a file path you provide must provide --
    --  open file tFileName for binary write;write myVariable to file tFileName;close file tFileName
end mouseUp
function getDeckerMacIIPalette
    get "255,255,255" & cr & \
   "255,255,0" & cr & \
   "255,101,0" & cr & \
   "220,0,0" & cr & \
   "255,0,151" & cr & \
   "54,0,151" & cr & \
   "0,0,202" & cr & \
   "0,151,255" & cr & \
   "0,168,0" & cr & \
   "0,101,0" & cr & \
   "101,54,0" & cr & \
   "151,101,54" & cr & \
   "185,185,185" & cr & \
   "134,134,134" & cr & \
   "69,69,69" & cr & \
   "0,0,0"
    -- the sorting of this list effects the resulting image
    sort it numeric by item 1 of each 
    return it
end getDeckerMacIIPalette
Developer

It's worth noting that Decker's 16-color palette can be customized via the Patterns Interface.

See also: the PalImport contraption.

(+1)

On that note, this may be useful, it's a 16 color palette designed for versatility, and in my experience does a decent job with dithering across a variety of photos. It desaturates them but often captures most of the frequency detail.

https://pixeljoint.com/forum/forum_posts.asp?TID=12795

Curious if there will ever be a version of Decker, or more features in Decker that are "color friendly" instead of it being sort of a hack/workaround to have color. I know this isn't totally in the spirit of Decker and HyperCard, but I really feel like it would probably encourage more users to gravitate towards Decker. Listen, I am 100% on board with the 1-bit Macintosh aesthetic, and I understand that it keeps the size of bitmaps small... But I feel like it would be nice to have the 16 colors not be so hidden. Let those colors be accessible from the toolbar. Have some sort of palette file, for swapping palettes between cards. 

Or... perhaps, if I could be even more bold, some sort of 8-bit color "extension" that allows 256 color palettes, but does not come stock with Decker? Perhaps also some sort of "extension" that allows for QuickTime style videos. I'm just sort of thinking about how it would be nice to author experiences with Decker that are on-par with other experiences of the Macintosh era, like Myst and Director-based games. Of course, this would balloon the size of decks... but this is why perhaps it could be some sort of "extended" feature. I just feel like Decker and Lil are powerful enough that they deserve to be at least this much more flexible as tools. I don't feel like this is feature creep/bloat to ask for. I think as long as Decker doesn't extend itself beyond "System 7" level Macintosh features, it will still be in the Macintosh spirit. 

I understand if this is not the ultimate goal of Decker. I just wanted to throw it out there. I still love Decker as it is and will continue to love it. I just would love to make experiences that are a little more 1995 than just 1985

Developer

The colors have been accessible from the toolbar for quite a while. If you choose any drawing tool, and then select "Style -> Color" from the menu, you'll get a color palette instead of the 1-bit palettes in the toolbar. Works for the modal color picker as well:

ooh, okay, I did not know that!

(+1)

As well as the colours in the toolbar, there's also a contraption in the contraption bazaar that lets you import palettes in from an external file https://itch.io/post/8352734