• Geometry 3D
  • Printing
  • Images
  • Audio
  • Films

  • Regions
  • Bundles
  • Matrices
  • Fonts
  • Text



Images

This part of the Guildhall toolbox declares the foundation class of the graphics architecture, AGraphicsPort, as well as two important subclasses, one for drawing to raster images and one for recording a sequence of graphics drawing calls.

AGraphicsPort

On Classic Mac the grafPort was the cornerstone of QuickDraw, the Lisa's and early Mac's graphics package. QuickDraw wasn't object oriented, so coding would proceed by setting the grafPort (SetPort) to which one wished to draw as a global system parameter. Subsequent drawing calls, as well as calls to change retained graphics state, all used that global port. The port was often tied to a window, but could also be attached to a printer. QuickDraw supported the PICT data structure as a graphics collection, but it wasn't used as an independent port in the same fashion as windows or printers. Instead it was attached, by a special toolbox call, to whatever port was then in use. While so attached it recorded a copy of everything drawn to that port. The picture could be retrieved when drawing was concluded.

This architectural approach always struck me as highly functional, and quite applicable to an object oriented graphics system. Having one way to do drawing that could be instantiated for a variety of purposes seemed efficient and extensible. But the Albert project at Taligent did not follow this model, and that left me wondering how it would have worked out. In many respects this was one of the main experiments that prompted me to create first an object oriented toolbox and later the Guildhall project in full. In my experience it has worked out really well.

The foundation of my approach is the abstract class AGraphicsPort. It defines all the available drawing calls in three successive forms.


AGraphicsPort::Draw(const TGeometry& g);
AGraphicsPort::Draw(const TGeometry& g,const TBundle& b);
AGraphicsPort::Draw(const TGeometry& g,const TBundle& b, const TMatrix& m);


In the example above, TGeometry stands in for any one of the geometry classes shown below (3D geometries omitted for the time being).


TLine

TRect

TEllipse

TRoundRect

TPolyline

TPolygon

TCurve

TShape

TText

TRegion

TImage

TGraph (1)

(1) because of how C++ works, TGraph objects must be drawn by a DrawGraph method


The idea behind the three forms was that the graphics port could be configured to hold state such as the fill color or the transform, and there were calls to set those values in the port (by setting the bundle or matrix). In practice, I can't think of a single instance where I have ever used the first form. I do use the second form, but only when the port's matrix remains unset and thus defaults to the identity matrix. And note that in doing so I'm relying upon the port's cached matrix to actually be the identity matrix. Most of the time, though, I use the third form, where the port's cached state, other than clipping, is not used.

And speaking of clipping, I do use the port's methods to set and restore clipping all the time. When drawing the look of a field, or part of a window's contents, setting the clipping once is highly convenient. And besides that, there are computations regarding the clipping that are cached across drawing calls, and typically region calculations are expensive enough that avoiding recalculation pays off. If every drawing call had to specify a clipping region as well, performance would likely suffer.

Besides clipping, AGraphicsPort provides methods for establishing back buffers (used mostly by windows) and for defining the start and end of pages (used mostly by printing). Specifically for windows it maintains a separate transform that defines how the window relates to the screen, including calls to translate coordinates between screen global values and window local values, and also a visible region that details how much of a window is actually visible on the desktop. Nothing new here, though. QuickDraw and probably all other graphics packages have the same functionality lurking somewhere.

So now let's look at a couple of important subclasses of AGraphicsPort, TImage and TGraph. There's are separate discussions for the related subclasses for windows (TWindow) and printers (APrinter).

TImage

I tried to make Guildhall's images really easy to work with. All you really need to create one is the size and, optionally, a choice of low or high resolution, low resolution being the current default.


TImage lorezImage(TPoint(600,400));
TImage hirezImage(TPoint(600,400),AGraphicsPort::GetDoubleResolution());


Because TImage subclasses from AGraphicsPort, drawing to one is the same as drawing to a window or a printer or a TGraph (discussed next). TImage includes the helper function Fill which fills the entire image with the provided color. Here's an example using the Codex interpreter in Terminus.



In this example TBundle is a class that collects the graphics state used in drawing calls, including fill color, frame color, pen size, pen style, end-cap style, and color operations. The TColor class is constructed with red, green, and blue values in the range 0.0 to 1.0, inclusive. The final Draw call is a predefined Codex function that explicitly adds the provided image to the console stream.

Besides its usage as a drawing medium, TImage offers some helpful methods. A static constructor, TImage::ConstructFromPartialImage, taking a source location (TPoint) and a size (TPoint), allows portions of images to be copied. There are routines to support the seedfill algorithm (used in implementing the bucket or wand in a paint program) as well as routines for resizing, changing the canvas size, flipping or rotating (by increments of 90º) the image, and blending the image with colors or other images. There are methods for accessing pixels, including some dangerous ones that allow the image memory to be modified directly. It is perhaps a somewhat eccentric class, but it's incredibly handy.

One thing I did not try to put into TImage is arbitrary image rotation. It hard to predict what the needs of the rotation will be without the context of the operation. It's also easy enough to rotate images by using a matrix during the drawing process from one image to another, whereupon the desired effect can be completely controlled.

Finally, there are calls elsewhere in the Guildhall toolbox to convert images to and from various host file types, notably png files. These calls rely heavily upon host conversion facilities and thus may be somewhat host dependent.

TGraph

The companion class to TImage is the graphics collection object, TGraph. Because it also subclasses from AGraphicsPort it provides all the drawing methods as expected. Instead of resolving any of the calls, it merely records them in order, capturing all of the state, including clipping, used in each call. Here's the same example from earlier, this time targeting a TGraph.



Unlike TImage, where the size is usually defined in the constructor, TGraph has no size until something is drawn into it. So the first step is to mimic the size of the earlier image by drawing a rectangle of the same size and color as the starting point of the graph. The final Draw call is another predefined Codex function, this one taking a TGraph parameter.

As of now (August 2021) I have just begun adding changes to the TGraph class to make its instances editable. I want it to serve as the data type for Guildhall's nascent Draw applet. This will be handy when I finally get around to deconstructing host side pdf clippings. Ultimately I also plan to target host side svg files for both import and export. Those will be useful in a number of future plans.

Abstract Classes

  • AGraphicsPort

Constructible Classes

  • TImage
  • TGraph

 

Copyright © 1981-2021 Arthur W Cabral. All Rights Reserved. All referenced trademarks are the property of their respective owners. This site does not use cookies. This site does not collect visitor information. The ISP hosting this site collects statistics regarding visitors to this site as part of the normal operation of the website. We do not currently examine those statistics. If that changes, this notice will change. Mac and macOS are registered trademarks of Apple, Inc.