Status & Roadmap
Authors & License
Funding Ultimate++
Search on this site

SourceForge.net Logo


This article tries to describe view of the Draw object's role in the painting process.


Please remember: Draw is not the raster image itself, much the less encoded in a particular image format. I believe you would do best to think about Draw as a channel or a toolbox interfacing the painting routine (a part of the program which wants to paint something; for the time being let's ignore the distinction between drawing vectors and rasters) to the actual "canvas" being painted onto. The main role of Draw is exactly to turn your logical drawing commands (e.g. "draw a line", "draw a bit of text", "draw a raster image" etc.) into something the output "device" can understand.


Now, this is the general story. In reality there are basically two families of Draw-related objects sharing many common traits. These are:


raster-oriented Draw objects: these normally include the Draw object in the Ctrl::Paint override, the ViewDraw, the BackDraw, the ImageDraw & ImageMaskDraw and sometimes PrintDraw.


vector-oriented Draw objects: DrawingDraw, WinMetaFileDraw and sometimes PrintDraw, and also (normally) PageDraw, PdfDraw and Report.


Although some might prefer to explain the characteristics of the above objects in abstract terms (with multiple references to "you don't need to know this and that" :-) ), I choose to be honest with you as to how they really work, because I believe that'll move you the farthest along the way.


Actually the Draw is something like a semi-intelligent painter with a plentiful palette of logical drawing objects; some of these are by nature vector-oriented, like lines, rectangles, polygons etc., some are naturally rasterized, typically Images, some are a bit of both, especially text objects.


Now, when the Draw receives a command to draw something (in U++ terminology, a drawing operation, see the host of xxxOp methods in the declaration of Draw), the painter for the desired output device has to decide what to do with it. Typically, when the object is of the same type as the output medium (both are vector or raster), not much work has to be done. When the source (the drawing operation) is vector-oriented and the output device is raster-based, the vector object has to be rasterized.


Typical raster-based Draw objects are related to painting into windows and images; the Draw passed to Ctrl::Paint by the U++ windowing mechanism is such a case, as well as ViewDraw, BackDraw or ImageDraw and ImageMaskDraw. All these drawing objects use the MS Windows or X Windows mechanism called GDI to channel the drawing objects to the built-in rasterizer which (perhaps using some graphic card accelerator in certain cases) ends up by modifying the desired pixels on the target device (the Ctrl area or the Image).


By calling the other Draw classes "vector-based" I don't mean they cannot cope with raster data. I am perhaps a little abusing the standard notion of the word to emphasize the fact that the latter group can manipulate vector objects directly, without rasterizing them first. So, for instance, DrawingDraw and WinMetaFileDraw are used to generate a serialized representation of the executed sequence of drawing operations, which can be later "played back" thus reproducing the original drawing.


Notice that in the above cases there is no actual "canvas" to be painted onto. Both DrawingDraw and WinMetaFileDraw merely maintain a data stream which is used to record the individual drawing operations (coming into Draw via the xxxOp member functions) without actually caring about what is being drawn very much. This is also the reason why you cannot read rasterized data from such types of Draw: if you call DrawToImage, for instance, for a DrawingDraw, it is sure to fail. But then, even if you call DrawToImage for a ViewDraw, you cannot always count on getting the correct image, because in situations when a portion of the window is obscured by another application, you'll get a snapshot of this other application and not your window.


The main advantage of DrawingDraw compared with ImageDraw (if we choose to see these two classes as two different means for creating a drawing which can be stored afterwards, perhaps to a file or a program cache) is that it can later (upon play-back) reproduce the original vector operations (like lines or polygons) exactly even when size of "painting" is rescaled, without blocky artifacts inevitable in rasters.


To sum the above into a few practical guidelines, please try to remember the following:


To create a recording of an image, use DrawingDraw or ImageDraw (see the above distinction between these two). E.g.


DrawingDraw ddraw(100, 100);


Drawing dwg = ddraw.GetResult(); // dwg is the output recording


Image img(100, 100);

ImageDraw idraw(img);



// now the Image has been modified by the myobject's drawing

operations and can be e.g. saved to disk


When using DrawToImage, you should take care of the above limitations. In particular, it is not always wise to use DrawToImage on a Draw which is not entirely under your control. To make the long story short, you're all right with ImageDraw and perhaps with BackDraw, but scarcely with anything else, becauses in most cases you cannot be sure what you'll get (e.g. with ViewDraw or PrintDraw). In certain cases you can be sure you'll get nothing at all (e.g. with DrawingDraw).


As concerns the difference between an Image and an AlphaArray, logically there's none (both represent masked raster images). Physically there is a lot of difference (you can view this difference as more or less optimization-related), because the AlphaArray is a physical matrix of pixels maintained directly by the application, whereas an Image is (at least sometimes) a logical bitmap object maintained by the Windows system (this is especially important in X Windows, because the AlphaArray is stored on the client, whereas Images are stored in the X Server). Another difference is that you can create an AlphaArray in any pixel format you want, but the supported pixel formats of Images are (or can be) limited by the properties of your windowing system.


As concerns image storage in the various standard formats (like jpg, png or gif), again these formats belong neither to the Draw object, nor to the Image object. It's best to see the ImageEncoder's as mere data processors which receive a raster input (an AlphaArray or an Image) and produce an encoded linearized image as their output (this is obviously the encoding phase corresponding to the Save-routines; with the Load-routines, the situation is vice versa). Therefore, as soon as you have an Image (or an AlphaArray), you can Save it in any format you like. Similarly, you can take an image file in one of the standard formats and read it into an AlphaArray or an Image.


Last edit by cxl on 05/01/2016. Do you want to contribute?. T++