creating graphics the functional way

I've created a small program to compose images with combinators: http://www.frank-buss.de/haskell/OlympicRings.hs.txt It produces TGA output, but I've converted it to PNG, because this is smaller: http://www.frank-buss.de/haskell/OlympicRings.png This is my first larger Haskell program and I have some questions: Nearly anything works without thinking too much about the types, but I don't like the use of fromInteger in the average and main functions. Is it possible that the integers are automaticly converted to floats? There are many functions like circle1Center, circle2Center, ... Is it possible to rewrite the program that it will be shorter, maybe using lists or an interpreter for a language for this kind of combinator programming style? Is it possible to write functions with an arbitrary number of arguments? Would be nice if the average function would accept any number of pixel values. Is there a PNG writer library for Haskell? I've seen a zlib interface, should be not too difficult to implement it in Haskell itself. Finally, what do you think about using this concept for generating images? It has some advantages, e.g. it is possible to scale the image without quality loss. But it needs some improvement, e.g. the anti-aliasing doesn't look very smooth. And it is very slow, it needs about 40 seconds on my computer to calculate the image. Using parametrized combinators sounds like a good idea for an interactive interface, like it is implemented in this program: http://www.theprodukkt.com/werkkzeug1#28 But this is impossible, if changing one parameter needs so long to update the image. -- Frank Buss, fb@frank-buss.de http://www.frank-buss.de, http://www.it4-systems.de

On 05/08/07, Frank Buss
Is it possible to write functions with an arbitrary number of arguments? Would be nice if the average function would accept any number of pixel values.
I think it's possible in some sense, because the Haskell interpretation of printf() works in the normal way. But there might be a bit of voodoo involved. Easier is to just pass a list of arguments to calculate over. (The following is neither correct nor fast...)
avg xs = sum xs `div` length xs
Cheers, D.

On Mon, Aug 06, 2007 at 12:48:02AM +0200, Frank Buss wrote: > I've created a small program to compose images with combinators: > > http://www.frank-buss.de/haskell/OlympicRings.hs.txt > > It produces TGA output, but I've converted it to PNG, because this is > smaller: > > http://www.frank-buss.de/haskell/OlympicRings.png > > This is my first larger Haskell program and I have some questions: > > Nearly anything works without thinking too much about the types, but I don't > like the use of fromInteger in the average and main functions. Is it (floor ((fromInteger (r1+r2+r3+r4)) / 4)) ... what about using `div` instead of / ? (ghci sesion) :Loading package base ... linking ... done. Prelude> :t (/) (/) :: (Fractional a) => a -> a -> a Prelude> :t div div :: (Integral a) => a -> a -> a Prelude> There has been a short discussion about this.. > possible that the integers are automaticly converted to floats? > Is it possible to write functions with an arbitrary number of arguments? > Would be nice if the average function would accept any number of pixel > values. I think I've read this question on #haskell once.. The answer of someone else was that he even could'nt think of it... Using one argument for each pixel would be overkill.. because you don't need different kinds of arguments here. So a list should be fine, shouldn't it? There are also some approaches of fixed length lists /Database/HaskellDB/BoundedString.hs (from package haskelldb) and the module SList http://www.haskell.org/haskellwiki/Applications_and_libraries/Data_structures#Serialising_data (-> SList) Think of an error message showing a function having 10.000 arguments? .. - No thanks :) Anyway.. you should have a look at http://haskell.org/haskellwiki/Applications_and_libraries (-> Graphics) Package Haven.. I think this library does what you want as well. Perhaps Pan is also interesting. But I haven't tried either of them yet. Marc Weber

Nearly anything works without thinking too much about the types, but I don't like the use of fromInteger in the average and main functions. Is it I've forgotten to attach this link: http://www.nabble.com/Perl-style-numeric-type-t3948269.html (perhaps use the threaded view to read all messages)
Marc

