Graphic and Window Documents

A graphic document is where all drawing occurs, whether that is drawing an image, drawing a graphic shape or applying an image filter. A window document is a graphic document that has a window. All properties or events that a graphic document can handle can be handled by a window document. The only extra functionality that a window document provides are window specific related properties. In all cases when a graphic document is referred to in this documentation any description applies to window documents as well.

iMagine Photo is less efficient when dealing with a window document than a graphics document because all drawing is applied to the graphic documet offscreen graphics world, and only when the drawing is finished does iMagine Photo copy the bits to the window. Nearly all of the iMagine Photo documentation examples create a window document rather than a graphics document because for demonstration purposes a script with visual feedback is more descriptive. Production scripts should nearly always create a graphic document. The following line creates a window document called My new window:

The following line creates a new graphic document called My new graphic document:

set thisDocument to make new graphic document with properties {dimensions:{640, 480}, name:"My new graphic document"}

Window documents are a subset of graphic documents. This means that if you are iterating through the list of graphic documents you will find all the window documents as well, but if you are iterating through the list of window documents you will not find graphic documents.

Whenever a graphic document is created, an associated graphic exporter is automatically created. This graphic exporter becomes part of the graphic document, so all graphic exporter properties and commands have to applied to the graphic document. When exporting the contents of a graphic document to a file there is no cropping or scaling functionality. This means that the graphic document needs to be created with the dimensions that you want the final image file to have.

The following line shows you how to obtain the dimensions of a graphic document.

set theDims to the dimensions of thisDocument

You can set and obtain the graphic document name using the name property.

The following script imports a graphic file and scales it by half and draws it to a window document. Panther users can open the following script in a new Script Editor window by clicking here.

set thisFile to choose file with prompt "Choose an image file to scale by half: "
tell application "iMagine Photo"
  
set thisImporter to import graphic thisFile
  
if component error of thisImporter is not equal to 0 then
    
close thisImporter
    
display dialog "Could not open: " & name of (info for thisFile)
    
return
  
end if
  
set {x, y, xDim, yDim} to the natural bounds of thisImporter
  
set thisDocument to make new window document with properties {dimensions:{xDim div 2, yDim div 2}}
  
set the scale of thisImporter to {0.5, 0.5}
  
set the top left point of thisImporter to {0, 0}
  
set the drawing destination of thisImporter to thisDocument
  
draw thisImporter
  c
lose thisImporter
end tell

If you are exporting your image in a file format that has an alpha channel so that you can produce images with transparency information, this is done using the write only property alpha channel. For the documentation on how to use this command see the transparency section.

The create composition element command applies to the graphic document. The create composition element command is used for all shape drawing and applying of filter effects. Using the create composition element command is fully described on the drawing shapes page with further information on the applying filter page. A full description of all the different types of composition elements that can be created is described on the composition element 2 page and common properties of composition elements are described on the composition element 1.

There are two further commands that apply to graphic documents. These are get pixel values, and get bad pixels. The get pixel values command obtains pixel values from the graphic document. The location of the pixels is defined by the pixel value class. The pixel value class is one of pixels at points, pixels on line, pixels in rectangle, pixels in polygon, and pixels in oval.

Depending on the value of pixel value class, extra information in the get pixel values record is required. For pixels in rectangle and pixels in oval, both require the bounds rectangle to be defined, for pixels on line then start point and end point are required, for pixels in polygon then poly points are required. For pixels at points, then pixel points are required. See the following scripts for a few examples on how to get pixel information.

The first script gets the pixel values for a rectangle 20 by 20 pixels in the middle of the picture. The get pixel values command returns two lists, a list of pixel points {horiz, vertical} and a list of pixel colors {red, green, blue}. This script leaves the result in the results view of Script Editor. On Panther or higher you can open this Apple Script in a new Script Editor window by clicking here.

set thisFile to choose file with prompt "Choose an image file: "
tell application "iMagine Photo"
  
set thisImporter to import graphic thisFile
  
if the component error of thisImporter is not equal to 0 then
    
close thisImporter
    
display dialog "Not an image file that quicktime recognizes."
    
return
  
end if
  
set {x, y, xDim, yDim} to the natural bounds of thisImporter
  
set thisDocument to make new window document with properties {dimensions:{xDim, yDim}}
  
set the drawing destination of thisImporter to thisDocument
  
draw thisImporter
  
close thisImporter
  --
The following section is to be replaced depending on the pixel value class
  set halfXDim to (xDim / 2) as integer
  
set halfYDim to (yDim / 2) as integer
  
set pixelValueRect to {halfXDim - 10, halfYDim - 10, halfXDim + 10, halfYDim + 10}
  
set pixelValues to get pixel values of thisDocument with properties {pixel value class:pixels in rectangle, bounds rectangle:pixelValueRect}
  --
