Tuesday, September 1, 2009

Creating a declarative XML UI language

Wrote an article on creating declarative XML UI languages which comes complete with a framework that includes the following features:
  • Full parsing validation of all elements, attributes, namespaces and types within the framework (based on the XML Schema recommendation from W3C)
  • Support for multiple namespaces within the XUI tagset
  • Fast & efficient parsing using the SAX API
  • Builds a custom DOM specifically matched for the API requirements
  • Real-time validation of the XUI tagset by the API when editing, deleting or removing elements from the XUI DOM
  • Building of Swing GUIs based on the XUI documents
  • Fast serialization of the entire XUI DOM
  • Advanced search capabilities based on attribute names, element names, element level within the hierarchy
  • Multiple view support (e.g. flat, immediate children, whole DOM)
  • Pretty formatting output
The article is hosted at IBM's developerWorks web site. The URL is: http://www.ibm.com/developerworks/library/x-decxmlui/


Copyright © 2009, Arron Ferguson

Friday, July 3, 2009

Sun's Java Digital Media Support: Epic Fail

The Beginnings Of A Rant
I don't normally have a desire to start flame wars, go out of my way to troll, nor do I like to make blanket statements - especially about the technology that I've been using for 12 years. I've benefited greatly over that time period by using Java and committing projects such as Purnama XUI, a couple of games in J2ME, a book on creating content management systems in Java, and all of the courses that I've taught throughout those years using Java's list of media APIs.

However, I just recently came across a bug "feature" based on the java.awt.Shape interface that caused me to grit my teeth, my left eye to twitch, and spike my blood pressure to an unhealthy and high level. The code was to draw a polygon and then perform a fill of that same polygon (actually this code was someone's test from a forum post - my original code drew a polygon with many more points but this code demonstrated to me that it wasn't the number of the points):
 1 @Override
2 public void
paintComponent(Graphics g) {
3 super.
paintComponent(g);
4
Graphics2D g2 = (Graphics2D) g;
5
6 int
w = 200, h = w/2, s2 = 150;
7
g2.setColor(Color.red);
8
g2.drawPolygon(new int[]{0,2*w/5,0},new int[]{h/2,0,-h/2},3);
9
g2.setColor(Color.black);
10
g2.fillPolygon(new int[]{0,2*w/5,0},new int[]{h/2,0,-h/2},3);
11
}

The result should of course be that no red pixels are shown, meaning that the fill, fills the exact same area as the draw with a line. But under JDK 1.6 update 10, it doesn't. The fill polygon is incorrectly offset (by one pixel to the left) and does not draw all the correct pixels to the edges of the polygon on all sides. I tried several other examples. All of which display the same bug "feature". *sigh*

Now this seems to be such a minor and small problem. Based on the API documentation, the java.awt.Shape class's description of "insidedness" implies that the above "feature" is working correctly and as it has been documented. Right? It's not like I've never made a bad choice either or a mistake; I know that. But this problem got me thinking. Recalling back to all of the other times I've gritted my teeth, eye twitching, like Chief Inspector Charles Dreyfus I began to realize just how many times show stopping bugs or "features" such as this have either caused me to shake my head in disbelief or watch students or clients do the same thing.

JMF - Java Media Foobar
I remember teaching with the Java Media Frameworks (JMF) back in 2000. Students were using it to play audio streams, create music players and develop video capture applications such as video-phone applications. The problems we had were too numerous to count but some of the more frustrating issues were:
  • Video playback only working some of the time (debugging and testing never revealed the rhyme or reason to this)
  • Video capture starting several seconds after being prompted to do so
  • Video capture not capturing for the time specified
  • Very few web cams actually supported
  • No support for MP3
  • Configuration problems while trying to set up JMF (under Windows 2000 at that time)
Many of these problems were happening to students and just at a time they were expected to either hand in assignments or client projects. Worse was the problem of industry projects requiring JMF support; students were expected to explain why these types of problems weren't their fault.

It was an exciting and yet, incredibly frustrating time and I had to listen to irate industry sponsors and students both telling me why we shouldn't be using Java for digital media (at the time called multimedia).

But it wasn't just the bugs that killed JMF. It was the lack of usability. It appeared that design patterns and half-baked solutions were more important than ease of use and common feature sets. I came to see this process in action (more on this later).

