org.hd.d.pg2k.svrCore.MIME
Class AbstractImageHandler

java.lang.Object
  extended by org.hd.d.pg2k.svrCore.MIME.AbstractHandler
      extended by org.hd.d.pg2k.svrCore.MIME.AbstractImageHandler
All Implemented Interfaces:
Handler
Direct Known Subclasses:
bmp, gif, jp2, jpg, png, tif

public abstract class AbstractImageHandler
extends AbstractHandler

Base class with useful default behaviour for image exhibit media-handler classes. By default this uses ImageIO (iio) routines to extract an image and metadata from an exhibit stream, and will allow the generation of thumbnails if an encoder and thumbnail parameters can be found at run-time.

Various routines can be overridden in deriving classes to change this behaviour.

Potentially-memory-intensive routines may be synchronised in this class (on a private lock) in order to reduce the chance of blowing up the VM by accident, but not if this may cause deadlock elsewhere.


Nested Class Summary
 
Nested classes/interfaces inherited from interface org.hd.d.pg2k.svrCore.MIME.Handler
Handler.ThumbnailParams
 
Field Summary
private static java.util.concurrent.atomic.AtomicReferenceArray<java.lang.Boolean> encoderExists
          Thread-safe bounded-size cache for canMakeThumbnails() and _getEncoder() as to whether an encoder can be created; never null.
private static boolean ONLY_GET_STD_METADATA
          If true, only get "standard" (lossy) metadata to save space.
private static java.lang.String STD_METADATA_FORMAT_NAME
          Standard metadata format name.
private static int THUMBNAIL_SIZE_TOL
          Image size tolerance as a fraction of the target size; strictly positive.
private static int TRIM_CHILDREN_MAX
          Maximum number of children of a single node before culling/trimming it; strictly positive.
private static boolean TRIM_METADATA
          If true, trim bulky and not-very-useful metadata (eg palette entries).
 
Fields inherited from interface org.hd.d.pg2k.svrCore.MIME.Handler
TAG_NAME_METADATA_TOP
 
Constructor Summary
AbstractImageHandler()
           
 
Method Summary
protected  javax.imageio.ImageWriter _getEncoder()
          Gets an encoder/writer for this image type if one is available, else returns null.
protected  int _reduceColoursQualityThreshold()
          Guide colour-reduction to reduce quality and size of lossless image formats.
protected  void _trimMetadata(org.w3c.dom.Node n, Name.ExhibitFull exhibitName)
          Removes bulky and not-very-useful metadata sub-trees from below the given node.
 boolean canMakeThumbnails()
          Claim that we can make thumbnails for this image type if we can find parameters and an encoder at run-time.
 java.awt.image.BufferedImage decodeImage(java.io.InputStream is)
          Decode image using generic image IO routines; null if cannot be done.
protected  int estimateWorkingMemoryToCreateThumbnails(java.awt.Dimension xyDim)
          Estimates bytes of working memory required to create thumbnails for an image.
protected  org.w3c.dom.Node extractSpecificImageMetaData(javax.imageio.metadata.IIOMetadata imageMetadata, Name.ExhibitFull exhibitName)
          Get specific (image) metadata for one particular image type; null if none.
 java.awt.Dimension get2DImageDimensions(java.io.InputStream is)
          Get dimensions X and Y of an image by decoding entire image, else null if dimensions cannot be computed.
 org.w3c.dom.Node getMetadata(java.io.InputStream is, Name.ExhibitFull exhibitName)
          Gets all available exhibit metadata as a single XML DOM tree; null if none.
 byte[] makeImageBinary(java.awt.image.BufferedImage imageIn, int quality)
          Creates output file-formatted; null for a permanent failure.
 byte[] makeSizeConstrainedEncodedImage(int lowerQualityBound, int initialQualityHint, int upperQualityBound, java.awt.image.BufferedImage inputImage, int targetMin, int targetMax, int absMinSize, int absMaxSize, int targetBytes)
          Make a byte[]-encoded image of this type constained above and below by size; null if not possible.
