Newton 2.x Q&A Category: Drawing and Graphics

Copyright © 1997 Newton, Inc. All Rights Reserved. Newton, Newton Technology, Newton Works, the Newton, Inc. logo, the Newton Technology logo, the Light Bulb logo and MessagePad are trademarks of Newton, Inc. and may be registered in the U.S.A. and other countries. Windows is a registered trademark of Microsoft Corp. All other trademarks and company names are the intellectual property of their respective owners.


For the most recent version of the Q&As on the World Wide Web, check the URL: http://www.newton-inc.com/dev/techinfo/qa/qa.htm
If you've copied this file locally, click here to go to the main Newton Q&A page.
This document was exported on 7/23/97.

Drawing and Graphics


Drawing Text on a Slanted Baseline (9/15/93)

Q: Is it possible in the Newton OS to draw text on a slanted baseline? I don't mean italics, but actually drawing a word at a 45 or 60 degree angle and so on. For example, can text be drawn along a line that goes from 10,10 to 90,90 (45 degrees)?

A: The drawing package in the Newton OS supports no calls for rotating text. Note: this is like QuickDraw in the MacOS operating system. In MacOS, the workaround is to draw the text into a bitmap and then rotate the bits; you can do the same on a Newton device. In the Newton OS, we even provide calls to rotate a bitmap in 90 degree increments.

You might consider creating a font having characters that are pre-rotated to common angles (such as 30 or 45 degrees) so that applications could just draw characters rather than actually having to rotate a bitmap.


LCD Contrast and Grey Texture Drawing (11/10/93)

Q: An artist working with me did a wonderful job rendering a 3D look using several different dithered grey textures. The problem is that when her image is displayed on a Newton display everything on the screen dims. Is it possible that the image causes too much display current to maintain contrast?

A: What you're seeing is a well-known problem with LCD displays, and there's not a lot you can do about it. It's especially aggravated by large areas of 50% dithered gray (checkerboard) patterns, but the light gray and dark gray patterns also cause some of it.

The user interface of the Newton OS deliberately avoids 3-D styling and 50% dithered grays as much as possible for this reason. If you know your application is going to display large gray areas, you can adjust the contrast yourself on some hardware devices. There's a global function, SetLCDContrast, to do just that. However, changing the contrast with no end user control is not considered a good user-interface practice.


Destination Rectangles and ScaleShape (3/11/94)

Q: What is a valid destination rectangle for the 2nd argument to ScaleShape?

A: The destination rectangle must be at least 1 pixel wide and 1 pixel high. Each element of the bounds frame must have values that fit in 16 bits, -32768...32767. 0-width/height and negative width/height bounding boxes may appear to work in some cases, but are not supported.


How to Rotate Bitmaps Left (3/5/96)

Q: When I rotate a bitmap left using MungeBitmap, it sometimes shifts the data. How can I rotate left correctly?

A: There is a bug in the Newton 2.0 OS that manifests when the row size of the unrotated bitmap is not an even byte boundary. The result can be a shift of data up to 7 pixels.

You can work around this bug most efficiently by replacing the left rotation with three calls to MungeBitmap using these operations: 'flipHorizontal, 'flipVertical, and 'rotateRight. ('rotateRight three times will work as well, but it is less efficient bacause flips are faster than rotates.)

Remember: "Three Rights (or Two Flips and a Right) Make a Left".


Newton Bitmap Formats (5/14/96)

Q: What is the format for bitmap binary objects in the Newton OS?

A: There are several bitmap formats used in the Newton OS. The Newton OS provides routines for creating and manipulating bitmaps at runtime, and uses other formats for displaying bitmaps from developer packages.

If you want to create a bitmap object at compile time, below is a description of the format of a simple bitmap object. If you want to create a bitmap at run time, we strongly encourage you to use MakeBitmap and copy data into the bitmap.

Simple Bitmaps

Normally, bitmaps are created at compile time using Newton Toolkit picture editors or functions (for example, GetPICTAsBits). If you want to create bitmaps dynamically at compile time, you can create a simple bitmap object with the following format.

Warning: Different formats may be used by images or functions in future ROMs. This format will still be supported for displaying images. This format does not describe images created by other applications nor any images provided or found in the Newton ROM. You can use the following format information to create and manipulate your own bitmaps -- preferably at compile time:

{
    bounds: <bounds frame>,
    bits:   <raw bitmap data>,
    mask:   <raw bitmap data for mask - optional>
}

    Binary object <raw bitmap data> - class 'bits
    
    bytes    data-type  descr
    0-3      long       ignored
    4-5      word       #bytes per row of the bitmap data
                        (must be a multiple of 4)
    6-7      word       ignored
    8-15     bitmap     rectangle - portion of bits to use--see IM I
    8-9      word       top
    10-11    word       left
    12-13    word       bottom
    14-15    word       right
    16-*     bits       pixel data, 1 for "on" pixel, 0 for off


The bitmap rectangle and bounds slot must be in agreement regarding the size of the bitmap.

MakeBitmap Shapes

