CHAPTER 5 Working with QuickDraw
And now, on to the oldest, cruftiest, yet cant-live-without-it-iest part of QTJ: QuickDraw. QuickDraw is a graphics API that can be traced all the way back to that first Mac Steve Jobs pulled out of a bag and showed the press more than 20 years ago. You knowback when Mac supported all of two colors: black and white.
Dont worry; its gotten a lot better since then.
To be fair, a native Mac OS X application being written today from scratch probably would use the shiny new "Quartz 2D" API. And as a Java developer, the included Java 2D API is at least as capable as QuickDraw, with extension packages like Java Advanced Imaging (JAI) only making things better.
The real advantage to understanding QuickDraw is that its whats used to work with captured images (see Chapter 6) and individual video samples (see Chapter 8). It is also a reasonably capable graphics API in its own right, supporting import from and export to many formats (most of which J2SE lacked until 1.4), affine transformations, compositing, and more.
Getting and Saving Picts
If you had a Mac before Mac OS X, you probably are very familiar with picts, because they were the native graphics file format on the old Mac OS. Taking screenshots would create pict files, as would saving your work in graphics applications. Developers used pict resources in their applications to provide graphics, splash screens, etc.
Actually, a number of tightly coupled concepts relate to picts. The native structure for working with a series of drawing commands is called a Picture actually. This struct, along with the functions that use it, are wrapped bythe QTJ class quicktime.qd.Pict. Theres also a file format for storing picts, which can contain either drawing commands or bit-mapped imagesfiles in this format usually have a .pct or .pict extension. QTJs Pict class has methods to read and write these files, and because its easy to create Picts from Movies, Tracks, GraphicsImporters, SequenceGrabbers (capture devices), etc., its a very useful class.
How do I do that?
The PictTour.java application, shown in Example 5-1, exercises the basics of getting, saving, and loading Picts.
Example 5-1. Opening and saving Picts
package com.oreilly.qtjnotebook.ch05;
import quicktime.*;
import quicktime.app.view.*;
import quicktime.std.*;
import quicktime.std.image.*;
import quicktime.io.*;
import quicktime.qd.*;
import java.awt.*;
import java.io.*;
import com.oreilly.qtjnotebook.ch01.QTSessionCheck;
public class PictTour extends Object {
static final int[ ] imagetypes =$N202-1677793-2715858;
static int frameX = -1;
static int frameY = -1;
public static void main (String[ ] args) {
try {
QTSessionCheck.check( );
// import a graphic
QTSessionCheck.check( );
QTFile inFile = QTFile.standardGetFilePreview (imagetypes);
GraphicsImporter importer =
new GraphicsImporter (inFile);
showFrameForImporter (importer,
"Original Import");
// get a pict object and then save it
// then load again and show
Pict pict = importer.getAsPicture( );
String absPictPath = (new File ("pict.pict")).getAbsolutePath( );
File pictFile = new File (absPictPath);if (pictFile.exists( ))
pictFile.delete( );
try { Thread.sleep (1000); } catch (InterruptedException ie) { }
pict.writeToFile (pictFile);
QTFile pictQTFile = new QTFile (pictFile);
GraphicsImporter pictImporter =
new GraphicsImporter (pictQTFile);
showFrameForImporter (pictImporter,
"pict.pict");
// write to a pict file from importer
// then load and show it
String absGIPictPath = (new File ("gipict.pict")).getAbsolutePath( );
QTFile giPictQTFile = new QTFile (absGIPictPath);
if (giPictQTFile.exists( ))
giPictQTFile.delete( );
try { Thread.sleep (1000); } catch (InterruptedException ie) { }
importer.saveAsPicture (giPictQTFile,
IOConstants.smSystemScript);
GraphicsImporter giPictImporter =
new GraphicsImporter (giPictQTFile);
showFrameForImporter (giPictImporter,
"gipict.pict");
} catch (Exception e) {
e.printStackTrace( );
}
}
public static void showFrameForImporter (GraphicsImporter gi,
String frameTitle)
throws QTException {
QTComponent qtc = QTFactory.makeQTComponent (gi);
Component c = qtc.asComponent( );
Frame f = new Frame (frameTitle);
f.add (c);
f.pack( );
if (frameX = = -1) {
frameX = f.getLocation( ).x;
frameY = f.getLocation( ).y;
} else {
Point location = new Point (frameX += 20,
frameY += 20);
f.setLocation (location);
}
f.setVisible (true);
}
}
W A R N I N G
The two Thread.sleep( ) calls are here only as a workaround to aproblem I saw while developing this examplereading a file Id just written proved crashy (maybe the file wasnt fully closed?). Because its unlikely youll write a file and immediately reread it, this isnt something youll want or need to do in your code.