protected  byte[] makeThumbnailImage(java.awt.image.BufferedImage imageIn, boolean std, int minSize, int maxSize)
          Return individual thumbnail image as file-format byte array in same format as original; null if not possible.
 ExhibitThumbnails makeThumbnails(ExhibitStaticAttr esa, AllExhibitProperties.ExhibitDataSource eds, AllExhibitProperties aep, boolean unlimitedResources)
          Make thumbnails/samples for the specified exhibit; null if thumbnails cannot (currently) be made.
 ExhibitThumbnails makeThumbnails(java.io.InputStream is, long originalLength)
          Make thumbnails/samples for the specified exhibit; null if thumbnails cannot (currently) be made.
private static void setJAICacheParams()
          Set/reset JAI cache/memory parameters.
 
Methods inherited from class org.hd.d.pg2k.svrCore.MIME.AbstractHandler
getThumbnailParams
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 
Methods inherited from interface org.hd.d.pg2k.svrCore.MIME.Handler
getExhibitType
 

Field Detail

THUMBNAIL_SIZE_TOL

private static final int THUMBNAIL_SIZE_TOL
Image size tolerance as a fraction of the target size; strictly positive. The tolerance is targetSize/SIZE_TOL, possibly circumscribed by other absolute limits.

The larger this number the tighter in conformance to the target size the final image will have to be, which will make convergence take longer or in extreme cases prevent generation of a thumbnail altogether.

A reasonable value for this is probably in the region 3--50.

See Also:
Constant Field Values

ONLY_GET_STD_METADATA

private static final boolean ONLY_GET_STD_METADATA
If true, only get "standard" (lossy) metadata to save space.

See Also:
Constant Field Values

STD_METADATA_FORMAT_NAME

private static final java.lang.String STD_METADATA_FORMAT_NAME
Standard metadata format name. This seems to be rather badly hidden in the API: yeuck!

See Also:
Constant Field Values

TRIM_METADATA

private static final boolean TRIM_METADATA
If true, trim bulky and not-very-useful metadata (eg palette entries).

See Also:
Constant Field Values

TRIM_CHILDREN_MAX

private static final int TRIM_CHILDREN_MAX
Maximum number of children of a single node before culling/trimming it; strictly positive.

See Also:
Constant Field Values

encoderExists

private static final java.util.concurrent.atomic.AtomicReferenceArray<java.lang.Boolean> encoderExists
Thread-safe bounded-size cache for canMakeThumbnails() and _getEncoder() as to whether an encoder can be created; never null. This is a mapping from the exhibit type number to a tri-state value:

Updated by _getEncoder() but also used by canMakeThumbnails() to avoid calling _getEncoder() if possible for speed and to save possible resource leaks.

This size of this is limited by the number of exhibit types we support.

Constructor Detail

AbstractImageHandler

public AbstractImageHandler()
Method Detail

makeThumbnails

public ExhibitThumbnails makeThumbnails(java.io.InputStream is,
                                        long originalLength)
                                 throws java.io.IOException
Make thumbnails/samples for the specified exhibit; null if thumbnails cannot (currently) be made. This may fail with an IOException or return null to indicate that it is currently unable to create thumbnails/samples (though this condition may be temporary).

If this wishes to indicate that it cannot ever make one or more thumbnails/samples for a given exhibit then this should return a ExhibitThumbnails object with one or both thumbnails set to null.

(If canMakeThumbnails() returns false, this should return null.)

This does not close its input stream when done.

This will only work correctly if the exhibit is of the correct type, eg its magic number must already have been tested.

This assumes enough memory and other resource is available.

By default, returns null, ie thumbnails cannot be made now.

Sophisticated handlers may wish to override this.