For example, JMF did not include MP3 support. This was a huge shortcoming that limited the usefulness of JMF. At that time MP3 support was pertinent for any digital media API that purported to play, capture, or stream digital audio. Another major flaw in Sun's addressing of features for JMF was the lack of complete support for RTSP/RTCP. Although it was a feature offered for playback, there was no way of serving up content using the RTSP/RTCP protocol on the server. This blind spot could have been the single-most reason why JMF never stood a chance: developers could not serve up media content using this protocol.

JMF now seems all but abandoned, although Sun Microsystems insists that JMF is going strong. There is a "plugin" for MP3 support but 10 years later and this feature is too little, too late. Most of us have moved on; once bitten, twice shy as the saying goes.

Java Imaging Support - Catch Me If You Can
Next, I recall using an API known as Java Image Management Interface (JIMI). This API wasn't actually created by Sun Microsystems, but it was inherited and used to offer (at the time) the important support of being able to encode/decode various types of raster image file formats such as PNG, TIFF, PSD, and a few others. While JIMI filled a void left by Sun's lack of foresight and planning for usability, JIMI had the uncanny ability to crash the Java VM. Once again, I went into damage control and had to help students and industry sponsors work around why a specific image would actually crash the VM. How embarrassing this was.

JIMI was quickly replaced by Java Advanced Imaging (JAI) which offered support advanced filtering effects and for encoding/decoding of raster image file formats (although not as many as JIMI had offered). JIMI is still downloadable but Sun Microsystems states that they are only "making it available for developers who have code with dependencies on JIMI" and that users should instead use the Java Advanced Imaging (JAI) API.

However, JAI also seems to be abandoned by Sun with it being moved to the Java.net website. Specifically, Sun states that "Java Advanced Imaging (JAI) and the associated Image I/O Tools packages are now community source projects on java.net". This is an indirect way of saying "we've offloaded this project to the open source community because we are no longer interested in directly supporting this API/framework". No direction, no future, just maintenance of existing flaws and the odd answer to a question in the forum. This is the final nail in the coffin. "It's dead Jim."

The Java 2D API, which is part of the J2SE bundle, has had its own share of problems. Some of these include:
Once again, immense blind spots that appear to fly in the face of usability. After stumbling across these issues (and many more), I find myself asking "why didn't I take the blue pill?"

3D In Java - Affine Mess
Then there's Java3D. Java3D is a scene-graph-based API and was publicly released in March, 1998. Java3D is yet another API that Sun Microsystems has offloaded to the open source community in the hopes that kind-hearted Java aficionados will continue to maintain the failed project. Java3D never really had a chance though. Like so many other digital media APIs and frameworks that Sun Microsystems created, it suffered from a lack of
usability. Because Java3D is a scene-graph-based API, many of the low-level control calls that 3D developers require, simply aren't available. Add that to the list of bugs tying Java3D to Direct3D and OpenGL, and Sun Microsystems has created another abandoned API.

There is hope within the Java community when it comes to 3D API support due to a project known as Java OpenGL (JOGL). JOGL was started in the summer of 2002 by former MIT graduate students Ken Russell and Chris Kline. The API is a direct 1:1 mapping to the procedural calls found in the C programming language. This API has even become a JSR and has some handy utility calls bundled in it including the ability to take screen captures, output tiled images of really large images, and a seamless integration between Java 2D and JOGL.

What's interesting is that this API seems to be holding it's own. I strongly believe this is due to non-Sun engineers/developers looking at usability, features and benefits; basically being built for use, not for looking at the pretty UML diagrams. Whereas Java3D was a Sun API tossed down to the open source community after lackluster performance and interest, JOGL is a project started by two grads (most likely out of frustration), which has been promoted to a JSR and enjoys the status of having been one of the few independent projects to steer some sensible direction in Swing's rendering pipeline. Usability, simplicity. What a concept!

Java Sound - Testing 1, 2, 3
This is another API I remember using back in 2000 with students and industry projects. Once again, UML diagrams and design patterns were the main focus of this API instead of usability. Back then, Java Sound was missing two vitally important features in order to be useful:
  • Ability to play encode/decode MP3
  • Ability to save a sampled stream recording directly to file
At the time I was completely flabbergasted that Sun would take the time to build such an elegant interface and yet forget or ignore something so important such as the ability to save the captured sampled sound as a stream. The upshot of this decision was that any captured sound from an input would have to fit inside of the OS's main memory. Any large recordings requirements would simply not be doable.