If you want to create bitmap data at run time or extract bitmap data from a bitmap created with the MakeBitmap global function, use the GetShapeInfo function to get the bitmap and other slots required to interpret the meaning of the bitmap created by MakeBitmap.

Warning: the following information applies only to bitmaps of depth 1 (black and white bitmaps) created by your application with MakeBitmap. Do not rely on GetShapeInfo or the following slots for images created by other applications, images stored in the Newton ROM, images created with functions other than MakeBitmap, nor images with a depth other than 1.

If you created a bitmap using MakeBitmap of depth 1, the return value of GetShapeInfo contains frame with information you can use to interpret the bitmap data.

This frame includes a bits slot referencing the bitmap data for the bitmap. This bitmap data can be manipulated at run time (or copied for non-Newton use), using other slots in the return value of GetShapeInfo to interpret the bitmap binary object: scanOffset, bitsBounds, and rowBytes. For instance, the first bit of the image created with MakeBitmap can be obtained with code like:

   bitmapInfo := GetShapeInfo(theBitmap);
   firstByte := ExtractByte(bitmapInfo.bits, bitmapInfo.scanOffset);
   firstBit := firstByte >> 7; // 1 or 0, representing on or off


Note that rowBytes will always be 32-bit aligned. For instance, for a bitmap with a bitsBounds having width 33 pixels, rowBytes will be 8 to indicate 8 bytes offsets per horizontal line and 31 bits of unused data at the end of every horizontal line.


Difference Between LockScreen and RefreshViews (1/15/97)

Q: In the NPG, it states that sending a view the view:LockScreen(nil) message forces an "immediate update". How is this different from calling RefreshViews?

A: When you post drawing commands (for example, DrawShape) the system normally renders the shape on the screen immediately. :LockScreen(true) provides a way to "batch up" the screen updates for multiple drawing calls. Sending :LockScreen(nil) "unplugs" the temporary block that has been placed on the screen updater, causing all the batched drawing changes to be rendered on the LCD.

RefreshViews tells the system to execute the commands needed to draw every view that has a dirty region. You can think of it as working at a level "above" the screen lock routines. When you send the message Dirty, it does not immediately cause the system to redraw the dirtied view, instead it adds the view to the dirty area for later redrawing.

You could lock the screen, dirty a view with a SetValue, call RefreshViews (and not see an update) draw a few shapes, and then, when you unlock the screen, the refreshes to the dirty regions and your shapes will all appear at once.

A bit more detail on the interaction between LockScreen and RefreshViews:
1. Does LockScreen(nil) result in a RefreshViews?

No. LockScreen(true) just stops the hardware screen from updating from the offscreen buffer. LockScreen(nil) releases that lock which usually causes the hardware screen to update soon thereafter.

2. While the screen is locked, will SetValues draw into the offscreen buffer?

SetValue doesn't draw. Otherwise, see 1.

3. While the screen is locked, what is the result of calling RefreshViews?

It will draw any dirty views into the offscreen buffer.


Drawing White Text on a Filled Background (1/15/97)

Q: I tried using vfFillWhite and kRGB_0 but neither seems to work. How do I draw white text?

A: kRGB_White has some unusual behavior. If you want a white-on-black effect then you will need to use one of two workarounds:

For white text on a filled background using a style frame, set your background to the desired shade using either the fill color of the view or a filled object (in other words, do not do this just by setting the color fill of the text). Then use the textPattern slot in the style frame to make the text black (kRGB_Black) and set the transferMode to modeBic.

For white text on black using the color slot of the viewFont frame, use kRGB_Gray1 for something that is as close to white as you can get.


Interaction Between Transfer Modes and Gray Patterns (1/15/97)

Q: How do the transfer modes interract with the new gray shades in Newton OS 2.1?

A: Here is how the transfer modes interact with images. Colors are determined by looking up the value in the color table. For instance, white means that the indexed pixel value is white in the color table. All the NOT modes operate on the values from the color table. In other words, the pixel value is looked up before the NOT is applied.

When the source and destination are different bit depths, the source is effectively expanded or shrunk to match the depth of the destination bitmap prior to drawing. When expanding, the index into the color table's bit pattern is repeated to fill the destination pixel. For instance, a 2-bit index of 0x1 (binary 01) is expanded to 0x3 (binary 0011) for 4 bits, while a 2-bit index of 0x2 (binary 10) is expanded to 0xC (binary 1100).

modeOr - Replaces pixels under the non-white part of the source image with source pixels. If the source pixel is white, the destination pixel is unchanged.

modeXor - Inverts pixels under the non-white part of the source image. Destination pixels under the white part of the source image are unchanged. This actually XORs the values in the source and destination pixels. For example, for destination of 0xA (75% grey), source 0x0 (white) produces result 0xA (unchanged). Source 0xF (black), produces result 0x5 (25% grey, or inverted). Source pixels of other values have less utility. For example, source 0x5 (25% grey) produces result 0xF (black), while source 0xA (75% grey) produces result 0x0 (white), and source 0x3 (50% grey) produces result 0x9 (slightly less than 75% grey).