Whatever thumbnails are returned, any small thumbnail is smaller than any standard thumbnail, and any standard thumbnail is smaller than the original.

Specified by:
makeThumbnails in interface Handler
Overrides:
makeThumbnails in class AbstractHandler
Parameters:
is - the whole raw image positioned at its start
originalLength - is the length of the encoded original in bytes; always positive and must reflect the stream input and will be constrained to Integer.MAX_VALUE if larger
Returns:
thumbnails, else null if not possible now; ExhibitThumbnails.NO_THUMBNAILS may be returned if it looks like it never be possible/sensible to make thumbnails for this exhibit
Throws:
java.io.IOException

makeThumbnails

public final ExhibitThumbnails makeThumbnails(ExhibitStaticAttr esa,
                                              AllExhibitProperties.ExhibitDataSource eds,
                                              AllExhibitProperties aep,
                                              boolean unlimitedResources)
                                       throws java.io.IOException
Make thumbnails/samples for the specified exhibit; null if thumbnails cannot (currently) be made. A data source for the exhibit must be supplied, along with all available properties of that exhibit.

This may fail with an IOException or return null to indicate that it is currently unable to create thumbnails/samples (though this condition may be temporary).

If this wishes to indicate that it cannot make one or more thumbnails/samples for a given exhibit then this should return a ExhibitThumbnails object with one or both thumbnails set to null.

(If canMakeThumbnails() returns false, this should return null.)

By default, returns null, ie thumbnails cannot be made.

This routine regulates memory use, rejecting the attempt to make the thumbnails if it cannot find/reserve sufficient memory using MemoryTools.runMemoryIntensiveOperation().

Calls the InputStream version of makeThumbnails().

Specified by:
makeThumbnails in interface Handler
Overrides:
makeThumbnails in class AbstractHandler
Parameters:
unlimitedResources - if true, the generation routine is allowed to try to use unlimited resources (especially memory)
Returns:
thumbnails, else null if not possible now or this format does not support thumbnails, eg a sound clip; ExhibitThumbnails.NO_THUMBNAILS may be returned if it looks like it never be possible/sensible to make thumbnails for this particular exhibit
Throws:
java.io.IOException

makeThumbnailImage

protected byte[] makeThumbnailImage(java.awt.image.BufferedImage imageIn,
                                    boolean std,
                                    int minSize,
                                    int maxSize)
                             throws java.io.IOException
Return individual thumbnail image as file-format byte array in same format as original; null if not possible. This is used for still images and possible animations or movies where the bounding rectangle and the contained data is scaled to the given bounds.

This uses a binary chop algorithm on the "quality" parameter calling the underlying makeScaledImage() routine to try to get the output file size to reasonable bounds. This may fail to work well, or at all, if the image size is not fixed or monotonically increasing with quality, or fails to produce any output at all some some values of the quality parameter. We treat the failure to generate an image as an indication that the quality parameter needs to be set higher.

The output image will, if possible, use the same colour scheme and other characteristics as the input, though some optional features that usually consume extra space, such as interlacing, may be disabled.

If no output can be generated this returns null, which is the default behaviour.

This should adjust the image "quality" with the detail value (adjusted within the bounds supplied by the handler class) to try to tune the output size. For a lossy encoding format such as JPEG this may be the "quality" factor or compression. For a lossless format the may have to be the number of bits-per-pixel that a colour map is reduced to, for example.

This base-class implementation can be overridden by sophisticated handlers.

This first scales the image using a (fast) nearest-pixel method, which should be good for true-colour and palette images.

Parameters:
imageIn - source image; must not be null and must be suitable for the target format
std - if true we are making a standard thumbnail, else we are making a small thumbnail
minSize - minimum (floor) size of thumbnail in bytes; must be non-negative (can be zero if not required)
maxSize - maximum (ceiling) size of thumbnail in bytes; must be non-negative and no smaller than minSize (can me Integer.MAX_VALUE if not required)
Throws:
java.io.IOException