The MP3 support and recording sampled sound directly to file were offered by two independent Java developers (Florian Bomers and Matthias Pfisterer) who created the Tritonus project which was meant to be an open source implementation of the Java API. Ironically the support of Tritonus scratched the itch more-so than what Sun provided. Like a repeat of JMF and the imaging APIs, Java sound lost the momentum that would have been required to attract programmers to this API.

Today, Java Sound
(finally) supports the ability to record streaming sampled sound directly to file but still lacks MP3 and OGG Vorbis support - two very common sound formats in use today. Without support for those two formats, there's very little chance of any rejuvenated interest in Java Sound. Sun Java software engineers did include the Service Provider Interface (SPI) within Java Sound but that's akin to telling a potential home buyer "Look, here's your dream house and the blueprints, if you can find someone that knows electrical, give them these blueprint and they'll set up the electricity in your dream house." Rather daft logic by my standards.

What's more peculiar is that although Java Sound is still listed as a Sun Microsystems interest (i.e. it's still on their site instead of being given up for adoption to open source developers at java.net), Sun Microsystems has delegated all technical questions and issues pertaining with Java Sound to Florian Bomers and Matthias Pfisterer's web site. Is this another example of Sun Microsystems disinterest and lack of any true vision when it comes to dealing with digital media support within the Java platform? I wonder.

JSR - Java Specification Refuse
Recall earlier on when I was talking about JMF and how UML and half-baked solutions were more important than ease-of-use. In 2001 I joined a Java Specification Request (JSR) known as The Stream Assembly API or JSR 158. The demand that this API was meant to satisfy at the time was to specify "classes and interfaces for the creation, management, and processing of broadcast and interactive stream multiplexes" for MPEG 2. I joined immediately since I had been toying with the idea of creating a media API in Java anyway and so I decided that it was better not to duplicate efforts.

It was an interesting opportunity that allowed a complete group of strangers from all over the world, to teleconference once a week and work together towards a common goal: provide a useful Java API. I found myself feeling very passionate about contributing to this project due to my frustration with JMF and Java Sound and so I looked at this opportunity as a way to help steer media support usability in the Java platform towards the right direction.

Unfortunately about three months into the draft I quickly realized that this was simply another example of Sun engineers' flawed syllogistic reasoning. I was preparing use cases, documenting an example API, preparing suggestions for ease-of-use for JSR 158 until one teleconference. One of the Sun engineers was suggesting that every position on the time line of a media stream had to be represented by an interface.

"What's wrong with a long, man?!" I blurted out.

It was suggested that in order to make all data types polymorphic and in order to ensure that strict design patterns were adhered to, that the position within a stream of media should be an interface. End of discussion. But I persisted and reminded the group that using a long primitive type in Java would support over 170 trillion hours (2^64/30/60/60) of positionable streaming or half that if one decided to ignore the negative values. Another way to look at it is having over 19 billion years of streaming - more than enough for your average streaming application requirements.

But the Sun engineers dug in their heels and refused to budge. However, it wasn't just that one particular design choice. It was everything. As the API was starting to take shape is was starting to look suspiciously like some mutated transmogrification of JMF and the Java Sound API. It was like David Cronenberg's The Fly: a complete aberration. I sent an email to the group and politely removed myself; I left feeling disappointed and frustrated.

The Future
Edward Gibbon once said "I have but one lamp by which my feet are guided, and that is the lamp of experience. I know no way of judging of the future but by the past." Using this outlook, it is easy to see that the current methodology that Sun has adopted is not working. It's leaving a garbage heap-trail of abandoned APIs and it's leaving Java developers less and less trusting with each iteration.

What Sun needs is a vision, a grand unification of digital media support. One framework to serve all forms of content and one that ties into existing standards, be they de facto or committee-based, no matter. No more blatant omissions or show-stopping bugs. But most importantly, one framework that places usability as its most principal goal. Java developers shouldn't feel envious towards their Python, Rails, Flex, or C#/.NET counterparts. Java developers shouldn't have to be embarrassed any more that we can't even fill a polygon correctly or play MP3 files.

As I watch the fanfare of JavaFX I find my default knee-jerk reaction asking "why?" Why create a new language, why go head-to-head with the de facto standard, Adobe's Flex/Flash/Air triple threat? Why assume that the underlying technology is working? Because it is not. Applets freeze and applets freeze the web browser. There are bugs to be fixed. Old bugs, new bugs, regressions, and blatantly missing fundamental features.