modeBic - Erases screen pixels under the non-white part of the source image, making them all white. Destination pixels under the white part of the source image are unchanged. This actually, does a bitwise NOT, so it is really only useful when source pixels are either 0 (white) or 0xF (black). With other values, weird things happen, For example, destination 0xF with source 0xA produces result 0x5. Destination 0x0 with source 0xA produces result 0x0. Destination 0x3 with source 0xA produces result 0x1.

modeNotCopy - Replaces screen pixels under the black part of the source image with white pixels. Screen pixels under the white part of the source image are made black.

modeNotOr - Screen pixels under the black part of the source image are unchanged. Screen pixels under the white part of the source image are made black.

modeNotXor - Screen pixels under the black part of the source image are unchanged. Screen pixels under the white part of the source image are inverted.


Limitations of GrayShrink (3/4/97)

Q: Why isn't GrayShrink doing what I want it to when I use it with relatively small bitmaps?

A: GrayShrink was designed for rendering relatively large images such as received faxes into a moderately large part of a Newton display. It works by setting a flag in the bitmap that tells the imager to gather multiple bits from the source bitmap and turn them into a single gray pixel when drawing through a reducing transform.

If passed a bitmap that is more than one bit deep, the shrinking algorithm is not appropriate and so GrayShrink will not modify the bitmap. The end result will be a transformed (shrunk) image with the same bit depth as the original. That is, the shrinking will still happen, but the graying won't.

GrayShrink will not work with read-only bitmaps (it is unable to set the flag.) The result will still be a transformed (shrunk) image, but pixels will not be combined to gray. There is no way to clear the flag once it has been set. After GrayShrink has modified a bitmap, drawing it to the screen through any scaling transform that reduces the image will produce a pixel combined gray result.

The GrayShrink pixel gathering algorithm produces an anomaly along the righthand side of the reduced image. When rendering large bitmaps into a reasonably large destination, this is generally uunnoticeable. However, when used with small source bitmaps or when rendering into a small area, several columns along the right side of the result may not be drawn, and the anomaly is easily seen. We recommend using GrayShrink and the 'drawGrayScaled setting for protoImageView only for large source images such as incoming faxes or scanned data.


Limitations of MungeBitmap (4/3/97)

Q: When I use MungeBitmap to flip or rotate a grayscale image, it gets corrupted. What's wrong?

A: MungeBitmap does not properly handle bitmaps with a depth greater than 1. You can work around this problem by using kMungeBitmapFunc, which has the same calling conventions and return value as MungeBitmap. kMungeBitmapFunc is provided in the Newton 2.1 Platform file, version 1.2b1 or later.

Calling MungeBitmap with the 'rotateLeft, 'rotateRight, or 'flipHorizontal options will trigger the bug. The 'rotate180 and 'flipVertical arguments to MungeBitmap work correctly with deeper bitmaps.

Note that with the Newton 2.1 OS release in the [English language] Apple MessagePad 2000 and Apple eMate 300 products, the built-in Drawing stationery in NewtonWorks exhibits this bug when rotating gray bitmaps.


NEW: Leave Extra Space for Text When Printing (5/7/97)

Q: I use text height/width functions to determine the exact size to make text for printing/faxing , but sometimes text still gets clipped. What's wrong?

A: Text height/width functions are guaranteed to be accurate only for on-screen use, and so the text may not actually fit in the bounds box you created for the text. This is true whether you draw the text using text shapes or try to create views of "minimal" size for the text. The exact bounds will usually be close to the bounds returned by functions like TextBounds and StrFontWidth, but those values may be too small to fit.

Some of this problem is due to inherent ambiguities in PostScript font substitution (for PostScript-based Apple LaserWriters.) Some of this problem is due to ROM problems in font scaling for raster/bitmap printers (including fax) at resolutions that are not 72 DPI.

To work around this problem, be as liberal as possible when designing the bounds for your text, using view justification as appropriate.

If you do not need a frame around your text or special calculations about text size, we recommend making your view or text shape as large as possible. For instance, a centered page number at the bottom of the page could be a text view that is justified with "parent full horizontal" justification with centered text. Or, it could be a text shape that is very large (as wide as the page -- use :LocalBox() to find out) and use center justification in a style frame passed to :DrawShape(...).

If you wanted a frame or border around your text, or have some other reason for wanting to know the exact size, use the font width/height functions and then add some space to the text bounds. As a guideline, adding 6% to the width/height when printing should be enough space to account for these problems. We recommend you experiment with different printers and page sizes (in the Locale preferences) to ensure that the "extra space" is enough for your text items.

Note: there is an unrelated text printing bug in the MessagePad 2000 and eMate 300 devices that in some circumstances will clip parts or entire characters, occasionally preventing small text strings from printing entirely. As of 7/16/97, this bug is fixed for the MessagePad 2000 in System Update "MessagePad 2000 2.1 (717041)US", but is not yet fixed on the eMate 300.