makeSizeConstrainedEncodedImage

public byte[] makeSizeConstrainedEncodedImage(int lowerQualityBound,
                                              int initialQualityHint,
                                              int upperQualityBound,
                                              java.awt.image.BufferedImage inputImage,
                                              int targetMin,
                                              int targetMax,
                                              int absMinSize,
                                              int absMaxSize,
                                              int targetBytes)
                                       throws java.io.IOException,
                                              java.lang.IllegalArgumentException
Make a byte[]-encoded image of this type constained above and below by size; null if not possible. This uses a binary-chop algorithm to attempt to quickly find the optimal "quality" to make the image at, lower quality values asking the encoder to discard more information, eg by doing colour reduction or other quantisation.

This is not possible for all exhibit types.

Specified by:
makeSizeConstrainedEncodedImage in interface Handler
Overrides:
makeSizeConstrainedEncodedImage in class AbstractHandler
Parameters:
upperQualityBound - maximum value of quality to use; non-negative
lowerQualityBound - minimum value of quality to use; non-negative and no greater than upperQualityBound
initialQualityHint - initial suggested quality hint; non-negative, no greater than upperQualityBound, no less than lowerQualityBound
inputImage - the input image to encode
targetMin - target lower bound, should be higher than absMinSize
targetMax - target upper bound, should be lower than absMaxSize
absMinSize - absolute minimum number of bytes
absMaxSize - absolute maximum number of bytes
targetBytes - target number of bytes
Returns:
encoded image, or null if the image cannot be generated with given constraints
Throws:
java.io.IOException - in case of difficulty generating the image
java.lang.IllegalArgumentException - if the arguments are invalid

estimateWorkingMemoryToCreateThumbnails

protected int estimateWorkingMemoryToCreateThumbnails(java.awt.Dimension xyDim)
Estimates bytes of working memory required to create thumbnails for an image. This includes the space to load the old image, plus one extra working copy of the original image, make one of the thumbnails at a time, and hold both the standard and small thumbnails in binary format.

This assumes still images amongst other things; for movies or animations this may, depending on the processing method, need to be multiplied by the number of frames, for example.

Fudge factors, such as guessed overheads, are liberally sprinkled in.

This assumes that the JVM and the codecs are reasonably efficient in their use of memory, but this is at best a wild guess.

A sophisticated handler may need to override this.

Should not be called if getThumbnailParams() returns null.

Parameters:
xyDim - pixel dimensions of original image; must be non-null
Returns:
estimated working memory in heap in bytes

decodeImage

public java.awt.image.BufferedImage decodeImage(java.io.InputStream is)
                                         throws java.io.IOException
Decode image using generic image IO routines; null if cannot be done. It should already have been established that the image is of the correct type.

Individual handlers may override this default (JAI) implementation if desired.

This does not close its input stream when done.

Calls to this implementation may be serialised because they can be very memory-intensive.

If the underlying decoder routine throws an (unchecked) exception, we absorb (and log) it and return null, thus making us robust in the face of some underlying handler weaknesses.

Specified by:
decodeImage in interface Handler
Overrides:
decodeImage in class AbstractHandler
Throws:
java.io.IOException

get2DImageDimensions

public java.awt.Dimension get2DImageDimensions(java.io.InputStream is)
                                        throws java.io.IOException
Get dimensions X and Y of an image by decoding entire image, else null if dimensions cannot be computed. This may be extremely slow and inefficient and should be overridden by handlers if at all possible.

This does not close its input stream when done.

Calls to this implementation may be serialised because they may be very memory-intensive.

Specified by:
get2DImageDimensions in interface Handler
Overrides:
get2DImageDimensions in class AbstractHandler
Parameters:
is - the exhibit as a binary data stream
Throws:
java.io.IOException - in case of problems with corrupt data (or a broken exhibit)

extractSpecificImageMetaData