So, will JavaFX become yet another casualty and die a slow and painful death, eventually
thrown to the open source community in the hopes that a new generation will offer their time and effort looking after maintenance and bug fixes? It's hard to say. I'm personally not very optimistic. From where I stand, desktop and digital media support from Sun's Java is in jeopardy. Sun's commitment appears unclear. In the mean time, I need to go and write a flood-fill algorithm that fills an arbitrary polygon.

- Arron

=========================================
July 23, 2009 Edit

After reading this article about Hans Muller, who was Sun MicroSystems' CTO for Sun's Desktop division, and his defection from Sun (after being assigned to JavaFX), I am now convinced that JavaFX will go nowhere. Flex will continue to be the juggernaut it is, adding to that momentum is Hans working for Adobe and being an engineer for Flex.

It speaks volumes when a top engineer such as Hans Muller leaves to go work for the competition after 15 years - especially after being assigned a framework that was suppose to go head-to-head against Flash/Flex/AIR.

Copyright © 2009, Arron Ferguson

Sunday, May 3, 2009

Video Editing Fun

Whew! It's been a while. Nothing written for the blog now. However, I did post a humorous (IMO) video of my daughter and her fun on the Jolly Jumper. It took me roughly four hours of editing to get it just right (Adobe Premiere Elements 4 kept crashing and did so about a dozen times in that time period). I had to jack my wife's Vista machine because none of the video editing software packages in Linux are stable enough or offer the types of features used to create this video. Anyways, the video is here:

FlashJump


Ninja Edit: I've forgotten what a complete schmozzle video technology is. Here's an example of the set of steps I went through:
  1. Attempted to use KDEnlive in Linux (Ubuntu 9.04, Jaunty) to create the video. Unfortunately it had a bugs it in including not able to define the amount of time a dissolve should take - a pretty fundamental part of Non-Linear Editor (NLE) IMO.
  2. Attempted to use Jahshaka in Linux (Ubuntu 9.04, Jaunty) to create the video. Unfortunately that project seems to have fizzled.
  3. Attempted to use Kino but realized that it's not really a NLE - an NLE offers a timeline widget.
  4. Turned to Adobe Premiere Elements 4 - a legitimate copy I bought last year. Using it took four hours due to Premiere crashing over a dozen times.
  5. Created the video (whew!) and attempted to encode it in AVI with Microsoft's MPEG 4 CODEC Version 2 which left very noticeable artifacts in the video at various places. Come on guys, you're killing me!
  6. Encoded the video as Quicktime. First version was encoded by Adobe Premiere Elements 4 just fine at 240 MB and included the FPS. However, after I made some changes to the timeline of my video, I attempted to encode in Quicktime again but Adobe Premiere Elements 4 would not include the FPS (it left it as 0). The result was YouTube video playback offered about 1 frame every 2-3 seconds. This after taking an hour or so to upload ... Twice :( I did even try to set to 29.97 FPS, 30 FPS, progressive, interlaced, didn't seem to matter - once only and no more. Sheesh!
  7. Encoded as AVI Radius which was lower quality (and took forever to encode!) than the Quicktime but for some reason Adobe Premiere Elements 4 decided this time to include the FPS which I had set to 30.
I did finish the video but what a complete headache! What this reminded me of is the importance of software planning, careful design, and testing, testing, and more testing. I was disappointed with Adobe for Premiere Elements 4 for being buggy; previous versions of Premiere had always been solid in my experience. And Microsoft's CODEC that corrupts the playback with noticeable and annoying artifacts wasn't something I was welcoming with open arms either.

*steps down from soap box*

Copyright © 2009, Arron Ferguson

Sunday, February 22, 2009

Graphic Art Stylization in GIMP

Introduction
There are a lot of tutorials out on "t3h 1nt3rw3bZ" that show various different filter effects in GIMP and specifically how to do cartoon-like effects. That said, none of the ones that I came across on my search, nay trek, bore visually pleasing fruit ... at least not for me.

So, as I usually do when I'm waisting time when I should be marking student assignments or more importantly, spending time with my wife and new daughter, I decided to start playing in GIMP and after many failed attempts I came across what I deemed to be a sort of graphic art-like effect; it's not necessarily cartoon-like, but it is cartoony and I liked the effect and decided to write it down.

Of course I realized that I would probably lose the sheet of paper I wrote these set of steps down onto and so decided that I would use Linus Torvalds' philosophy which is:

"Only wimps use tape backup: real men just upload their important stuff on ftp, and let the rest of the world mirror it ;)"
This isn't FTP, but it's the same idea no doubt. :)