end section for replacing.
  
close thisDocument
end tell
pixelValues

It should already be clear that this command can produce large amounts of data. The small 20 by 20 rectangle contains 400 pixels resulting in over 8000 bytes being transferred from iMagine to the script. If you attempted this for a rectangle that contained a 1 megapixel image then around 20 MBytes of data would be copied from iMagine to the Apple Script which is quite slow. The script below replaces the content in the section marked for replacing in the script above and gets the pixel values along a horizontal line passing through the middle of the image.

set halfYDim to (yDim / 2) as integer
set pixelValues to get pixel values of thisDocument with properties {pixel value class:pixels on line, start point:{0, halfYDim}, end point:{xDim, halfYDim}}

On Panther or higher the complete script can be opened in a new Script Editor window by clicking here.

The get bad pixels command allows you to provide some simple rules for detecting pixels that are significantly different to adjacent pixels. Each rule creates a list of rectangles that contain the bad pixels, and adds its list of rectangles to the list of rectangles calculated by the previous rules. If rectangles interestect then they are combined. Diagonal lines can be problematic if the rules are too loose as a rectangle grows to contain the diagonal line it contains. This command can take some time and the command slows down depending on the number of rectangles that it creates. The command can obviously be used for more than detection of bad pixels, but I developed it for picking up the pixels in my digital camera that have a high noise level.

For a single rule the command looks like the following:

set badPixelRects to get bad pixels using rules {{adjacent to:2, different by:35000, color channels:blue channel, bounds rectangle:boundRect}}

The adjacent to property is the number of pixels adjacent to the pixel in question that have to be different to the pixel in question by different by amount (pixel values range from 0 to 65535). The color channel property specifies the color that you want to detect bad pixels against, and can be one of: red channel, blue channel, green channel, or average of where average of is the average of the three color channels. The bounds rectangle property is the rectangle that you want to search for bad pixels within. Pixels at the edge of the image will not be detected as a bad pixel.

The following script will look for bad pixels in the top right 500 X 500 rectangle of the image using 4 rules, one each for each color plus one average rule. The script then draws red rectangles around the detected results. On Panther the script can be opened in a new Script Editor window by clicking here.

set thisFile to choose file with prompt "Choose an image file to draw scaled by half: "
tell application "iMagine Photo"
  
set thisImporter to import graphic thisFile
  
if component error of thisImporter is not equal to 0 then
    
close thisImporter
    
display dialog "Could not open: " & name of (info for thisFile)
    
return
  
end if
  
set {x, y, xDim, yDim} to the natural bounds of thisImporter
  
set xDimDiv2 to xDim div 2
  
set yDimDiv2 to yDim div 2
  
set thisDocument to make new window document with properties {dimensions:{xDim div 2, yDim div 2}}
  
set the scale of thisImporter to {0.5, 0.5}
  
set the top left point of thisImporter to {0, 0}
  
set the drawing destination of thisImporter to thisDocument
  
draw thisImporter
  
close thisImporter
  
if xDimDiv2 is greater than 500 then set xDimDiv2 to 500
  
if yDimDiv2 is greater than 500 then set yDimDiv2 to 500
  
set boundRect to {0, 0, xDimDiv2, yDimDiv2}
  
with timeout of 300 seconds
    
tell thisDocument
      
set badPixelRects to get bad pixels using rules {{adjacent to:2, different by:35000, color channels:blue channel, bounds rectangle:boundRect}, {adjacent to:4, different by:30000, color channels:average of, bounds rectangle:boundRect}, {adjacent to:5, different by:20000, color channels:red channel, bounds rectangle:boundRect}, {adjacent to:7, different by:15000, color channels:green channel, bounds rectangle:boundRect}}
    
end tell
  
end timeout
  
repeat with i from 1 to the count of badPixelRects
    
tell thisDocument to create composition element with properties {class:framed rectangle, bounds rectangle:(item i of badPixelRects), color:{65535, 0, 0}}
  
end repeat
end tell

The above script is written to demonstrate the range of functionality available. But to detect bad pixels from a camera it is more likely that there would be one rule for each color component, and adjacent to and different by would be the same for each rule.

If like me you have taken pictures with your digital camera in low light conditions without having turned noise reduction on, then it may be possible for me to write a script for you that will remove the noise (for a small fee). It will be necessary for you to send me a few of your pictures that you would want to have fixed up. If your digital pictures have a large number of pixels with lots of noise it may not be possible to fix them.

The ability to open scripts in a new Script Editor window is provided by an application called "Convert Script to Markup Code" and can be obtained from http://homepage.mac.com/jonn8/as/

keywords: AppleScript, Apple Script, Macintosh, Mac, Quicktime, quickdraw, quartz.