anastigmatix.net

This document has a standard, validated CSS2 stylesheet, which your browser does not seem to display properly. In a browser supporting web standards, this table of contents would be fixed at the side of the page for easy reference.

anastigmatix home
  • Importing design elements
  • How is Import different?
  • Allow inline or referenced
  • Avoid format preconversion
  • Avoid data and code redundancy
  • Import's approach to images
  • Import: reference
  • Import dictionary contents
  • JPEG and JFIF image import
  • ExecJPEG
  • StatJFIF
  • StatJPEG
  • ReadyJFIF
  • Encapsulated PostScript import
  • BeginEPSF
  • EndEPSF
  • ExecEPSF
  • StatEPSF
  • ReadyEPSF
  • FitEPSF (deprecated)
  • PNG image import
  • ExecPNG
  • StatPNG
  • ReadyPNG
  • PNGmagic
  • PNGchunk
  • PNGkey
  • =PNGkey
  • PNGChunkDecode
  • PNGIDATDecode
  • Utilities
  • csdimension
  • hintrenderintent
  • Import: importing design elements in direct PostScript

    This resource extends PostScript with concise syntax for including and placing, in a PostScript document, design elements in various common file formats. The aim is to take care of the fiddly bits as far as possible while allowing overrides for unusual cases.

    A quick example will show what the necessary code looks like to import an EPS, JPEG/JFIF, or PNG graphic into a document. The example can be viewed either in a PostScript previewer or a text editor, as you may prefer to see what comes out or to read how it is done. It also comes in two flavors: the self-contained file has all the resources it needs included in its prolog, so it will work without prearrangement on any PostScript printer or viewer. On the other hand, if you did this sort of thing a lot, you would probably download or save some of those prolog pieces where your printer or viewer could always find them, and then the bare file would work just as is. (There's more about downloading resources in the reference section.)

    Bare file Self-contained file
    EPS, JPEG/JFIF, and PNG demo PostScript view
    text view
    PostScript view
    text view
    PDF view
    EPS-printing header text view text view

    The second example is a simple header that can be prepended to any EPS file and sent to a printer, causing the EPS file to print. It will work even with a DOS-format, binary-preview EPS, as long as the communication channel to the printer is transparent to binary data. It's here just because there's been an entry in the wikibooks PostScript FAQ for about two years now saying this could be done with a simple header but not providing an example. Here's one now. It has no PostScript or PDF view, as there is nothing to see until it is prepended to some EPS file.

    Note: The PNG code in the first example requires PostScript LanguageLevel 3. If you download the example as a text file and remove the PNG portions, it will run on LanguageLevel 2 devices.

    How is Import different?

    To the user of some PostScript-emitting application program, the details of how imported items get worked into the PostScript output usually stay under the hood. The details are similar, for most applications. Decoding of various file formats will be done in the application itself, which reads an imported file and writes some translated version of it into the PostScript output. In the process, the application program learns certain vitals about the imported file, for example its dimensions and color depth. The application program determines how the PostScript graphics state should be set up to place the item properly, and just ahead of the translated item it emits code to handle the set-up—often half a screenful of open-coded PostScript boilerplate with a few values changed.

    That may be tolerable for application-generated PostScript that no human is expected to look at, but it's not an inviting way to ask people to write direct PostScript. The usual goal for humans writing programs is to abstract out common code sequences and minimize redundancy and visual clutter so code is less tedious to write, understand, and maintain. Looking at some aspects of the usual application-generated style, and how they complicate direct PostScript composition, will motivate the aims of this resource—which, while developed with direct PostScript in mind, can certainly be used by PostScript-emitting applications to simplify their output as well.

    Allow files to be inlined or referenced

    Applications generally emit the contents of imported files inline in the PostScript output. Inlining is ultimately necessary to arrive at a self-contained PostScript file that can be sent anywhere, but only gets in the way while editing PostScript by hand. During editing, it is more convenient to use previewing software on a computer and keep the included items as separate files. The main PostScript source being edited only needs a PostScript file operator at each point an import is needed, to refer to the file by name.

    An example below shows a handy way to organize the code so that the file name and code to open it make a distinctive line that can be replaced with the inlined file contents later by a simple script, and nothing else needs to be changed.

    Avoid format preconversion

    Applications generally translate imported files from their original format into some converted form to be inlined into the PostScript output, rather than using PostScript code to interpret the original form. That choice has several disadvantages for direct PostScript, and at least some are disadvantages even for generated code:

    Appropriateness of representation
    Usually the original format of a file to be imported was chosen for its appropriateness to the type of content. For example, a typical photographic image is well suited to JPEG coding. Conversion to some alternate form may inflate the size for storage and transmission by a factor of 10 or even 20.
    Distance from form of choice for creation/editing
    The converted form inlined into PostScript by typical applications may not be directly editable by the usual tools for working with illustrations or images. Even if the converted form follows Encapsulated PostScript (EPS) conventions and some tools can load it as EPS, they may not be able to manipulate it as capably as the original form. So, the converted form is likely kept in addition to the original form, and regenerated whenever the original is edited, adding a step.
    Irreversible transformation
    Related to the last point is the information loss that may be incurred by conversion. It is often impossible to reconstruct the original from the converted form. Obvious examples of lost information include metadata the original file may contain, such as source, copyright, and dimensions, but the loss can involve more than metadata. If a JPEG image has been converted, for example, it cannot be reconstructed from the converted form without another generational loss of image quality.
    Reliance on specialized programs
    This point is no disadvantage in the case of a PostScript-generating application—it is the specialized program—but it is a disadvantage when writing direct PostScript. In addition to a text editor, PostScript previewer, and shell, it becomes necessary to accumulate specialized programs like pnmtops for munging files into the preconverted form.

    The alternative of simply using pure PostScript to interpret common file formats directly avoids all four problems. Files to be imported can be maintained in the most appropriate format at all times: the file created and edited is the file to be used in the PostScript document. While a direct PostScript document is being written, the points of import in the code need only reference the imported files by name. Later, the files can be inlined into the document. The inlining needs no format conversion beyond perhaps ASCII85 armoring, which is nothing but a PostScript one-liner that can be run in the previewer and requires no other program, regardless of the type of the imported file. ASCII85 is a completely reversible transformation from which the exact original file can be recreated at any time, again with a simple line of PostScript.

    Naturally, the approach can only be taken so far. Image formats such as JPEG and PNG have variants that are harder to support in pure PostScript; progressive or interlaced rendering is an example. So, it can be necessary to convert some files from difficult to simpler variants of their own format, as for example the jpegtran utility can losslessly do for JPEG images. But even so, the file remains in an appropriate, standard, easily-edited form.

    Avoid redundancy of data and code

    Some existing tools have already addressed the problems inherent in format conversion; an example is jpeg2eps, one of several tools that wrap a JPEG/JFIF, without recoding, in the form of an EPS file. The table below compares the code emitted by jpeg2eps with what you might write using Import to place the same image. The second column also shows what you might write with Import if the image is in a separate file instead of inlined:

    jpeg2epsImport
    124 169 scale 
    /DeviceRGB setcolorspace 
    <<  % ears4to6.eps 
       /ImageType 1
       /Decode [ 0 1 0 1 0 1 ]
       /Width 124 
       /Height 169 
       /ImageMatrix [ 124 0 0 -169 0 169 ] 
       /BitsPerComponent 8 
       /MultipleDataSources false 
       /Interpolate false 
       /DataSource currentfile 
          /ASCII85Decode filter 
          /DCTDecode filter 
    >>
    image 
    s4IA0!"_al8O`[\!<E0s!)NXqs4[N@!"]MH...
    #lC%&lAV]~>
    % separate file:
    {
      gsave
      StatJFIF pop ReadyJFIF pop pop ExecJPEG
      grestore
    }
    (ears4to6.jpg) (r) file exch exec
    
    
    % inlined:
    {
      gsave
      StatJFIF pop ReadyJFIF pop pop ExecJPEG
      grestore
    }
    currentfile /ASCII85Decode filter exch exec    
    s4IA0!"_al8O`[\!<E0s!)NXqs4[N@!"]MH...
    #lC%&lAV]~>

    Several comparisons can be made, but the one for the moment is redundancy. Most of the information in the PostScript code emitted by jpeg2eps is either unchanging boilerplate or repeats information contained in the image file itself, such as its width and height in pixels, number of color components, and bits per component. In fact the width appears three times and the height four times in addition to their specification in the image file itself (and not counting the generated EPSF BoundingBox comment not shown in the example). To write or maintain such code by hand is tedious and error-prone: you could not just replace the ASCII85'd image data with an updated version after cropping or resizing the file, without the risk of forgetting to update some of the copies of its dimensions.

    True, as a jpeg2eps user you would not usually do that: if you edited the image, you would not replace only the ASCII85 inline data, but re-run jpeg2eps and paste the complete output again, including the regenerated PostScript code. But besides making you a bit dependent on the jpeg2eps tool, that means that any choices you had made by editing the code, such as to change the scale, set a more appropriate color space, or enable interpolation, will be lost and you will have to restore them by editing the generated code again. Not only is the code verbose, but the approach just isn't very convenient for direct PostScript work.

    With Import, the redundancy is reduced. If you just need to place the image at its natural dimensions with reasonable defaults, the code shown is all you need. If you add any code between ReadyJFIF and ExecJPEG to override any defaults, your choices are left alone when you update the image (and replace just the ASCII85'd data, if you are using the inlined form). StatJFIF picks up any changed parameters directly from the image. You could even add code to use the wx and wy computed by ReadyJFIF, rather than popping them, to adaptively scale and position the image.

    Import's approach to images

    To provide reasonable default behavior easily, while allowing it to be overridden for sophisticated uses, support for an imported graphic type, say FOO, will generally be provided with a sequence of procedures rather than a single one that does everything. Typically, these will be:

    StatFOO
    Obtains the vital statistics of a FOO-type graphic, by reading them out of the file, and returns those statistics and a file object positioned appropriately for later use by ExecFOO, even if the file is inlined.
    ReadyFOO
    Crunches the parameters obtained by StatFOO, without further file access, to set the graphics state appropriately for rendering the graphic, and compute any parameters to be provided to ExecFOO. The caller is able to examine or even modify the statistics obtained by StatFOO before calling ReadyFOO, and may examine or override any of ReadyFOO's computed results or graphics state settings before calling ExecFOO.
    ExecFOO
    Places the imported graphic.

    While that describes the overall pattern, the exact details may vary between graphic types.

    For images, a curious practice sanctioned by the PostScript Language Reference is to construct an ImageMatrix for every image that maps it to the unit square, and then place it with a scale operation that specifies its exact final dimensions. It is an interesting game, and the only winning move is not to play. The first step throws away everything known about the dimensions and aspect ratio, which you then have to replace by obtaining them somehow from the image file, and coding them redundantly in a scale operation.

    The ReadyFOO procedures take a different approach. If the image format specifies physical dimensions, ReadyFOO sets the ImageMatrix so that the image, with no scaling, would have exactly those dimensions given the default PostScript coordinate space. In that case, if you want to scale the image, you can specify a scale factor equal for x and y and relative to the natural size of the image.

    If the image has no specified physical size but the aspect ratio can be determined, ReadyFOO will set the ImageMatrix so that the image just fits in the unit square, but with the correct aspect ratio; that is, its maximum dimension will be 1. In that case you scale with a factor equal in x and y that represents the largest final dimension that you want. Only if the image format does not even define the aspect ratio will ReadyFOO create the old unconditional unit-square mapping.

    In all cases, ReadyFOO will return the dimensions wx wy that its default scaling will produce, so calling code can compute a scale appropriately.

    Import: reference

    Import is a ProcSet resource. To make it available to your own code, include in the setup section of your file:

    /net.anastigmatix.Import /ProcSet findresource
    

    The findresource will succeed, leaving a dictionary on the operand stack, if you have made the Import resource file [download] available in any of these ways:

    Import relies on a few other resources, and you will need those files also. If you use the first method, directly including resources in your file's prolog, the prolog has to contain all of the needed resources, in any order so long as no resource comes before one it depends on, and categories come before resources that belong in them. Any of the other methods should just work as long as all the files are where they need to be. These are the resources you will need:

    ResourceCategoryDescription
    net.anastigmatix.MetaPre ProcSet Staged-programming extensions for PostScript
    net.anastigmatix.filter Category Category to contain filter resources usable with StreamIO.
    DSCDecode net.anastigmatix.filter Filter for scanning DSC-conformant PostScript input.
    net.anastigmatix.StreamIO ProcSet I/O utilities and pure PostScript definable filters.
    net.anastigmatix.BinaryIO ProcSet Utilities for binary I/O
    net.anastigmatix.Import ProcSet EPS and JPEG/JFIF support.
    net.anastigmatix.PNG ProcSet Optional PNG support (LanguageLevel 3 only).

    The resource files are in a compact form. That is for efficiency, not to keep you from viewing them; there is a script for that on the resource packaging page.

    The Import dictionary may be placed on the lookup stack (with begin) for convenient access to the definitions in it, without the bother of get and exec. The dictionary is read-only, so before creating any definitions, you will want either userdict begin or your own dict begin so that you have a writable dictionary on top of the dictionary stack.

    Import dictionary contents

    This section describes the contents of the read-only dictionary that is returned by /net.anastigmatix.Import /ProcSet findresource.

    JPEG and JFIF image import

    The procedures for JPEG/JFIF image import are split to provide sensible default behavior with the opportunity to override defaults when necessary. To render a physically-dimensioned JFIF image at its natural size, assuming default PostScript units, with its lower left corner at the origin, nothing more is needed than:

    gsave (file.jpg) (r) file StatJFIF pop ReadyJFIF pop pop ExecJPEG grestore

    StatJPEG and StatJFIF extract the essential header information from the file (most “JPEG files” are in fact JFIF files, which contain additional header information that StatJFIF picks out). ReadyJFIF uses the stats from StatJFIF to compute several defaults and return the pixel dimensions and image dictionary for ExecJPEG, plus the default dimensions of the image, which the calling program may use to compute a scale. The program may modify any of the defaults set by ReadyJFIF before using ExecJPEG to render the image.

    Only baseline or extended-sequential (SOF0 or SOF1) JPEG images are sure to be supported. An image in an unsupported form such as progressive JPEG can be losslessly munged into baseline form using the jpegtran utility from the Independent JPEG Group, with no arguments.

    There is currently no ReadyJPEG procedure because non-JFIF JPEG files leave many details unspecified so not many defaults could be set. For example, the JPEG header alone has insufficient information to compute the natural image size or aspect ratio, and the JPEG standard does not specify a color space. Therefore, when importing a non-JFIF, JPEG image, the calling program must know more about it, and set more of the graphics state explicitly.

    There is currently no StatExif or ReadyExif procedure to make use of the additional information in an Exif header. Exif files can be handled as generic JPEGs. Exif metadata can specify the color space in about the same ways PNG can. Strictly, the image matrix could be overridden according to the camera orientation, but user-space transformations can be used to get the image the right way up.

    ExecJPEG
    src w h [dict] ExecJPEG

    Renders an image of width w pixels and height h pixels from src, which must be any source acceptable to the DCTDecode filter, such as a baseline JPEG or JFIF stream. The optional dict is the dictionary for the image operator, which may be supplied to override the defaults that ExecJPEG otherwise supplies. If supplied, dict need only contain the entries to be overridden; ExecJPEG will supply the rest from the defaults shown here. ExecJPEG always sets Width and Height, so dict must be writable.

    Image parameterDefault
    ImageType1
    BitsPerComponent8
    ImageMatrix [w 0 0 -h 0 h] to map the PostScript unit square onto the image, with the first scan left to right across the top. This is the order specified by JFIF, but could need to be overridden for an arbitrary non-JFIF JPEG.
    Decode Array containing 0 1 for each dimension of the current color space. Note that this default must be reversed for certain 4-component JPEGs produced by Adobe applications (the symptom if this is overlooked will be that the image appears rendered as a color negative).
    DataSource src /DCTDecode filter. This would only need to be overridden if the DCTDecode filter had to be created with non-default parameters, which should be very rare. The automatic setting of the filter's ColorTransform parameter is the correct behavior for JFIF, but might, in obscure cases, have to be overridden for some arbitrary non-JFIF JPEG. The color transform cannot be overridden here if the image stream contains the Adobe-specific APP14 marker specifying it explicitly.
    StatJFIF
    file StatJFIF file units Xden Yden prec X Y Nf version

    Reads the JFIF header, and the JPEG header using StatJPEG, from the supplied file, returning the file rewound to the original position (this will not be the same file object), the JPEG header information (see StatJPEG), and these JFIF items:

    units
    Interpretation of Xden and Yden:
    unitsInterpretation
    2Pixels per centimeter
    1Pixels per inch
    0 No physical dimension specified. Xden and Yden specify only the aspect ratio of a pixel, which is either Xden/Yden or Yden/Xden: the JFIF 1.02 spec is ambiguous, both interpretations have been used, and it is hard to find any examples of software where the issue isn't just punted completely. On the bright side, as long as the pixels are square the meaning is perfectly clear.
    Xden Yden
    Horizontal and vertical pixel density when units is 1 or 2. Something else if units is zero.
    version
    The JFIF specification version in 16 bits, major number in the high 8, minor in the lower.

    Note that JFIF specifies either 1 or 3 components at 8 bits per component, so values of Nf other than 1 or 3, and values of prec other than 8, will not be seen in strictly-conformant JFIF data.

    A syntaxerror will be signalled if StatJFIF cannot parse the input stream as JFIF.

    StatJPEG
    file StatJPEG file prec X Y Nf

    Reads the JPEG file header from the supplied file, returning the file rewound to the original position (this will not be the same file object), and these image parameters:

    prec
    Bits per component. Only 8 bit components are sure to be supported by the DCTDecode filter.
    X Y
    Horizontal and vertical maximum image dimensions, in pixels.
    Nf
    Number of image components: the dimension of the color space.

    A syntaxerror will be signalled if StatJPEG cannot parse the input stream as JPEG of “baseline” (SOF0) or “extended sequential” (SOF1) type.

    ReadyJFIF
    units Xden Yden prec X Y Nf ReadyJFIF X Y imagedict wx wy

    Ponders the image details extracted by StatJFIF, sets some graphics state defaults, and constructs a default imagedict to override the more generic defaults ExecJPEG would otherwise supply. Returns X Y imagedict as needed by ExecJPEG, as well as wx wy, the default dimensions of the image in default PostScript units, which the caller may use to compute a scale. The caller may change any of the defaults before calling ExecJPEG.

    The default dimensions of the image, and the default ImageMatrix in imagedict, are computed to preserve the original aspect ratio, not to map the image unconditionally from the unit square, so the caller can simply scale equally in x and y to size the image without fear of distortion. If the image has a physical size (units is 1 or 2), the default dimensions are its natural physical size in default PostScript units. In that case any scaling factor used by the calling program is relative to the image's natural size.

    In the case where units is zero, the image has a known aspect ratio but unknown natural size, and the default dimensions will be chosen to fit in the unit square; that is, the maximum of wx and wy will be 1. The calling program must scale it up to the desired size, as in the common practice of mapping every image to the unit square, but again may scale equally in x and y to preserve aspect ratio. Note, however, that the rare combination of units=0 with nonsquare pixels suffers from an ambiguity in the JFIF 1.02 spec, and ReadyJFIF's interpretation may differ from that of other software.

    Depending on whether the image has 1 or 3 components, ReadyJFIF selects the device-independent color space installed as DefaultGray or DefaultRGB in the ColorSpace resource category if possible, or falls back to DeviceGray or DeviceRGB otherwise. If the image has other than 1 or 3 components—which would make it a nonconformant JFIF—ReadyJFIF does not set any color space, and the caller must ensure that a color space with the right number of components has been set.

    If the interpreter is Level 3 or sufficiently recent Level 2 to have a findcolorrendering operator, ReadyJFIF requests a Perceptual rendering intent, most appropriate for general photographic images. The caller may select a different rendering dictionary before calling ExecJPEG. Rendering intents are explained nicely on Sean McHugh's site.

    Encapsulated PostScript (EPS) import

    Import provides procedures BeginEPSF and EndEPSF that perform exactly the tasks of the same-named example procedures in the TN5002 EPSF Specification, but more robustly and without placing temporary clutter in the program's namespace. They genuinely protect the dictionary and operand stacks from the EPS code—and vice versa—by not merely counting them as in the TN5002 examples, but clearing them and restoring them after EPS execution completes. The save object is not accessible to the EPS code. The work is done by ExecEPSF, which is the recommended procedure for new code to use; BeginEPSF/EndEPSF are compatibility interfaces to it.

    A StatEPSF procedure obtains the bounding box from the DSC comments in the EPSF stream.

    A ReadyEPSF procedure computes the clipping rectangle and user-space transformation specified in TN5002, given the bounding box from StatEPSF and desired position, rotation, and scale. The results are a clipproc and matrix to be passed to ExecEPSF.

    StatEPSF and ExecEPSF do not automagically handle EPS files with non-EPSI previews, but BinaryPreviewEPSDecode can be used when necessary to filter the input to StatEPSF. If such a file is to be inlined, the filter can be used at inlining time to include only the PostScript text in the usual way, or the entire binary file can be inlined in ASCII85 and decoded at run time by ASCII85Decode and BinaryPreviewEPSDecode. That would use more space and be a peculiar thing to do, unless there is a reason to preserve the original EPS file exactly.

    The intended use of ExecEPSF is with a file object that reaches EOD at the end of the EPS code. The file object returned by StatEPSF fits the bill.

    BeginEPSF
    BeginEPSF

    Executes ExecEPSF passing currentfile, a procedure that does not change the clipping path, and an identity matrix. The result is as for the example procedure in TN5002: the code following BeginEPSF is executed with cleared dictionary and operand stacks and the normalized graphics state described in the spec. A no-effect entry for showpage, and an entry for EndEPSF, have been placed in userdict. They will be removed by the automatic restore after executing the EPS code. BeginEPSF should be immediately followed by code to set the desired user-space transformation and clipping path, and then the EPS code itself.

    EndEPSF
    EndEPSF

    This name is present in userdict only while executing EPS code preceded with BeginEPSF. It signals the end of the EPS code and causes the saved state of the enclosing program to be restored, which removes this entry from userdict.

    Note that an EPS import might contain EPS imports of its own, and could overwrite this definition of EndEPSF with a different one, such as the example from TN5002. If the imported code only makes that definition after creating a save object in preparation for its own EPS import, then imports will nest properly (the restore after the sub-import will reinstate this definition). However, misbehavior is possible if the imported code overwrites this definition outside of a save. That is why ExecEPSF is recommended for new code.

    ExecEPSF
    file proc matrix ExecEPSF

    Executes Encapsulated PostScript code from file. First the environment is saved and the graphics state normalized as described in TN5002. The operand and dictionary stacks are cleared, a no-effect definition of showpage is made in userdict, the given matrix is concatenated to the CTM, and the given proc is executed, which is expected to set an appropriate clipping path. Finally file is executed. When it reaches EOD, or execution is interrupted by an uncaught stop, the operand and dictionary stacks are cleared and their prior contents restored, and the prior saved state is restored, which, among other things, removes the redefinition of showpage from userdict.

    StatEPSF
    file StatEPSF file llx lly urx ury

    Reads DSC comments from the supplied file, returning the file rewound to the original position (this will not be the same file object) and the bounding box lower left and upper right corner coordinates.

    No blank line or other white space may precede the first DSC comment read from file, which must be a %%BeginDocument: comment if the file has been inlined, and will normally be the %!PS-Adobe-3.0 EPSF-3.0 line otherwise. When the supplied file begins with a %%BeginDocument: comment, the file object returned by StatEPSF will reach EOD at the balancing %%EndDocument comment. Nested BeginDocument/EndDocument and BeginData/EndData are properly handled.

    Values from a %%HiResBoundingBox: comment are used if available, otherwise they are taken from the %%BoundingBox: comment, which must be present in every EPS file. To read a bounding box given with (atend) in the header comment will consume memory in roughly the size of the file, so it may be advisable to avoid (atend) in large EPS files or where memory is tight.

    Note: for now, an (atend) is satisfied by the first matching comment later encountered (not in a nested document), rather than the last as TN5001 4.4 specifies. This can only be an issue if an EPS file has more than one such comment.

    ReadyEPSF
    llx lly urx ury left bottom angle Xscale Yscale ReadyEPSF clipproc matrix

    Given a desired position (left,bottom), rotation angle, and scaling (Xscale,Yscale), and the EPS bounding box llx lly urx ury, compute matrix representing the user-space transformation by the procedure in TN5002, and proc, a procedure to set a clipping rectangle matching the bounding box. The results can be passed directly to ExecEPSF.

    FitEPSF (deprecated)
    left bottom angle Xscale Yscale llx lly urx ury FitEPSF clipproc matrix

    This procedure is identical, but for order of arguments, to ReadyEPSF, and is retained for compatibility with an earlier version of Import.

    Portable Network Graphic (PNG) image import

    PNG image support is provided in a separate resource file because it relies on LanguageLevel 3 features and the rest of Import is usable with LanguageLevel 2.

    The procedures for PNG image import are split to provide sensible default behavior with the opportunity to override defaults when necessary. To render a physically-dimensioned PNG image at its natural size, assuming default PostScript units, with its lower left corner at the origin, nothing more is needed than:

    gsave (file.png) (r) file StatPNG ReadyPNG pop pop ExecPNG grestore

    StatPNG extracts the essential header information from the file. ReadyPNG uses the stats from StatPNG to compute several defaults and return the parameters and image dictionary for ExecPNG, plus the default dimensions of the image, which the calling program may use to compute a scale. The program may modify any of the defaults set by ReadyPNG before using ExecPNG to render the image.

    Only non-interlaced grayscale, truecolor, or indexed PNG images are supported. A single fully-transparent color is supported. If an indexed image assigns an alpha of zero to more than one index, only the first such index is treated as transparent. All other colors are fully opaque. ReadyPNG will fail on images with an alpha channel.

    ExecPNG
    file1 array file2 dict ExecPNG

    Renders a PNG image, given the four results of ReadyPNG. The values in dict, the dictionary to be used by the image operator, may be changed to override the default values installed in it by ReadyPNG. file1, the file from which the entire PNG image is being read, will be advanced past the entire PNG image on ExecPNG's completion. file2 is the filtered subfile representing the PNG image data chunks; it is set up by ReadyPNG and will be completely consumed by ExecPNG. The array is of no interest to the caller, but used to receive the length and key of the next chunk after all the image bits have been read; ExecPNG uses it to correctly consume any extra chunks that may follow the image data in the file.

    StatPNG
    file StatPNG file length key dict

    Reads from file the PNG chunks necessary to render the image, storing them in dict. file is left advanced just past the length and key of the first IDAT chunk, and length and key are those values. The keys in dict are integers; to check for a certain chunk type in dict, use (for example)

    dict /IHDR PNGkey known

    Chunks not necessary for image rendering are not read into dict; these include the various text chunks, timestamp, histogram, suggested background color and fallback palette. The PNG file primitives described below can be used if a program needs to read those chunks.

    ReadyPNG
    file length key dict ReadyPNG file array filtered-file imagedict wx wy

    Ponders the image details extracted by StatPNG, sets some graphics state defaults, and constructs a default imagedict. Returns file array filtered-file imagedict as needed by ExecPNG, as well as wx wy, the default dimensions of the image in default PostScript units, which the caller may use to compute a scale. The caller may change any of the defaults before calling ExecPNG.

    The default dimensions of the image, and the default ImageMatrix in imagedict, are computed to preserve the original aspect ratio, not to map the image unconditionally from the unit square, so the caller can simply scale equally in x and y to size the image without fear of distortion. If the image has a specified physical size, the default dimensions are its natural physical size in default PostScript units. In that case any scaling factor used by the calling program is relative to the image's natural size.

    In the case where the physical size is unspecified, the default dimensions will be chosen to fit in the unit square; that is, the maximum of wx and wy will be 1. The calling program must scale it up to the desired size, as in the common practice of mapping every image to the unit square, but again may scale equally in x and y to preserve aspect ratio.

    If the file specifies the sRGB color space, ReadyPNG establishes that space and, if the interpreter is Level 3 or sufficiently recent Level 2 to have a findcolorrendering operator, requests the specified rendering intent. Otherwise, ReadyPNG leaves the rendering intent alone and creates a color space according to the gamma and chromaticity specifications, if any, present in the file. If gamma is specified without chromaticity, then for grayscale a calibrated gray space corresponding to Example 4.13 in the PostScript Language Reference, third edition is used, while for color the same reference primaries (BT.709) and white point (D65) used in sRGB are assumed. DeviceGray or DeviceRGB, as appropriate, will be set if the file contains no gamma or chromaticity information, or if, contrary to the W3 2003 PNG recommendation section 12.3, it supplies chromaticity but not gamma. The caller is free to change the color space established by ReadyPNG before calling ExecPNG.

    ReadyPNG disregards any embedded ICC profile, using instead the gamma and chromaticity information that the file's encoder should have supplied as a fallback, or DeviceGray/DeviceRGB in their absence. However, StatPNG does bring the ICC profile into the dictionary it returns, so the caller is free to parse it, create the correct color space, and use it to replace the color space selected by ReadyPNG before calling ExecPNG.

    PNG file manipulation primitives

    These primitives allow manipulating a PNG file at a lower level than StatPNG, ReadyPNG, and ExecPNG.

    PNGmagic
    This read-only string must match the initial bytes of any PNG file.
    PNGchunk
    file PNGchunk length key

    Provided that file is positioned at the beginning of a PNG chunk, reads and returns the length and key (chunk type) of that chunk, leaving file positioned at the beginning of the chunk's data, if any. The first chunk begins immediately after the PNGmagic.

    PNGkey
    name PNGkey key

    PNG keys, or chunk types, are 32-bit integers with a natural interpretation as four-character names. PNGkey converts such a name to integer form for comparison to a key as returned by PNGchunk or in the dictionary returned by StatPNG.

    =PNGkey
    key =PNGkey

    Prints a PNG key in its readable form on standard output.

    PNGChunkDecode
    file1 dict //PNGChunkDecode extfilter file2

    From file1 positioned at the start of a chunk's data (as it is left by PNGchunk), creates a filter from which the chunk's data can be read. file2 must be read to EOD, at which point the filter consumes the chunk's CRC and leaves file1 positioned for another call to PNGchunk. If there is any doubt that all data will be read from file2, add a flushfile after all data of interest have been read from it. A chunk can be skipped by creating a PNGChunkDecode filter on it and doing an immediate flushfile.

    Because this filter is of little use except with this procset, it is not entered in the net.anastigmatix.filter category, and must be supplied to extfilter in immediately-evaluated form as shown above. dict must contain the two entries ChunkLength and ChunkType with the values returned by PNGchunk. The filter does not at present compute or compare the chunk CRC, but the CRC can be implemented in future; that's why the filter needs to know the chunk type.

    PNGIDATDecode
    file1 dict //PNGIDATDecode extfilter file2

    From file1 positioned at the start of an IDAT chunk's data (as it is left by PNGchunk), creates a filter from which to read all of the data in the current and all following IDAT chunks. file2 must be read to completion, at which point the filter leaves file1 positioned at the start of data for the first non-IDAT chunk encountered, storing its length and key in the NextChunk array. If there is any doubt that all data will be read from file2, add a flushfile after all data of interest have been read from it. Note that a FlateDecode filter may detect the end of a compressed stream without reading its input completely to EOD.

    All chunks following the last IDAT chunk, including the IEND, must be read or flushed to ensure that all of the PNG file, in case it is inline, has been consumed.

    Because this filter is of little use except with this procset, it is not entered in the net.anastigmatix.filter category, and must be supplied to extfilter in immediately-evaluated form as shown above. dict must contain the two entries ChunkLength and ChunkType with the values returned by PNGchunk, and NextChunk with a two-element array retained by the caller, which will receive the length and key of the following chunk when file2 has been read to the end of the final IDAT chunk.

    Utilities

    csdimension
    csdimension int

    Returns the number of components in the currently selected color space. Signals undefinedresult if a pattern space is selected.

    hintrenderintent
    name hintrenderintent

    If the interpreter is Level 3, or sufficiently recent Level 2 to have a findcolorrendering operator, this is a procedure that uses findcolorrendering to find a color rendering dictionary with rendering intent name, and uses setcolorrendering to instate it. Otherwise, this is a procedure that pops name and does nothing.

    Valid XHTML 1.0! Valid CSS! $Id: Import.html,v 1.10 2009/11/12 03:16:30 chap Exp $