Getting Started
Either way, what we want to do is turn an image such as this:

Figure 1

Into this:

Figure 2

For this tutorial, you'll need to have the following:
  • Installed version on GIMP 2.4.x or better (although most of the filter effects should be found in earlier versions, they may be in different places within the application)
  • An image that you wish use to create a new graphic-art style image
In order to successfully complete this tutorial you'll need approximately 30 minutes of time and a basic understanding of GIMP. If you are a complete beginner to GIMP, you want to visit the GIMP web site documentation first.


Step 1 - Copy Original Image
As always, never start with an original image and make changes to it. Make a copy and manipulate the copy. Also, remember to save copies in a file format that supports lossless compression such as BMP, TIFF, or PNG. Technically GIF uses lossless compression too but it also only uses indexed color (i.e. 8 bits per pixel) and so at most you have 256 unique colors in your image - don't use GIF either.

For this particular type of style and effect, it is better to use images that contain even and well lit subjects in addition to noticeable edges around the subject (e.g. lighter color for the face and a darker background or vice versa).

Note: This tutorial will show screen shots of GIMP 2.4.5 but the tutorial should work with earlier versions of GIMP. Additionally, the screen shots are done in Linux but since GIMP is cross-platform you will see the same menu selections no matter what your operating system is - the windows may look different but that shouldn't have any affect on your work flow.
You can copy the image in GIMP by using the Image menu's Duplicate menu item (control-D). With this new in-memory copy, you need to desaturate the image. Do this by choosing the Colours menu's Desaturate menu item. Choosing the Desaturate menu item displays a dialog (figure 3). You can choose the Lightness radio button for the shades of gray desaturate algorithm. Choose Desaturate.

Figure 3

You should now have a gray scale version of your original which is what you want. You'll want to make a copy of this grayscale image (so Image->Duplicate again). You can close the original that you started with if you haven't already done so. At this point you now have two in-memory gray scale images opened in GIMP (figure 4).

Figure 4

