1

In a Factor program I want to:

  1. programmatically draw an image.
  2. display it.
  3. save it in some file.

Preferably:

  1. portable.
  2. with no external dependencies.

If not portable, should work on Windows.
If with external dependencies, something freely distributable and easy to bundle (like a dll/so file).

If the image is tuple class image, then (2) (displaying) is covered by ui and images.viewer` vocabs.

But I can't find a straightforward way to create and draw to an image, or output it in a raster format.

I don't care about:

  • having to draw pixel by pixel, as for the time being it would just be drawing simple straight lines.
  • bad performance. (Completely Ridiculously Awful Performance might be an issue, though ;)

What is the easiest way to do this in Factor?

fede s.
  • 582
  • 3
  • 17
  • Have you looked into the `images.bitmap` vocabulary? – cat Apr 09 '16 at 00:15
  • I remember when I tried to work with `images.png` a week or two ago -- just figuring out how to make a `loading-png` object from an io stream was confusing. – cat Apr 09 '16 at 00:17
  • 1
    @cat I did, but didn't get anywhere, I'll have a closer look. Can you point me in some direction? And yeah, confused is what I am right now! – fede s. Apr 09 '16 at 00:57
  • 1
    @cat Also, If you have time you could document your streaming adventure somewhere? maybe a Q-A here? Would be nice! :D – fede s. Apr 09 '16 at 00:58
  • I would be happy to do that, since I'm kinda stumped with [socket programming](http://stackoverflow.com/questions/36511260/how-do-i-write-to-a-duplex-stream) right now (maybe you can help with that?) :P – cat Apr 09 '16 at 01:01
  • The first and third points are simple enough that I can cook up an answer. I am not, however, at all experienced with UI development in Factor and so just looking at [the `ui.images` documentation](http://docs.factorcode.org/content/vocab-ui.images.html) is making me sigh. If you've already got a UI `world` up and running, it will probably be no problem to just call `draw-image`. – cat Apr 09 '16 at 01:33
  • @cat Sure, post it! I'm not interested in a full fledged UI right now. That can come later, as long as I can do it in the listener :D – fede s. Apr 09 '16 at 01:39
  • http://stackoverflow.com/q/37623559/ https://github.com/exercism/xfactor http://exercism.io/languages/factor :D – cat Jun 03 '16 at 21:36

1 Answers1

1

In order:

  1. Programmatically draw an image.

We're talking about bitmaps, which means unfortunately you'll need to work with each byte individually, unless you'd rather work with the even-less-documented svg vocabulary, which seems under-featured.

The good news is that Factor has lots of higher-order functions for working with arrays. Additionally, the promising-sounding images.processing vocab doesn't have very many words for this sort of thing.

What you'll actually want to do (as far as I can tell) is make a valid file header, then write the image data and header to a .bmp file.

  1. Display it.

Less easy. It seems like ui.images will take an image-name (whatever that is -- something that implements path>>, so maybe it's expecting a stream or file object?) and apparently display it in the current UI world, which is likely simpler if you have a UI already.

Just look at world's constructor:

TUPLE: world < track
    active? focused? grab-input? fullscreen? saved-position
    layers title status status-owner text-handle handle images
    window-loc pixel-format-attributes background-color promise
    window-controls window-resources ;

Damn, son.

  1. Save it in some file.

This one I can actually give an implementation for since it's pretty simple once you get the hang of it.

You've got an image in a folder, and we're going to load it into the listener. (Again, displaying it is a whole 'nother story).

USING: images.bitmap io.encodings.binary io.files ;

: bmp-open ( path -- stream ) binary <file-reader> load-bitmap ;

<file-reader> needs a path and an encoding (from io.encodings), and leaves an io.stream on the stack, which is what load-png, load-bitmap etc are looking for.

That will give us a loading-bmp, which is more useful than it sounds.

T{ loading-bitmap
    { file-header
        T{ file-header
            { size 12726 }
            { offset 54 }
            { header-length 40 }
        }
    }
    { header
        T{ v3-header
            { width 64 }
            { height 66 }
            { planes 1 }
            { bit-count 24 }
            { image-size 12672 }
        }
    }
    { color-index
        B{
            255 255 255 255 255 255 255 255 255 255 255 255 255
            255 255 255 255 255 255 255 255 255 255 255 255 255
            255 255 255 255 255 255 255 255 255 255 255 255 255
            255 255 255 255 255 255 255 255 255 255 255 255 255
            255 255 255 255 255 255 255 255 255 255 255 255 255
            255 255 255 255 255 255 255 255 255 255 255 255 255
            255 255 255 255 255 255 255 255 255 255 255 255 255
            255 255 255 255 255 255 255 255 ~12573 more~
        }
    }
}

The data you're looking for is obviously in color-index>>.

dup color-index>>

--- Data stack:
T{ loading-bitmap f ~file-header~ ~v3-header~ f ~byte-array~ f }
B{ 255 255 255 255 255 255 255 255 255 255 255 255 255 255...

You can mess with that array however you like, and then just do >>color-index (or mess with loading-bitmap's constructor), and write those bytes to a file.

TUPLE: loading-bitmap
    file-header header color-palette color-index bitfields ;

Something like loading-bitmap>bytes or bitmap>bytes should help you there.


When I was writing this answer last night, I totally didn't think to look on RosettaCode for bitmap-related things.

enter image description here

cat
  • 3,888
  • 5
  • 32
  • 61