Frank Buss wrote:
I've created a small program to compose images with combinators:
http://www.frank-buss.de/haskell/OlympicRings.hs.txt
Finally, what do you think about using this concept for generating images? It has some advantages, e.g. it is possible to scale the image without quality loss. But it needs some improvement, e.g. the anti-aliasing doesn't look very smooth. And it is very slow, it needs about 40 seconds on my computer to calculate the image.
The idea of representing images simply by a function Int -> Int -> RGB is great :) You may want to look at Pan and its various offsprings, in particular Pancito http://www.haskell.org/haskellwiki/Applications_and_libraries/Graphics#Pan Unfortunately, there's not much you can do about the speed. Pan is faster, but it creates the illusion that you're programming in Haskell while internally, it compiles the image generation code to C++. Very clever, but hard to maintain and one of the reasons why it only works on Windows.
There are many functions like circle1Center, circle2Center, ... Is it possible to rewrite the program that it will be shorter, maybe using lists or an interpreter for a language for this kind of combinator programming style?
Well, you have lists for that type Point = (Int,Int) positions :: [Point] positions = zip [0.5 + fromIntegral n * dx | n <- [-2..2]] (cycle [y1,y2]) where dx = 0.125 y1 = 0.15 y2 = 0.25 colors :: [RGB] colors = [blue, yellow, black, green, red] type Image = Point -> RGB circles :: RGB -> [Image] circles background = map circle (zip positions colors) where circle (p,c) = fillMask (translate p ringCenter) c $ fillMask (translate p ringOutline) white background
Is it possible to write functions with an arbitrary number of arguments? Would be nice if the average function would accept any number of pixel values.
Lists are the natural choice here.
Is there a PNG writer library for Haskell? I've seen a zlib interface, should be not too difficult to implement it in Haskell itself.
Not that I know of. But gtk2hs has a Cairo-binding and I guess this one supports PNG. Note that this is vector graphics though, your approach is more general. Regards, apfelmus

apfelmus wrote:
The idea of representing images simply by a function
Int -> Int -> RGB
is great :) You may want to look at Pan and its various offsprings, in particular Pancito
http://www.haskell.org/haskellwiki/Applications_and_libraries/ Graphics#Pan
this looks interesting. The Java applets demonstrates that it is possible to implement this in realtime. I assume there are some clever optimizations implemented, which could be done with Haskell, too.
positions :: [Point] positions = zip [0.5 + fromIntegral n * dx | n <- [-2..2]] (cycle [y1,y2]) where dx = 0.125 y1 = 0.15 y2 = 0.25
Nice calculation for the positions, but at least for me it is more difficult to understand it than just writing the 5 points. But using lists is a good idea. I've updated the source: http://www.frank-buss.de/haskell/OlympicRings2.hs.txt http://www.frank-buss.de/haskell/OlympicRings2.png The anti-aliasing doesn't look good anyway, so I have removed it. Very cool for me was the "foldr (.) id" construct, which someone on #haskell suggested. Changing separate x/y coordinates to a list with 2 elements helped, too, to cleanup the source code. Maybe some more cleanups and the PNG save implementation, and then this code could be used as a small practical example for other Haskell newbies like me. BTW: Is there any coding standard for Haskell programs? I've seen different formattings, like how to indent "where" and the following parts of the code. Is there a common practice? -- Frank Buss, fb@frank-buss.de http://www.frank-buss.de, http://www.it4-systems.de

Am Montag, 6. August 2007 00:48 schrieb Frank Buss:
I've created a small program to compose images with combinators:
...
look very smooth. And it is very slow, it needs about 40 seconds on my computer to calculate the image. Using parametrized combinators sounds like ...
in that source file, you define Size and Pixel as structs of "Integer"s. that are neither unsigned chars (8_bit) nor ints (32-64_bit) nor floats (32_bit) but an artificial oo_bit int (1 int + list of bytes). i'm sure you will gain a speedup by redefining these structs. i.e. use Float or Int instead of Integer; see Data.Int and Data.Word for more alternatives. - marc
[code snippet from source file] -- image size data Size = Size { width :: Integer, height :: Integer } deriving (Eq, Ord, Show, Read) -- RGB components for an image pixel data Pixel = Pixel { r :: Integer, g :: Integer, b :: Integer } deriving (Eq, Ord, Show, Read) -- helper functions for saving bytes writeByte byte = putWord8 (fromIntegral byte) writeBytes bytes = mapM_ putWord8 bytes -- binary instance for saving Pixels instance Binary Pixel where put (Pixel r g b) = do writeByte b writeByte g writeByte r get = error "Pixel get not supported" [/code]

Marc A. Ziegert wrote:
in that source file, you define Size and Pixel as structs of "Integer"s. that are neither unsigned chars (8_bit) nor ints (32-64_bit) nor floats (32_bit) but an artificial oo_bit int (1 int + list of bytes). i'm sure you will gain a speedup by redefining these structs. i.e. use Float or Int instead of Integer; see Data.Int and Data.Word for more alternatives.
I've tried it, but it was not faster. Using Word8 for the RGB pixels even resulted in wrong colors with the anti-aliased version, maybe because of number overflows. -- Frank Buss, fb@frank-buss.de http://www.frank-buss.de, http://www.it4-systems.de