Step 2 - Create Cartoon Outline
For this step you want to choose one of your gray scale images (you can minimize the other one for now, you're going to use it later as part of this process). With the chosen gray scale image, go to the Layer menu and choose the Duplicate Layer menu item (shift-control-D). With this new layer, invert it by going to the Colour menu and choosing the Invert menu item. Your image should now look similar to figure 5.

Figure 5

Now, with the same (inverted) layer, set the layer's mode to dodge like in figure 6.

Figure 6

Of course the image now looks like it's almost completely washed out but that's okay - it will very quickly look like something next. With the now copied, inverted and now "dodged" layer currently selected, go to the Filters menu, choose the Blur sub-menu, and choose the Gaussian Blur menu item. This offers a dialog box (figure 7). Set the Gaussian blur radius to 8 (both horizontal and vertical).
Choose OK.

Figure 7


Your image will now look similar to figure 8. The image is now starting to look like the outline drawing portion of the final effect. However there are a few things we can do to it to make it look a little more well-defined.

Figure 8

If you choose the Filters menu, then choose the Artistic sub-menu and then the Cartoon menu item, you're presented with a dialog box as in figure 9.

Figure 9

In the Cartoon dialog, set the mask radius to 24 and the percentage of black to between 0.1 and 0.2 for best results. Choose OK. You may have to adjust yours to a little higher than 0.2 if you need to bring the black outline out more. Now choose the Image menu's Flatten Image menu item. This removes all layers except the default (background) layer, essentially "baking" the layer as the term goes. From here there are a couple of enhancements that you can perform in order to make the black outline a little more "cartoony" or just plain artsy.

First, if the black lines are simply not showing up as dark as in figure 8, you can choose the Colours menu's Brightness Contrast menu item and adjust the brightness and contrast until you see similar black lines as in figure 10.

Figure 10

The next enhancement that you can perform is to use GIMP's eraser tool and simply erase certain lines. The filter is an edge detection filter and so what it's doing is showing lines where there are high frequency changes within the image (e.g. a sudden change from white to black). Because of this, some of the dark black lines may be unwanted. Patterns in a shirt or shadows on a wall may be lines that you may not wish to have in your image. In figure 10, detail in the face was removed, certain lines from the sofa pattern were removed to simplify the outline portion of this rendering. This image is now complete and you will want to save it. You can simply minimize it at this point - we will use it later. Remember to save it as a BMP or TIFF or something with lossless compression. We will now turn our attention to the other gray scale image that we minimized.

Step 3 - Create Background Shading
With the second gray scale image, Colours menu's Posterize menu item. This brings up the Posterize dialog shown in figure 11. Choose a value of 8 (i.e. 8 posterization levels). Choose OK.

Figure 11
Note: You can choose different posterization levels although if you go higher than about 12, the effect will be hidden. Additionally, going lower than 3 will remove too much detail.
Now choose the Filters menu, and then the Enhance sub-menu's Despeckle menu item. A dialog appears (figure 12). Uncheck the adaptive and recursive median values, set radius to about 4, black level to about 7, and white level to about 248. Choose OK.

Figure 12

Now choose the Filters menu, go to the Blur sub-menu's Gaussian Blur menu item - we've been here before! Select a horizontal and vertical radius of 2 (figure 13). Choose OK.

Figure 13

At this point you may wish to adjust the brightness contrast via the Colour menu's Brightness Contrast menu item. So soften this part of the image, choose the Filters menu, then Artistic sub-menu's Softglow menu item (figure 14) Set glow radius to around 35, brightness to approximately 0.27, and sharpness to around 0.86. Choose OK.

Figure 14

Your image will look something like figure 15. At this point you may wish to perform further touch ups. For example, you can use the Smudge Tool in GIMP to soften certain edges. In figure 15, many of the edges of different colors in the face are a little too harsh and obvious. I decided to use the smudge tool to soften them although I performed my smudge enhancements once I had placed the outline image into the shaded image
(see figure 17).

This leaves this image complete and you should save this image in a lossless image file format such as TIFF or BMP. Now we can move onto the merging portion of this tutorial.


Figure 15

Step 4 - Merge Shading with Outline
Now that you've created both an outline of the original and a shaded rendering of the original, you can bring them both together. If you don't already have it opened, open the shaded image from step 2 in GIMP, the outline rendering. Now open the shaded image rendering. Choose the Select menu's All menu item (control-A). This will select all pixels in your image since you only have one layer in it. Go to the outline image and choose the Edit menu's Paste menu item (control-V). GIMP will paste the shaded image as a new layer into the outline image You'll need to choose the New Layer icon to unfloat the new layer (figure 16).

Figure 16

Set this new layer's mode to multiply (figure 17). This allows both layers to be painted and therefore visible.

Figure 17

Step 5 - Finishing Touches
Our last step is to create a new color filter layer which we'll use to give ... color to the image. Choose the Layer menu's New Layer menu item (shift-control-N). This creates a new layer. Use the paint bucket tool in GIMP to fill the entire new layer with a color. In my example I chose baby blue which is going to be complimented to orange (color's complement). Now change this new painted layer's mode to Divide (figure 18). The color changes from blue to an orange-brown and it now shows both previous layers underneath. Continuing, choose the Image menu's Flatten Image menu item. This will flatten the image.

Figure 18

We're almost near the end. One last step to perform is to add the newsprint half-tone pattern. This is accomplished by duplicating the flattened image's one layer. (Yes, we just flattened and now we're creating more layers - just hang in there!) Choose the Layer menu's Duplicate Layer menu item (shift-control-D). This creates a duplicate of the rendered image. Now choose Filters menu's Distort sub-menu and choose the Newsprint menu item. You're presented with a dialog (figure 19).

Figure 19

For the dialog settings, choose the following:
  • Input SPI: 72
  • Output LPI: 17.1
  • Cell size: 4
  • Screen: Intensity (this is to keep it monochrome)
  • Spot function: PS Diamond
  • Antialiasing: 6
Choose OK. This will leave the black areas as transparent holes. You'll have to create a new layer underneath this half-toned layer and paint it black (figure 20). With the black layer underneath our half-tone layer, select the halftone layer, and merge it down to the black layer by choosing the Layer menu's Merge Down menu item.

Figure 20

Lastly, set this top layer's mode to percentage of Normal (e.g. 39). Figure 21 shows the percentage effect. At this point you can flatten the image and save the image as a TIFF or BMP. Voila! You have yourself a new image effect to add to your arsenal.

Figure 21

Summary

This tutorial walked through the set of steps required to create a graphic-art-like rendering of a photograph using some of the many GIMP filters and effects. Feel free to change some of the settings and even come up with new effects. Hopefully you found this tutorial useful.

Copyright
© 2009, Arron Ferguson