protected org.w3c.dom.Node extractSpecificImageMetaData(javax.imageio.metadata.IIOMetadata imageMetadata,
                                                        Name.ExhibitFull exhibitName)
Get specific (image) metadata for one particular image type; null if none. This does not have to be provided, but if so enables such things as EXIF and IPTC extraction from JPEG images.

This is passed the metadata for the first available image.

This may be a mix of stream and image/frame metadata.

Parameters:
exhibitName - full exhibit name for diagnostics; never null

_trimMetadata

protected void _trimMetadata(org.w3c.dom.Node n,
                             Name.ExhibitFull exhibitName)
Removes bulky and not-very-useful metadata sub-trees from below the given node. This removes the following:

Parameters:
exhibitName - non-null full exhibit name for diagnostics

getMetadata

public org.w3c.dom.Node getMetadata(java.io.InputStream is,
                                    Name.ExhibitFull exhibitName)
Gets all available exhibit metadata as a single XML DOM tree; null if none. We do not (yet) have an XML schema for this and may never do so, since its structure and content will depend on various external sources and parts of the ImageIO and JAI subsystems and others.

This tries to fetch any stream data and any metadata from the first available image.

Note that this has to turn off the ImageIO file cache to avoid failing since there seems to be no cache clearing.

By default we trim some of the most bulky and least useful data from the metadata, mainly the palette information for indexed images.

This implementation is serialised as it may be very memory-intensive.

Specified by:
getMetadata in interface Handler
Overrides:
getMetadata in class AbstractHandler
Parameters:
is - input stream containing exhibit data; never null
exhibitName - full exhibit name (primarily to help with debugging); never null
Returns:
top-level node "metadata" with captured metadata beneath, else null

_getEncoder

protected javax.imageio.ImageWriter _getEncoder()
Gets an encoder/writer for this image type if one is available, else returns null. Uses IIO facilities to locate an available writer.

Any non-null value returned should be dispose()d of when finished with.


canMakeThumbnails

public boolean canMakeThumbnails()
Claim that we can make thumbnails for this image type if we can find parameters and an encoder at run-time.

Specified by:
canMakeThumbnails in interface Handler
Overrides:
canMakeThumbnails in class AbstractHandler

_reduceColoursQualityThreshold

protected int _reduceColoursQualityThreshold()
Guide colour-reduction to reduce quality and size of lossless image formats. Defaults to -1, implying that the image format is a lossy format for which the ImageWriteParam.setCompressionQuality() mechanism is enough to trade encoded image size for quality.

Else this is a positive value n, typically 8 or 24, which sets a quality level at/below which the number of colours in the image is reduced to (capped at) 2^n, and the image representation may be tweaked too (eg converted to a palette/indexed format) as a strong hint to the encoder.


makeImageBinary

public byte[] makeImageBinary(java.awt.image.BufferedImage imageIn,
                              int quality)
                       throws java.io.IOException
Creates output file-formatted; null for a permanent failure. Can return null for a permanent error handling a particular image, eg in the ImageIO GIF/PNG drivers for some palette sizes.

We are careful to dispose() of our write when done to release resources.

Specified by:
makeImageBinary in interface Handler
Overrides:
makeImageBinary in class AbstractHandler
Parameters:
imageIn - single image to encode, never null
quality - desired encoding quality in range 0--100 inclusive, with 0 interpreted as "high compression is important," and 100 (or over) interpreted as "high image quality is important."; this parameter is ignored where it does not make sense for the format
Throws:
java.io.IOException

setJAICacheParams

private static void setJAICacheParams()
Set/reset JAI cache/memory parameters. This may be particularly important for small heap instances.

See: http://java.sun.com/products/java-media/jai/forDevelopers/jaifaq.html#memory1


DHD Multimedia Gallery V1.53.0

Copyright (c) 1996-2009, Damon Hart-Davis. All rights reserved.