On 8/5/07, Frank Buss
Nearly anything works without thinking too much about the types, but I don't like the use of fromInteger in the average and main functions. Is it possible that the integers are automaticly converted to floats?
I recommend using Float or Double instead of Int for your point coordinates. You'll eliminate the need to convert to Float/Double. More importantly, your whole model will then be resolution independent, supporting continuous scaling, sub-pixel translation, rotation, etc. See http://conal.net/Pan for examples & papers. Cheers, - Conal

Hi Conal, I've tried some links, e.g. the pre-compiled components from http://conal.net/Pan/Releases/2000-12-06/ or the interactive presentation from http://conal.net/Pan/papers.htm , but file not found. Do you have the files? Would be easier than trying to setup Haskell and Visual C++ environment for compiling it (looks like the sources link works). BTW: There is Visual Studio Express, maybe you want to update your webpage, because Microsoft gives it away for free, if it can be used with Pan. How fast is your implementation? I've downloaded "werkkzeug" from http://www.theprodukkt.com/werkkzeug1#25 . The user interface is a bit unusual, but if you start the tutorial, it can display a texture example with about 50 composed functions and 256x256 pixels with about 300 fps. I've emailed the author and they didn't revealed much about the implementation, but said it was C with some inline assembler. I assume to make it fast, a good idea would be to cache some calculations, e.g. if you want a swirl effect, for all destination image cache all source positions, for the desired destination image size. Regards, Frank

On Tuesday 07 August 2007 21:22:00 Frank Buss wrote:
I assume to make it fast, a good idea would be to cache some calculations...
If you want to make it fast you should be using hardware acceleration. -- Dr Jon D Harrop, Flying Frog Consultancy Ltd. OCaml for Scientists http://www.ffconsultancy.com/products/ocaml_for_scientists/?e

I agree with Jon. And hardware acceleration is in tension with the
generality of the extreme generality of formulating images as general
(computable) functions on space (and hence arbitrary non-linear
transformations, etc).
*Unless*, you abandon the traditional acceleration of a fixed set of 2D (or
3D) primitives and transformations and instead compile into graphics
processor code as in http://conal.net/Vertigo.
BTW, I'd love to find one or more enthusiastic collaborators to help create
and release open-source, cross-platform, and successors to Pan & Vertigo.
Anyone interested?
- Conal
On 8/7/07, Jon Harrop
On Tuesday 07 August 2007 21:22:00 Frank Buss wrote:
I assume to make it fast, a good idea would be to cache some calculations...
If you want to make it fast you should be using hardware acceleration.
-- Dr Jon D Harrop, Flying Frog Consultancy Ltd. OCaml for Scientists http://www.ffconsultancy.com/products/ocaml_for_scientists/?e _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On 8/8/07, Conal Elliott
*Unless*, you abandon the traditional acceleration of a fixed set of 2D (or 3D) primitives and transformations and instead compile into graphics processor code as in http://conal.net/Vertigo .
Wow, cool :-)

Hi Frank,
Pan has been bit-rotten for a while now. Besides the unfortunate dependency
on Visual C++, it used a now long-obsolete GUI library. That's one reason I
started working on Pajama (http://conal.net/Pajama).
There's no reason not to create modern, cross-platform successors to
Pan/Pajama and Vertigo. Since I'm focusing on other projects (related to
Eros -- http://conal.net/papers/Eros), I'm waiting for collaborators.
Thanks for the VS Express tip. If I wanted to stick with VS, that'd be the
way to go.
I hadn't heard about werkkzeug. Looks pretty cool. Thanks.
Regards,
- Conal
On 8/7/07, Frank Buss
Hi Conal,
I've tried some links, e.g. the pre-compiled components from http://conal.net/Pan/Releases/2000-12-06/ or the interactive presentation from http://conal.net/Pan/papers.htm , but file not found. Do you have the files? Would be easier than trying to setup Haskell and Visual C++ environment for compiling it (looks like the sources link works). BTW: There is Visual Studio Express, maybe you want to update your webpage, because Microsoft gives it away for free, if it can be used with Pan.
How fast is your implementation? I've downloaded "werkkzeug" from http://www.theprodukkt.com/werkkzeug1#25 . The user interface is a bit unusual, but if you start the tutorial, it can display a texture example with about 50 composed functions and 256x256 pixels with about 300 fps. I've emailed the author and they didn't revealed much about the implementation, but said it was C with some inline assembler. I assume to make it fast, a good idea would be to cache some calculations, e.g. if you want a swirl effect, for all destination image cache all source positions, for the desired destination image size.
Regards,
Frank
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
participants (8)
-
apfelmus
-
Conal Elliott
-
Dougal Stanton
-
Frank Buss
-
Hugh Perkins
-
Jon Harrop
-
Marc A. Ziegert
-
Marc Weber