java-imaging-utilities-0.14.2+3.orig/ 0000775 0000000 0000000 00000000000 04547516600 014135 5 ustar java-imaging-utilities-0.14.2+3.orig/net/ 0000775 0000000 0000000 00000000000 10546531760 014723 5 ustar java-imaging-utilities-0.14.2+3.orig/net/sourceforge/ 0000775 0000000 0000000 00000000000 10546532046 017244 5 ustar java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/ 0000775 0000000 0000000 00000000000 10546532052 020030 5 ustar java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/ 0000775 0000000 0000000 00000000000 10546532076 021154 5 ustar java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/io/ 0000775 0000000 0000000 00000000000 10546532076 021563 5 ustar java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/io/MatrixSerialization.java 0000664 0000000 0000000 00000002617 10324333312 026420 0 ustar /* * MatrixSerialization * * Copyright (c) 2001, 2002, 2003, 2004, 2005 Marco Schmidt * All rights reserved. */ package net.sourceforge.jiu.color.io; import java.io.PrintStream; import net.sourceforge.jiu.color.data.CoOccurrenceMatrix; import net.sourceforge.jiu.color.data.CoOccurrenceFrequencyMatrix; /** * Write co-occurrence and co-occurrence frequency matrices to text files. * * @author Marco Schmidt * @since 0.6.0 */ public class MatrixSerialization { private MatrixSerialization() { } public static void save(CoOccurrenceMatrix matrix, PrintStream out) { if (matrix == null || out == null) { return; } int dim = matrix.getDimension(); out.println(Integer.toString(dim)); for (int i = 0; i < dim; i++) { StringBuffer sb = new StringBuffer(); for (int j = 0; j < dim; j++) { sb.append(matrix.getValue(i, j)); sb.append(' '); } out.println(sb.toString()); } } public static void save(CoOccurrenceFrequencyMatrix matrix, PrintStream out) { if (matrix == null || out == null) { return; } int dim = matrix.getDimension(); out.println(Integer.toString(dim)); for (int i = 0; i < dim; i++) { StringBuffer sb = new StringBuffer(); for (int j = 0; j < dim; j++) { sb.append(matrix.getValue(i, j)); sb.append(' '); } out.println(sb.toString()); } } } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/io/package.html 0000664 0000000 0000000 00000000350 07741250132 024033 0 ustar
Classes to read and write color-related data from and to files.
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/io/HistogramSerialization.java 0000664 0000000 0000000 00000006634 10324333256 027123 0 ustar /*
* HistogramSerialization
*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005 Marco Schmidt
* All rights reserved.
*/
package net.sourceforge.jiu.color.io;
import java.io.PrintStream;
import net.sourceforge.jiu.color.data.Histogram1D;
import net.sourceforge.jiu.color.data.Histogram3D;
/**
* This class has static methods for saving histograms.
* Text files (actually, any PrintStream, so you could write to standard output
* using {@link java.lang.System#out}) are used to store the histogram information.
* Hint: When creating a {@link java.io.PrintStream} object yourself, set the autoFlush
* argument of the constructor to false
.
* You should also wrap your {@link java.io.OutputStream} object into a {@link java.io.BufferedOutputStream} object.
* That may speed things up.
*
* A simple format is used for storing the histograms. * The first line holds the number of components. * This would be 3 for a three-dimensional histogram, e.g.for RGB color images, * or 1 for a one-dimensional histogram as used for a grayscale image. *
* Next, as many lines as dimensions follow. * Each line holds the maximum value allowed for that component. * The minimum value is always zero. * Typically, the maximum values are all the same, e.g. 255 for each * component of a 24 bit RGB truecolor image. *
* Following these header lines is the actual histogram. * Each line holds a non-zero counter value for one pixel. * The counter is always the last integer value in the line. *
* Example: *
* 34 0 55 4033 ** For the histogram of an RGB24Image, this would mean that the pixel * red=34, green=0, blue=55 occurs 4033 times. *
* 0 2 ** For the histogram of any one channel image, this means that the value 0 occurs twice. */ public class HistogramSerialization { private HistogramSerialization() { } /** * Saves a one-dimensional histogram to a text output stream. * * @param hist the histogram that will be written to a stream * @param out the stream that will be written to */ public static void save(Histogram1D hist, PrintStream out) { if (hist == null || out == null) { return; } int max = hist.getMaxValue(); out.println("1"); out.println(max); for (int i = 0; i <= max; i++) { int counter = hist.getEntry(i); if (counter != 0) { out.print(i); out.print(' '); out.println(counter); } } out.flush(); } /** * Saves a three-dimensional histogram to a text output stream. * * @param hist the histogram to be saved * @param out the output stream where the histogram will be saved to */ public static void save(Histogram3D hist, PrintStream out) { if (hist == null || out == null) { return; } int max1 = hist.getMaxValue(0); int max2 = hist.getMaxValue(1); int max3 = hist.getMaxValue(2); out.println("3"); out.println(max1); out.println(max2); out.println(max3); for (int i = 0; i <= max1; i++) { for (int j = 0; j <= max2; j++) { for (int k = 0; k <= max3; k++) { int counter = hist.getEntry(i, j, k); if (counter != 0) { out.print(i); out.print(' '); out.print(j); out.print(' '); out.print(k); out.print(' '); out.println(counter); } } } } out.flush(); } } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/io/PaletteSerialization.java 0000664 0000000 0000000 00000006724 07741250132 026564 0 ustar /* * PaletteSerialization * * Copyright (c) 2001, 2002, 2003 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.color.io; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.Vector; import net.sourceforge.jiu.codecs.ImageLoader; import net.sourceforge.jiu.codecs.PNMCodec; import net.sourceforge.jiu.data.MemoryRGB24Image; import net.sourceforge.jiu.data.Palette; import net.sourceforge.jiu.data.PixelImage; import net.sourceforge.jiu.data.RGB24Image; import net.sourceforge.jiu.data.RGBIndex; import net.sourceforge.jiu.ops.OperationFailedException; /** * This class loads and saves palettes. * Loading is done using the {@link ImageLoader} class - an image * is loaded which is supposed to have no more than 256 pixels, the palette entries. * When saving, the {@link PNMCodec} is used to store palettes as .ppm files. * * @author Marco Schmidt * @since 0.5.0 */ public class PaletteSerialization implements RGBIndex { private PaletteSerialization() { } /** * Create a palette from the pixels of the argument image. */ public static Palette convertImageToPalette(RGB24Image image) { if (image == null) { return null; } int numPixels = image.getWidth() * image.getHeight(); if (numPixels > 256) { // too many pixels return null; } Palette result = new Palette(numPixels, 255); int index = 0; for (int y = 0; y < image.getHeight(); y++) { for (int x = 0; x < image.getWidth(); x++) { result.put(index++, image.getSample(INDEX_RED, x, y), image.getSample(INDEX_GREEN, x, y), image.getSample(INDEX_BLUE, x, y)); } } return result; } /** * Creates an RGB24Image from the palette entries, each entry * becomes a pixel in an image of width 1 and height * palette.getNumEntries(). */ public static RGB24Image convertPaletteToImage(Palette palette) { RGB24Image result = new MemoryRGB24Image(1, palette.getNumEntries()); for (int index = 0; index < palette.getNumEntries(); index++) { result.putSample(INDEX_RED, 0, index, palette.getSample(INDEX_RED, index)); result.putSample(INDEX_GREEN, 0, index, palette.getSample(INDEX_GREEN, index)); result.putSample(INDEX_BLUE, 0, index, palette.getSample(INDEX_BLUE, index)); } return result; } /** * Loads a palette from the argument file. * Uses {@link net.sourceforge.jiu.codecs.ImageLoader} to load an * image from the argument file, then calls {@link #convertImageToPalette} * and returns the palette created that way. */ public static Palette load(File paletteFile) { PixelImage image; try { image = ImageLoader.load(paletteFile, (Vector)null); } catch (Exception e) { return null; } if (!(image instanceof RGB24Image)) { return null; } return convertImageToPalette((RGB24Image)image); } /** * Saves the palette to the given file as a PPM image file. * Uses {@link net.sourceforge.jiu.codecs.PNMCodec}. */ public static void save(Palette palette, File paletteFile) throws IOException { RGB24Image image = convertPaletteToImage(palette); PNMCodec codec = new PNMCodec(); codec.setOutputStream(new FileOutputStream(paletteFile)); codec.setAscii(true); codec.setImage(image); try { codec.process(); } catch(OperationFailedException ofe) { throw new IOException("I/O error: " + ofe.toString()); } } } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/quantization/ 0000775 0000000 0000000 00000000000 10546532076 023702 5 ustar ././@LongLink 0000000 0000000 0000000 00000000145 00000000000 011565 L ustar root root java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/quantization/PopularityQuantizer.java java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/quantization/PopularityQuantizer.java0000664 0000000 0000000 00000013206 10421160643 030607 0 ustar /* * PopularityQuantizer * * Copyright (c) 2003, 2004, 2005, 2006 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.color.quantization; import net.sourceforge.jiu.color.analysis.Histogram3DCreator; import net.sourceforge.jiu.color.data.Histogram3D; import net.sourceforge.jiu.data.IntegerImage; import net.sourceforge.jiu.data.Palette; import net.sourceforge.jiu.data.PixelImage; import net.sourceforge.jiu.data.RGB24Image; import net.sourceforge.jiu.data.RGBIndex; import net.sourceforge.jiu.ops.ImageToImageOperation; import net.sourceforge.jiu.ops.MissingParameterException; import net.sourceforge.jiu.ops.OperationFailedException; import net.sourceforge.jiu.ops.WrongParameterException; /** * Performs the popularity color quantization algorithm that maps an image to * the colors occurring most frequently in the input image. * The number of colors in the palette can be defined by the user of this * operation with {@link #setPaletteSize(int)}. *
* PopularityQuantizer quantizer = new PopularityQuantizer(); * quantizer.setInputImage(image); * quantizer.setPaletteSize(256); * quantizer.process(); * PixelImage quantizedImage = quantizer.getOutputImage(); ** @author Marco Schmidt * @since 0.11.0 * @see ArbitraryPaletteQuantizer */ public class PopularityQuantizer extends ImageToImageOperation implements RGBIndex, RGBQuantizer { private ArbitraryPaletteQuantizer arbQuantizer; private int paletteSize; private Palette palette; private boolean doNotMap; public Palette createPalette() { if (palette == null) { try { palette = determinePalette(); return (Palette)palette.clone(); } catch (OperationFailedException ofe) { return null; } } else { return (Palette)palette.clone(); } } private Palette determinePalette() throws OperationFailedException { Histogram3DCreator hc = new Histogram3DCreator(); hc.setImage((IntegerImage)getInputImage(), RGBIndex.INDEX_RED, RGBIndex.INDEX_GREEN, RGBIndex.INDEX_BLUE); hc.process(); Histogram3D hist = hc.getHistogram(); if (hist == null) { throw new OperationFailedException("Could not create histogram from input image."); } int numUniqueColors = hist.getNumUsedEntries(); if (numUniqueColors <= paletteSize) { paletteSize = numUniqueColors; } RGBColorList list = new RGBColorList(hist); list.sortByCounter(0, list.getNumEntries() - 1); Palette result = new Palette(paletteSize); int paletteIndex = paletteSize - 1; int listIndex = list.getNumEntries() - 1; while (paletteIndex >= 0) { RGBColor color = list.getColor(listIndex--); result.put(paletteIndex--, color.getSample(RGBIndex.INDEX_RED), color.getSample(RGBIndex.INDEX_GREEN), color.getSample(RGBIndex.INDEX_BLUE) ); } return result; } /** * Returns the number of colors in the destination image. * If output is paletted, this is also the number of entries * in the palette. * @return number of colors in the destination * @see #setPaletteSize(int) */ public int getPaletteSize() { return paletteSize; } public int map(int[] origRgb, int[] quantizedRgb) { return arbQuantizer.map(origRgb, quantizedRgb); } public void process() throws MissingParameterException, OperationFailedException, WrongParameterException { ensureInputImageIsAvailable(); ensureImagesHaveSameResolution(); PixelImage in = getInputImage(); if (!(in instanceof RGB24Image)) { throw new WrongParameterException("Input image must implement RGB24Image."); } Histogram3DCreator hc = new Histogram3DCreator(); hc.setImage((IntegerImage)in, RGBIndex.INDEX_RED, RGBIndex.INDEX_GREEN, RGBIndex.INDEX_BLUE); hc.process(); Histogram3D hist = hc.getHistogram(); if (hist == null) { throw new OperationFailedException("Could not create histogram from input image."); } int numUniqueColors = hist.getNumUsedEntries(); if (numUniqueColors <= paletteSize) { paletteSize = numUniqueColors; } arbQuantizer = new ArbitraryPaletteQuantizer(createPalette()); if (!doNotMap) { arbQuantizer.setInputImage(in); arbQuantizer.setOutputImage(getOutputImage()); arbQuantizer.process(); // TODO: copy ProgressListeners to arbQuantizer setOutputImage(arbQuantizer.getOutputImage()); } } /** * Specifies whether this operation will map the image to the * new palette (true) or not (false). * The latter may be interesting if only the palette is required. * By default, this operation does map. * @param newValue map to new image (true) or just search palette (false) */ public void setMapping(boolean newValue) { doNotMap = !newValue; } /** * Sets the number of colors that this operations is supposed to reduce * the original image to. * @param newPaletteSize the number of colors * @throws IllegalArgumentException if the argument is smaller than 1 or larger than 256 * @see #getPaletteSize */ public void setPaletteSize(int newPaletteSize) { if (newPaletteSize < 1) { throw new IllegalArgumentException("Palette size must be 1 or larger."); } if (newPaletteSize > 256) { throw new IllegalArgumentException("Palette size must be at most 256."); } paletteSize = newPaletteSize; } } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/quantization/RGBColor.java 0000664 0000000 0000000 00000005542 07741250132 026155 0 ustar /* * RGBColor * * Copyright (c) 2001, 2002, 2003 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.color.quantization; import net.sourceforge.jiu.data.RGBIndex; /** * Encapsulates a single color from RGB (red, green, blue) color space plus a frequency counter. * Each of the three RGB samples is of type int. * Also stores a counter of type int. * @author Marco Schmidt */ public class RGBColor implements RGBIndex { /** The intensity values that make up the color. */ private int[] samples; /** Stores how many times this colors appears in a certain image. */ private int counter; /** * Creates an instance of this class and initializes it to the given * intensity values. * The internal color counter is set to zero. */ public RGBColor(int red, int green, int blue) { this(red, green, blue, 0); } /** * Creates an instance of this class and initializes it to the given * intensity values. * Also sets the internal color counter to the given parameter. */ public RGBColor(int red, int green, int blue, int counter) { samples = new int[3]; samples[INDEX_RED] = red; samples[INDEX_GREEN] = green; samples[INDEX_BLUE] = blue; this.counter = counter; } /** * Compares this color to the argument color, using the sortOrder argument (which is one of the * three index values defined in {@link RGBIndex}. * That way, the two sample values for one component (e.g. red if sortOrder == INDEX_RED) are * compared. * * @param c the color to which this color is compared * @param sortOrder the component used for the comparison * @return relation between this color and the argument color */ public int compareTo(RGBColor c, int sortOrder) { int s1 = samples[sortOrder]; int s2 = c.samples[sortOrder]; if (s1 < s2) { return -1; } else if (s1 == s2) { return 0; } else { return 1; } } /** * For two RGB triplets (r1, g1, b1) and (r2, g2, b2) this will return * the distance between those colors in RGB color space. */ public static double computeDistance(int r1, int g1, int b1, int r2, int g2, int b2) { int r = r1 - r2; int g = g1 - g2; int b = b1 - b2; return Math.sqrt(r * r + g * g + b * b); } /** * Compares this color with another instance of RGBColor and returns true * if all intensity values are equal, false otherwise. */ public boolean equals(Object obj) { RGBColor c = (RGBColor)obj; return (samples[0] == c.samples[0] && samples[1] == c.samples[1] && samples[2] == c.samples[2]); } public int getCounter() { return counter; } public int getSample(int index) { return samples[index]; } public String toString() { return "(" + samples[INDEX_RED] + ", " + samples[INDEX_GREEN] + ", " + samples[INDEX_BLUE] + ")"; } } ././@LongLink 0000000 0000000 0000000 00000000151 00000000000 011562 L ustar root root java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/quantization/MedianCutContourRemoval.java java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/quantization/MedianCutContourRemoval.0000664 0000000 0000000 00000046340 07741250132 030454 0 ustar /* * MedianCutContourRemoval * * Copyright (c) 2001, 2002, 2003 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.color.quantization; import java.util.Hashtable; import java.util.Vector; import net.sourceforge.jiu.codecs.BMPCodec; import net.sourceforge.jiu.codecs.CodecMode; import net.sourceforge.jiu.codecs.ImageLoader; import net.sourceforge.jiu.color.analysis.MatrixCreator; import net.sourceforge.jiu.color.analysis.MeanDifference; import net.sourceforge.jiu.color.data.CoOccurrenceFrequencyMatrix; import net.sourceforge.jiu.color.data.CoOccurrenceMatrix; import net.sourceforge.jiu.data.Palette; import net.sourceforge.jiu.data.Paletted8Image; import net.sourceforge.jiu.data.PixelImage; import net.sourceforge.jiu.data.RGB24Image; import net.sourceforge.jiu.data.RGBIndex; import net.sourceforge.jiu.ops.ImageToImageOperation; import net.sourceforge.jiu.ops.MissingParameterException; import net.sourceforge.jiu.ops.OperationFailedException; import net.sourceforge.jiu.ops.WrongParameterException; import net.sourceforge.jiu.util.ComparatorInterface; import net.sourceforge.jiu.util.Sort; import net.sourceforge.jiu.util.Statistics; /** * A data structure for storing the index values of a pair of * contouring colors plus their respective self co-occurrence * frequency values. * @author Marco Schmidt * @see MedianCutContourRemoval */ class ContouringColorPair implements ComparatorInterface { private int index1; private int index2; private double scof1; private double scof2; /** * Creates a new object of this class. */ public ContouringColorPair() { } /** * Creates a new object of this class. * @param i1 palette index of first color * @param i2 palette index of second color * @param sf1 self co-occurrence frequency value of first color * @param sf2 self co-occurrence frequency value of second color */ public ContouringColorPair(int i1, int i2, double sf1, double sf2) { index1 = i1; index2 = i2; scof1 = sf1; scof2 = sf2; } public int compare(Object o1, Object o2) { ContouringColorPair p1 = (ContouringColorPair)o1; ContouringColorPair p2 = (ContouringColorPair)o2; double sum1 = p1.scof1 + p1.scof2; double sum2 = p2.scof1 + p2.scof2; if (sum1 < sum2) { return -1; } else if (sum1 > sum2) { return 1; } else { return 0; } } public int getColorIndex(boolean smaller) { if (smaller) { return scof1 < scof2 ? index1 : index2; } else { return scof1 < scof2 ? index2 : index1; } } } /** * Performs the Median Cut color quantization algorithm in combination with * a contour removal algorithm. *
* Quantization is an operation that reduces the number of colors in * an image while trying to remain as close to the original image * as possible. * Standard Median Cut quantization is implemented in the * {@link net.sourceforge.jiu.color.quantization.MedianCutQuantizer} * class. *
* This class implements an algorithm that improves the standard * implementation. * It repeatedly calls the original quantizer and adjusts the palette * in order to reduce the amount of contouring errors. *
* RGB24Image inputImage = ...; // image to be processed, from a file etc. * MedianCutQuantizer quantizer = new MedianCutQuantizer(); * quantizer.setPaletteSize(256); * MedianCutContourRemoval removal = new MedianCutContourRemoval(); * removal.setQuantizer(quantizer); * removal.setInputImage(inputImage); * removal.setTau(11.0); * removal.setNumPasses(3); * removal.process(); * PixelImage outputImage = removal.getOutputImage(); **
double
values between
* 0.0
and 1.0
.
* If the value is 0.6
, j makes 60 percent of all neighboring
* pixels of i.
* * MedianCutQuantizer quantizer = new MedianCutQuantizer(); * quantizer.setInputImage(image); * quantizer.setPaletteSize(256); * quantizer.process(); * PixelImage quantizedImage = quantizer.getOutputImage(); ** If you want to combine Median Cut quantization with error diffusion dithering to * improve the visual quality of the output, try the * {@link net.sourceforge.jiu.color.dithering.ErrorDiffusionDithering} class. * However, note that noise is introduced into the image with dithering methods so * that the resulting image may not be suitable for automatic processing. *
true
) or paletted
* (argument useTruecolor is false
).
* If the color type is to be changed afterwards, use PromoteToRgb24
* to convert from paletted to truecolor.
* Reducing a truecolor image that uses only 256 or less colors to
* a paletted image can be done with AutoDetectColorType.
* @param useTruecolor
*/
public void setTruecolorOutput(boolean useTruecolor)
{
outputTruecolor = useTruecolor;
}
public void splitNode(MedianCutNode node)
{
if (!node.isAxisDetermined())
{
int[] pairAxisDiff = list.findExtrema(node.getLeftIndex(), node.getRightIndex());
node.setLargestDistribution(pairAxisDiff[0], pairAxisDiff[1]); // axis, difference
}
list.sortByAxis(node.getLeftIndex(), node.getRightIndex(), node.getAxisOfLargestDistribution());
int middleIndex = node.getMiddleIndex();
int leftIndex = node.getLeftIndex();
int rightIndex = node.getRightIndex();
RGBColor color = list.getColor(middleIndex);
int axis = node.getAxisOfLargestDistribution();
int medianValue = color.getSample(axis);
node.setMedianValue(medianValue);
if (leftIndex == rightIndex)
{
throw new IllegalArgumentException("Cannot split leaf that only holds one color. This should never happen.");
}
MedianCutNode left = new MedianCutNode(node, leftIndex, middleIndex);
MedianCutNode right = new MedianCutNode(node, middleIndex + 1, rightIndex);
node.setSuccessors(left, right);
for (int i = 0; i < 3; i++)
{
int max = node.getMaxColorSample(i);
left.setMaxColorSample(i, max);
right.setMaxColorSample(i, max);
int min = node.getMinColorSample(i);
left.setMinColorSample(i, min);
right.setMinColorSample(i, min);
}
left.setMaxColorSample(axis, medianValue);
right.setMinColorSample(axis, medianValue + 1);
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/quantization/OctreeNode.java 0000664 0000000 0000000 00000013606 07741250132 026573 0 ustar /*
* OctreeNode
*
* Copyright (c) 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.color.quantization;
import net.sourceforge.jiu.data.RGBIndex;
import net.sourceforge.jiu.util.ComparatorInterface;
/**
* A single node in an octree.
* @author Marco Schmidt
* @since 0.6.0
* @see OctreeColorQuantizer
*/
public class OctreeNode implements ComparatorInterface, RGBIndex
{
private int paletteIndex;
private int pixelCount;
private int redSum;
private int greenSum;
private int blueSum;
private int red;
private int green;
private int blue;
private OctreeNode[] children;
/**
* Add a color red-green-blue to the octree, given by its root node.
* This methods follows the octree down to the bitsPerSample'th level,
* creating nodes as necessary.
* Increases the pixelCount of a leaf node (if the node already exists)
* or initializes a newly-created leaf.
* @param root root node of the octree
* @param red the red intensity value of the color to be added
* @param green the green intensity value of the color to be added
* @param blue the blue intensity value of the color to be added
* @param bitsPerSample
*/
public static boolean add(OctreeNode root, int red, int green, int blue, int bitsPerSample)
{
OctreeNode node = root;
boolean newColor = false;
int shift = bitsPerSample - 1;
do
{
if (shift >= 0)
{
// not a leaf
OctreeNode[] children = node.children;
if (children == null)
{
children = new OctreeNode[8];
node.children = children;
}
int index = computeIndex(red, green, blue, shift);
node = children[index];
if (node == null)
{
node = new OctreeNode();
children[index] = node;
newColor = true;
}
shift--;
}
else
{
// leaf; update its red/green/blue/pixel count and leave
node.update(red, green, blue);
return newColor;
}
}
while (true);
}
public int compare(Object o1, Object o2)
{
OctreeNode n1 = (OctreeNode)o1;
OctreeNode n2 = (OctreeNode)o2;
int pc1 = n1.pixelCount;
int pc2 = n2.pixelCount;
if (pc1 < pc2)
{
return -1;
}
else
if (pc1 == pc2)
{
return 0;
}
else
{
return 1;
}
}
private static int computeIndex(int red, int green, int blue, int shift)
{
return (((red >> shift) & 1) << 2) |
(((green >> shift) & 1) << 1) |
((blue >> shift) & 1);
}
/**
* Adds the sums for red, green and blue values and
* the pixel count values of all child nodes and
* stores the results in this node.
* Does nothing if this is a leaf.
* Otherwise, recursively calls itself with all
* non-null child nodes and adds their sums for red,
* green and blue and the number of pixel values.
* Then stores these values in this node.
* They will be used when the octree is pruned to have
* a certain number of leaves.
*/
public void copyChildSums()
{
if (children == null)
{
return;
}
redSum = 0;
greenSum = 0;
blueSum = 0;
pixelCount = 0;
for (int i = 0; i < children.length; i++)
{
OctreeNode child = children[i];
if (child != null)
{
child.copyChildSums();
redSum += child.redSum;
greenSum += child.greenSum;
blueSum += child.blueSum;
pixelCount += child.pixelCount;
}
}
}
public void determineRepresentativeColor()
{
if (pixelCount > 0)
{
red = redSum / pixelCount;
green = greenSum / pixelCount;
blue = blueSum / pixelCount;
}
}
/*public static OctreeNode findMinimumNode(OctreeNode node, OctreeNode currentMinimumNode, int minimumNodePixelCount)
{
OctreeNode[] children = node.getChildren();
if (children == null)
{
return currentMinimumNode;
}
int sum = 0;
boolean hasOnlyLeafChildren = true;
for (int i = 0; i < children.length; i++)
{
OctreeNode child = children[i];
if (child != null)
{
if (child.isLeaf())
{
sum += child.pixelCount;
}
else
{
hasOnlyLeafChildren = false;
//findMinimumNode(child, currentMinimumNode, minimumNodePixelCount);
}
}
}
return currentMinimumNode;
}*/
public int getBlue()
{
return blue;
}
public OctreeNode[] getChildren()
{
return children;
}
public int getGreen()
{
return green;
}
public int getNumChildren()
{
int result = 0;
if (children != null)
{
for (int i = 0; i < children.length; i++)
{
if (children[i] != null)
{
result++;
}
}
}
return result;
}
public int getPaletteIndex()
{
return paletteIndex;
}
public int getRed()
{
return red;
}
public boolean isLeaf()
{
return children == null;
}
/**
* Returns the index of the best match for origRgb in the palette or
* -1 if the best match could not be determined.
* If there was a best match, quantizedRgb is filled with the quantized color's
* RGB values.
*/
public int map(int[] origRgb, int[] quantizedRgb)
{
return map(origRgb[INDEX_RED], origRgb[INDEX_GREEN], origRgb[INDEX_BLUE], 7, quantizedRgb);
}
private final int map(final int r, final int g, final int b, final int shift, final int[] quantizedRgb)
{
if (children == null)
{
quantizedRgb[INDEX_RED] = red;
quantizedRgb[INDEX_GREEN] = green;
quantizedRgb[INDEX_BLUE] = blue;
return paletteIndex;
}
int index = computeIndex(r, g, b, shift);
OctreeNode node = children[index];
if (node == null)
{
return -1;
}
return node.map(r, g, b, shift - 1, quantizedRgb);
}
public void setChildren(OctreeNode[] newChildren)
{
children = newChildren;
}
public void setPaletteIndex(int index)
{
paletteIndex = index;
}
private void update(int red, int green, int blue)
{
redSum += red;
greenSum += green;
blueSum += blue;
pixelCount++;
}
}
././@LongLink 0000000 0000000 0000000 00000000151 00000000000 011562 L ustar root root java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/quantization/UniformPaletteQuantizer.java java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/quantization/UniformPaletteQuantizer.0000664 0000000 0000000 00000011145 07741250132 030537 0 ustar /*
* UniformPaletteQuantizer
*
* Copyright (c) 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.color.quantization;
import net.sourceforge.jiu.color.quantization.RGBQuantizer;
import net.sourceforge.jiu.data.MemoryPaletted8Image;
import net.sourceforge.jiu.data.Palette;
import net.sourceforge.jiu.data.Paletted8Image;
import net.sourceforge.jiu.data.RGB24Image;
import net.sourceforge.jiu.data.RGBIndex;
import net.sourceforge.jiu.ops.ImageToImageOperation;
/**
* A color quantizer that maps to a palette which is equidistantly distributed
* in the RGB color cube.
* Equidistantly distributed only within each channel.
* @author Marco Schmidt
*/
public class UniformPaletteQuantizer extends ImageToImageOperation implements
RGBIndex,
RGBQuantizer
{
private final int RED_BITS;
private final int RED_LEFT_SHIFT;
private final int RED_RIGHT_SHIFT;
private final int[] RED_VALUES;
private final int GREEN_BITS;
private final int GREEN_LEFT_SHIFT;
private final int GREEN_RIGHT_SHIFT;
private final int[] GREEN_VALUES;
private final int BLUE_BITS;
private final int BLUE_RIGHT_SHIFT;
private final int[] BLUE_VALUES;
private final int TOTAL_BITS;
private int[] PALETTE_RED;
private int[] PALETTE_GREEN;
private int[] PALETTE_BLUE;
public UniformPaletteQuantizer(int redBits, int greenBits, int blueBits)
{
if (redBits < 1)
{
throw new IllegalArgumentException("Must have at least 1 bit for red.");
}
if (greenBits < 1)
{
throw new IllegalArgumentException("Must have at least 1 bit for green.");
}
if (blueBits < 1)
{
throw new IllegalArgumentException("Must have at least 1 bit for blue.");
}
BLUE_BITS = blueBits;
BLUE_RIGHT_SHIFT = 8 - BLUE_BITS;
BLUE_VALUES = new int[1 << BLUE_BITS];
for (int i = 0; i < BLUE_VALUES.length; i++)
BLUE_VALUES[i] = i * 255 / (BLUE_VALUES.length - 1);
GREEN_BITS = greenBits;
GREEN_RIGHT_SHIFT = 8 - GREEN_BITS;
GREEN_LEFT_SHIFT = BLUE_BITS;
GREEN_VALUES = new int[1 << GREEN_BITS];
for (int i = 0; i < GREEN_VALUES.length; i++)
GREEN_VALUES[i] = i * 255 / (GREEN_VALUES.length - 1);
RED_BITS = redBits;
RED_RIGHT_SHIFT = 8 - RED_BITS;
RED_LEFT_SHIFT = GREEN_BITS + BLUE_BITS;
RED_VALUES = new int[1 << RED_BITS];
for (int i = 0; i < RED_VALUES.length; i++)
RED_VALUES[i] = i * 255 / (RED_VALUES.length - 1);
TOTAL_BITS = RED_BITS + GREEN_BITS + BLUE_BITS;
if (TOTAL_BITS > 8)
{
throw new IllegalArgumentException("Sum of red / green / blue bits must not exceed 8.");
}
}
public Palette createPalette()
{
int numEntries = 1 << TOTAL_BITS;
Palette result = new Palette(numEntries, 255);
PALETTE_RED = new int[numEntries];
PALETTE_GREEN = new int[numEntries];
PALETTE_BLUE = new int[numEntries];
int index = 0;
for (int r = 0; r < (1 << RED_BITS); r++)
{
for (int g = 0; g < (1 << GREEN_BITS); g++)
{
for (int b = 0; b < (1 << BLUE_BITS); b++)
{
//System.out.println(index + ":" + r + ", " + g + ", " + b);
result.putSample(INDEX_RED, index, RED_VALUES[r]);
PALETTE_RED[index] = RED_VALUES[r];
result.putSample(INDEX_GREEN, index, GREEN_VALUES[g]);
PALETTE_GREEN[index] = GREEN_VALUES[g];
result.putSample(INDEX_BLUE, index, BLUE_VALUES[b]);
PALETTE_BLUE[index] = BLUE_VALUES[b];
index++;
}
}
}
return result;
}
public int map(int[] origRgb, int[] quantizedRgb)
{
int index = mapToIndex(origRgb[INDEX_RED], origRgb[INDEX_GREEN], origRgb[INDEX_BLUE]);
quantizedRgb[INDEX_RED] = PALETTE_RED[index];
quantizedRgb[INDEX_GREEN] = PALETTE_GREEN[index];
quantizedRgb[INDEX_BLUE] = PALETTE_BLUE[index];
return index;
}
public final int mapToIndex(int red, int green, int blue)
{
return
((red >> RED_RIGHT_SHIFT) << RED_LEFT_SHIFT) |
((green >> GREEN_RIGHT_SHIFT) << GREEN_LEFT_SHIFT) |
(blue >> BLUE_RIGHT_SHIFT);
}
private void process(RGB24Image in, Paletted8Image out)
{
final int WIDTH = in.getWidth();
final int HEIGHT = in.getHeight();
if (out == null)
{
out = new MemoryPaletted8Image(WIDTH, HEIGHT, createPalette());
}
for (int y = 0; y < HEIGHT; y++)
{
for (int x = 0; x < WIDTH; x++)
{
int r = in.getSample(INDEX_RED, x, y);
int g = in.getSample(INDEX_GREEN, x, y);
int b = in.getSample(INDEX_BLUE, x, y);
out.putSample(0, x, y, mapToIndex(r, g, b));
}
setProgress(y, HEIGHT);
}
setOutputImage(out);
}
public void process()
{
process((RGB24Image)getInputImage(), (Paletted8Image)getOutputImage());
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/quantization/RGBColorList.java 0000664 0000000 0000000 00000011406 07741250132 027005 0 ustar /*
* RGBColorList
*
* Copyright (c) 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.color.quantization;
import net.sourceforge.jiu.color.data.Histogram3D;
import net.sourceforge.jiu.data.RGBIndex;
import net.sourceforge.jiu.util.ComparatorInterface;
import net.sourceforge.jiu.util.Sort;
/**
* Holds an array of {@link RGBColor} objects.
* @author Marco Schmidt
*/
public class RGBColorList implements RGBIndex
{
private RGBColor[] list;
private final int numEntries;
/**
* Creates a color list with room for a fixed number of entries.
* @param numberOfEntries the number of entries in the new list (must be larger than zero)
* @throws IllegalArgumentException if the argument is smaller than one
*/
private RGBColorList(final int NUM_ENTRIES)
{
if (NUM_ENTRIES < 1)
{
throw new IllegalArgumentException("RGBColorList must have at least one entry; got " + NUM_ENTRIES);
}
numEntries = NUM_ENTRIES;
list = new RGBColor[NUM_ENTRIES];
}
/**
* Creates a new list and initializes it with the argument histogram.
* All values from the histogram with a counter larger than zero will
* be added to the list (which will include all colors that appear at least
* once in the image on which the histogram was created).
* @param hist the histogram from which the list will be initialized
* @throws IllegalArgumentException thrown if no histogram entry has a non-zero counter
*/
public RGBColorList(Histogram3D hist)
{
this(hist.getNumUsedEntries());
int i = 0;
final int MAX_RED = hist.getMaxValue(INDEX_RED);
final int MAX_GREEN = hist.getMaxValue(INDEX_GREEN);
final int MAX_BLUE = hist.getMaxValue(INDEX_BLUE);
for (int r = 0; r <= MAX_RED; r++)
{
for (int g = 0; g <= MAX_GREEN; g++)
{
for (int b = 0; b <= MAX_BLUE; b++)
{
int counter = hist.getEntry(r, g, b);
if (counter > 0)
{
list[i++] = new RGBColor(r, g, b, counter);
}
}
}
}
}
/**
* In a given interval of the list this method searches for the color axis
* that has the largest distribution of values.
* Returns a pair of int values;
* the first value is the component (0, 1 or 2),
* the second value is the difference between the minimum and maximum value found in the list.
* Only checks colors from index i1 to i2 of the list.
*/
public int[] findExtrema(int i1, int i2)
{
if (i1 < 0 || i1 >= numEntries || i2 < 0 || i2 >= numEntries || i1 > i2)
{
return null;
}
int[] max = new int[3];
int[] min = new int[3];
RGBColor c = list[i1];
for (int i = 0; i < 3; i++)
{
min[i] = max[i] = c.getSample(i);
}
int i = i1 + 1;
while (i < i2)
{
c = list[i++];
for (int j = 0; j < 3; j++)
{
int cSample = c.getSample(j);
if (cSample < min[j])
{
min[j] = cSample;
}
else
{
if (cSample > max[j])
{
max[j] = cSample;
}
}
}
}
// first value: sample index (0 - 2); second value: difference
int[] result = new int[2];
result[0] = result[1] = -1;
for (i = 0; i < 3; i++)
{
int newDiff = max[i] - min[i];
if (newDiff > result[1])
{
result[0] = i;
result[1] = newDiff;
}
}
return result;
}
/**
* Returns an {@link RGBColor} object from this list, given by its zero-based
* index value.
* @param index zero-based index into the list; must be smaller than {@link #getNumEntries()}
* @return the color object
*/
public RGBColor getColor(int index)
{
return list[index];
}
/**
* Returns the number of color objects in this list.
* @return number of colors in the list
*/
public int getNumEntries()
{
return list.length;
}
/**
* Sorts an interval of the array of colors by one of the three components (RGB).
* @param index1 the index of the first element in the interval
* @param index2 the index of the last element in the interval
* @param axis the color component by which the interval is to be sorted, {@link #INDEX_RED}, {@link #INDEX_GREEN} or {@link #INDEX_BLUE}
*/
public void sortByAxis(int index1, int index2, int axis)
{
Sort.sort(list, index1, index2, new RGBColorComparator(axis));
}
/**
* Sorts an interval of the array of colors by their counters.
* @param index1 the index of the first element in the interval
* @param index2 the index of the last element in the interval
*/
public void sortByCounter(int index1, int index2)
{
Sort.sort(list, index1, index2, new ComparatorInterface()
{
public int compare(Object obj1, Object obj2)
{
RGBColor col1 = (RGBColor)obj1;
RGBColor col2 = (RGBColor)obj2;
return col1.getCounter() - col2.getCounter();
}
});
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/quantization/MedianCutNode.java 0000664 0000000 0000000 00000016265 07741250132 027227 0 ustar /*
* MedianCutNode
*
* Copyright (c) 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.color.quantization;
import net.sourceforge.jiu.color.quantization.RGBColor;
import net.sourceforge.jiu.data.RGBIndex;
/**
* An instance of this node class represents a cuboid part
* of the color cube representing the three-dimensional RGB color space.
* @author Marco Schmidt
* @see MedianCutQuantizer
*/
public class MedianCutNode implements RGBIndex
{
private int axis;
private boolean axisDetermined;
private int diff;
private int index1;
private int index2;
private MedianCutNode leftSuccessor;
private int[] max;
private int medianValue;
private int middleIndex;
private int[] min;
private int paletteIndex;
private MedianCutNode parent;
private int[] reprColor;
private MedianCutNode rightSuccessor;
/**
* Creates a node for a Median Cut tree of nodes with index values for
* some external color array and the parent node.
* This parent is null for the root node.
* @param parent the parent node of this new node, should be null only for the root node
* @param index1 the index value of the first element of colors in the color list
* @param index2 the index value of the last element of colors in the color list; must be larger than or equal to index1
* @throws IllegalArgumentException if index1 is larger than index2
*/
public MedianCutNode(MedianCutNode parent, int index1, int index2)
{
if (index1 > index2)
{
throw new IllegalArgumentException("MedianCutNode constructor, index1 must be smaller than or equal to index2.");
}
this.parent = parent;
this.index1 = index1;
this.index2 = index2;
determineMiddleIndex();
leftSuccessor = null;
rightSuccessor = null;
diff = 0;
axisDetermined = false;
max = new int[3];
min = new int[3];
paletteIndex = -1;
}
/**
* Returns if this node can be split into two.
* This is true if and only if this is a leaf and if the color
* list index values represent an interval of at least length 2.
* @return if this node can be split into two nodes
*/
public boolean canBeSplit()
{
return isLeaf() && index1 != index2;
}
/**
* Computes the distance in RGB color space between the representative color of this node and the
* argument node and returns it as non-negative value.
*/
public double computeRgbDistance(MedianCutNode node)
{
int[] c = node.reprColor;
return RGBColor.computeDistance(reprColor[INDEX_RED], reprColor[INDEX_GREEN], reprColor[INDEX_BLUE], c[INDEX_RED], c[INDEX_GREEN], c[INDEX_BLUE]);
}
/**
* Computes the middle index value of this node.
* It uses the index values given to this node's constructor, index1 and index2.
*/
private void determineMiddleIndex()
{
if (index1 == index2)
{
middleIndex = index1;
}
else
{
middleIndex = (index1 + index2) / 2;
}
}
/**
* Returns the axis of the channel whose samples are most widely
* distributed among the colors that belong to this node.
* @return index of axis, one of the {@link RGBIndex} constants
* @throws IllegalArgumentException if that axis has not been determined
*/
public int getAxisOfLargestDistribution()
{
if (axisDetermined)
{
return axis;
}
else
{
throw new IllegalArgumentException("The axis has not been determined and can thus not be returned.");
}
}
public int getDifferenceOfLargestDistribution()
{
if (axisDetermined)
{
return diff;
}
else
{
throw new IllegalArgumentException("The axis has not been determined and can thus not be returned.");
}
}
public int getLeftIndex()
{
return index1;
}
/**
* Returns left successor node (or null if this node is a leaf).
*/
public MedianCutNode getLeftSuccessor()
{
return leftSuccessor;
}
public int getMaxColorSample(int index)
{
return max[index];
}
public int getMedianValue()
{
return medianValue;
}
public int getMiddleIndex()
{
return middleIndex;
}
public int getMinColorSample(int index)
{
return min[index];
}
public int getNumColors()
{
return index2 - index1 + 1;
}
public int getPaletteIndex()
{
return paletteIndex;
}
/**
* Returns parent node (or null if this node is the root node).
*/
public MedianCutNode getParentNode()
{
return parent;
}
public int[] getRepresentativeColor()
{
return reprColor;
}
public int getRightIndex()
{
return index2;
}
/**
* Returns right successor node (or null if this node is a leaf).
*/
public MedianCutNode getRightSuccessor()
{
return rightSuccessor;
}
public MedianCutNode getSuccessor(int[] rgb)
{
if (rgb[axis] <= medianValue)
{
return leftSuccessor;
}
else
{
return rightSuccessor;
}
}
public boolean isAxisDetermined()
{
return axisDetermined;
}
/**
* Returns if this node is a leaf by checking if both successors are null.
* Note that the case of one successor being null and the other non-null
* should never happen.
* @return if this node is a leaf (true)
*/
public boolean isLeaf()
{
return (leftSuccessor == null && rightSuccessor == null);
}
public void setLargestDistribution(int newAxis, int newDifference)
{
if (newAxis != INDEX_RED && newAxis != INDEX_GREEN && newAxis != INDEX_BLUE)
{
throw new IllegalArgumentException("Axis must be either INDEX_RED, INDEX_GREEN or INDEX_BLUE.");
}
axis = newAxis;
diff = newDifference;
axisDetermined = true;
}
public void setMaxColor(int red, int green, int blue)
{
max[INDEX_RED] = red;
max[INDEX_GREEN] = green;
max[INDEX_BLUE] = blue;
}
public void setMaxColorSample(int index, int value)
{
max[index] = value;
}
public void setMedianValue(int newMedianValue)
{
medianValue = newMedianValue;
}
public void setMinColor(int red, int green, int blue)
{
min[INDEX_RED] = red;
min[INDEX_GREEN] = green;
min[INDEX_BLUE] = blue;
}
public void setMinColorSample(int index, int value)
{
min[index] = value;
}
public void setPaletteIndex(int newPaletteIndex)
{
paletteIndex = newPaletteIndex;
}
public void setRepresentativeColor(int[] aRepresentativeColor)
{
if (aRepresentativeColor != null && aRepresentativeColor.length != 3)
{
throw new IllegalArgumentException("Representative color array argument must have a length of 3.");
}
reprColor = aRepresentativeColor;
}
/**
* Sets the successor nodes for this node.
* The successors must be either both null or both initialized.
* They must not be equal.
* @param left the left successor node
* @param right the left successor node
*/
public void setSuccessors(MedianCutNode left, MedianCutNode right)
{
if ((left == null && right != null) ||
(left != null && right == null))
{
throw new IllegalArgumentException("The successor nodes must be either both null or both initialized .");
}
if (left != null && left == right)
{
throw new IllegalArgumentException("The successor nodes must not be the same.");
}
leftSuccessor = left;
rightSuccessor = right;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/quantization/RGBColorComparator.java 0000664 0000000 0000000 00000002070 10324333347 030177 0 ustar /*
* RGBColorComparator
*
* Copyright (c) 2001, 2002, 2003, 2004, 2005 Marco Schmidt
* All rights reserved.
*/
package net.sourceforge.jiu.color.quantization;
import net.sourceforge.jiu.data.RGBIndex;
import net.sourceforge.jiu.util.ComparatorInterface;
/**
* Compares two {@link RGBColor} objects.
* @author Marco Schmidt
*/
public class RGBColorComparator implements
ComparatorInterface,
RGBIndex
{
private int sortOrder;
public RGBColorComparator(int aSortOrder)
{
setSortOrder(aSortOrder);
}
public int compare(Object o1, Object o2)
{
return ((RGBColor)o1).compareTo((RGBColor)o2, sortOrder);
}
/**
* Sets the internal sort order (it is sorted by one of the three
* RGB components) to the parameter.
*/
public void setSortOrder(int aSortOrder)
{
if (aSortOrder != INDEX_RED && aSortOrder != INDEX_GREEN && aSortOrder != INDEX_BLUE)
{
throw new IllegalArgumentException("The sort order argument must be either INDEX_RED, INDEX_GREEN or INDEX_BLUE.");
}
sortOrder = aSortOrder;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/quantization/package.html 0000664 0000000 0000000 00000001710 07741250132 026153 0 ustar
Classes to perform color image quantization, the reduction of the number of unique colors in an image. This is a lossy operation. Usually a number of colors in the destination image is specified by the user (e.g. 256), then the quantization algorithm creates a copy of the input image that has no more than that number of colors. The goal is to be as close to the original as possible. Depending on the actual number of colors specified and the image content this can lead to varying results.
Quantization is usually done to reduce the amount of data necessary to represent the image. The cost for this reduction is a loss of information.
See the dithering package for algorithms that improve the result of color image quantization algorithms. ././@LongLink 0000000 0000000 0000000 00000000146 00000000000 011566 L ustar root root java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/quantization/OctreeColorQuantizer.java java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/quantization/OctreeColorQuantizer.jav0000664 0000000 0000000 00000024551 10572434210 030524 0 ustar /* * OctreeColorQuantizer * * Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.color.quantization; import net.sourceforge.jiu.color.quantization.RGBQuantizer; import net.sourceforge.jiu.data.MemoryPaletted8Image; import net.sourceforge.jiu.data.Palette; import net.sourceforge.jiu.data.Paletted8Image; import net.sourceforge.jiu.data.PixelImage; import net.sourceforge.jiu.data.RGB24Image; import net.sourceforge.jiu.data.RGBIndex; import net.sourceforge.jiu.ops.ImageToImageOperation; import net.sourceforge.jiu.ops.MissingParameterException; import net.sourceforge.jiu.ops.WrongParameterException; import net.sourceforge.jiu.util.Sort; /** * Performs the octree color quantization algorithm for a given RGB truecolor image. * The quality is usually somewhat inferior to the results of {@link MedianCutQuantizer}. * Note that you can improve the quality by applying a dithering algorithm. * See {@link net.sourceforge.jiu.color.dithering.ErrorDiffusionDithering}. * *
* MemoryRGB24Image image = ...; // initialize * OctreeColorQuantizer ocq = new OctreeColorQuantizer(); * ocq.setInputImage(image); * ocq.setPaletteSize(16); * ocq.process(); * PixelImage quantizedImage = ocq.getOutputImage(); ** *
origRgb
to one of the colors in the
* color map; that color will be written to quantizedRgb
* and its palette index will be returned.
* @param origRgb the color to be mapped to the best-possible counterpart in the
* palette; the array is indexed by the constants from {@link RGBIndex}
* @param quantizedRgb the resulting color from the palette will be written
* to this array; it is also indexed by the constants from {@link RGBIndex}
* @return index of the found color in the palette
*/
public int map(int[] origRgb, int[] quantizedRgb)
{
int result = root.map(origRgb, quantizedRgb);
if (result == -1)
{
int minIndex = 0;
int minDistance = Integer.MAX_VALUE;
int i = 0;
int red = origRgb[INDEX_RED];
int green = origRgb[INDEX_GREEN];
int blue = origRgb[INDEX_BLUE];
while (i < redValues.length)
{
int v = (redValues[i] - red);
int sum = v * v;
v = (greenValues[i] - green);
sum += v * v;
v = (blueValues[i] - blue);
sum += v * v;
if (sum < minDistance)
{
minIndex = i;
minDistance = sum;
}
i++;
}
quantizedRgb[INDEX_RED] = redValues[minIndex];
quantizedRgb[INDEX_GREEN] = greenValues[minIndex];
quantizedRgb[INDEX_BLUE] = blueValues[minIndex];
return minIndex;
}
else
{
// quantizedRgb was filled with values in root.map
return result;
}
}
private void mapImage()
{
RGB24Image in = (RGB24Image)getInputImage();
Palette palette = createPalette();
Paletted8Image out = new MemoryPaletted8Image(in.getWidth(), in.getHeight(), palette);
int[] origRgb = new int[3];
int[] quantizedRgb = new int[3];
for (int y = 0; y < in.getHeight(); y++)
{
for (int x = 0; x < in.getWidth(); x++)
{
origRgb[INDEX_RED] = in.getSample(INDEX_RED, x, y);
origRgb[INDEX_GREEN] = in.getSample(INDEX_GREEN, x, y);
origRgb[INDEX_BLUE] = in.getSample(INDEX_BLUE, x, y);
int index = map(origRgb, quantizedRgb);
out.putSample(0, x, y, index);
}
}
setOutputImage(out);
}
/**
* Initializes an octree, reduces it have as many leaves (or less) as
* the desired palette size and maps the original image to the newly-created
* palette.
*/
public void process() throws
MissingParameterException,
WrongParameterException
{
init();
mapImage();
}
/**
* Reduces the octree until it has as many leaves (or less) than specified
* by the paletteSize
argument in the constructor
* {@link #OctreeColorQuantizer(int)}.
*/
private void pruneOctree()
{
// create an array for as many palette entries as specified by paletteSize
OctreeNode[] a = new OctreeNode[paletteSize];
// initial length is 1, the only element is the root
a[0] = root;
int length = 1;
// create a comparator that will be used to sort the nodes by their pixel count,
// in ascending order
OctreeNode comparator = new OctreeNode();
// loop and split leaves as long as the number of nodes (length) is smaller
// than the desired palette size
while (length < paletteSize)
{
Sort.sort(a, 0, length - 1, comparator);
int index = length - 1;
while (index >= 0)
{
OctreeNode node = a[index];
int numChildren = node.getNumChildren();
// check if current length minus the node which may be split
// plus the number of its children does not exceed the desired palette size
if (numChildren > 0 && length - 1 + numChildren < paletteSize)
{
// child nodes fit in here
if (index < length - 1)
{
System.arraycopy(a, index + 1, a, index, length - index - 1);
}
length--;
OctreeNode[] children = node.getChildren();
for (int i = 0; i < children.length; i++)
{
if (children[i] != null)
{
a[length++] = children[i];
}
}
break;
}
else
{
index--;
}
}
if (index == -1)
{
// we could not find a node to be split
break;
}
}
// in some cases it is not possible to get exactly paletteSize leaves;
// adjust paletteSize to be equal to the number of leaves
// note that length will never be larger than paletteSize, only smaller
// in some cases
paletteSize = length;
// make all found nodes leaves by setting their child nodes to null
for (int i = 0; i < length; i++)
{
a[i].setChildren(null);
}
}
public void setPaletteSize(int newPaletteSize)
{
if (newPaletteSize < 1)
{
throw new IllegalArgumentException("Palette size must be 1 or larger.");
}
if (newPaletteSize > 256)
{
throw new IllegalArgumentException("Palette size must be 256 or smaller.");
}
paletteSize = newPaletteSize;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/quantization/RGBQuantizer.java 0000664 0000000 0000000 00000010002 07741250132 027044 0 ustar /*
* RGBQuantizer
*
* Copyright (c) 2001, 2002 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.color.quantization;
import net.sourceforge.jiu.data.Palette;
/**
* An interface for an RGB color quantizer.
* Color quantizers take an input image and produce an output image
* that looks like the original but uses less colors.
* Keeping the error (the difference between input and output image) as small
* as possible is important - the more similar input and output are, the better.
* * Similarity between to pixels (or, more accurately, the colors of two pixels) * can be defined by their distance in color space. * Imagine two colors given by (r1, g1, b1) * and * (r2, g2, b2). * The distance can then be defined as * sqrt((r1 - r2)2 + * (g1 - g2)2 + (b1 - b2)2) * (with sqrt being the square root). *
* A quantizer has two main tasks: *
* If a quantizer does use a fixed palette, this first step obviously is not * so much about finding the palette but about specifying it. *
* The code that does the mapping from the original to any given palette * could be shared among quantizers - after all, the goal is always the same, * picking the palette entry with the smallest distance in color space * to the original pixel. * However, sometimes the data structures built while finding the palette * can be reused for faster mapping from the original to output. * This is the case for both the MedianCutQuantizer and the OctreeColorQuantizer. *
* Dithering methods like error diffusion dithering * may be used to increase * the quality of the output. * Note however that dithering introduces noise that makes the quantized image harder to * compress and in some cases unusable for post-processing (the noise may be an obstacle for * image processing algorithms). *
* This quantizer interface was designed with JIU's error diffusion dithering operation * {@link net.sourceforge.jiu.color.dithering.ErrorDiffusionDithering} in mind. * * * @author Marco Schmidt */ public interface RGBQuantizer { /** * Return a Palette object with the list of colors to be used in the quantization * process. * That palette may be fixed or created specifically for a given input image. * @return Palette object for destination image */ Palette createPalette(); /** * This method maps a triplet of intensity values to its quantized counterpart * and returns the palette index of that quantized color. * The index values for the two arrays are taken from RGBIndex. * @param origRgb the three samples red, green and blue for which a good match is searched in the palette * @param quantizedRgb will hold the three samples found to be closest to origRgb after the call to this method * @return int index in the palette of the match quantizedRgb */ int map(int[] origRgb, int[] quantizedRgb); } ././@LongLink 0000000 0000000 0000000 00000000153 00000000000 011564 L ustar root root java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/quantization/ArbitraryPaletteQuantizer.java java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/quantization/ArbitraryPaletteQuantize0000664 0000000 0000000 00000014445 07741250132 030625 0 ustar /* * ArbitraryPaletteQuantizer * * Copyright (c) 2001, 2002, 2003 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.color.quantization; import net.sourceforge.jiu.color.quantization.RGBQuantizer; import net.sourceforge.jiu.data.MemoryPaletted8Image; import net.sourceforge.jiu.data.Palette; import net.sourceforge.jiu.data.Paletted8Image; import net.sourceforge.jiu.data.PixelImage; import net.sourceforge.jiu.data.RGB24Image; import net.sourceforge.jiu.data.RGBIndex; import net.sourceforge.jiu.ops.ImageToImageOperation; import net.sourceforge.jiu.ops.MissingParameterException; import net.sourceforge.jiu.ops.WrongParameterException; /** * A color quantizer that maps an {@link net.sourceforge.jiu.data.RGBImage} * to any given palette. * This operation is restricted to RGB24Image and palettes with up to 256 colors. * It picks the color from the palette which is closest to the * color to be quantized (with the minimum distance). * This is a rather naive implementation which, for any given color * to be quantized, computes the distance between it and each color * in the palette (read: this operation is rather slow with a large palette and input image). *
* It uses Manhattan distance (L1) * instead of Euclidean distance (L2). * This saves a square root operation per distance computation. *
* There are more sophisticated nearest * neighbor algorithms available, left for future extensions. * *
This example maps an RGB truecolor image to some palette * we create.
** RGB24Image image = ...; // initialize this * // create some Palette object that you want to map the image to * Palette palette = new Palette(3); // create palette with three entries * palette.put(0, 33, 00, 244); // set first color * palette.put(1, 0, 240, 193); // set second color * palette.put(2, 245, 126, 136); // set third color * ArbitraryPaletteQuantizer quantizer = new ArbitraryPaletteQuantizer(palette); * quantizer.setInputImage(image); * quantizer.process(); * PixelImage quantizedImage = quantizer.getOutputImage(); ** * @author Marco Schmidt * @since 0.5.0 */ public class ArbitraryPaletteQuantizer extends ImageToImageOperation implements RGBIndex, RGBQuantizer { private final int[] RED; private final int[] GREEN; private final int[] BLUE; private Palette palette; private int numEntries; /** * Creates a quantizer that will be able to map pixels (or a complete image) * to the argument palette. */ public ArbitraryPaletteQuantizer(Palette palette) { this.palette = palette; numEntries = palette.getNumEntries(); // create 1D lookup tables for the three components and fill them with // the palette entry data RED = new int[numEntries]; GREEN = new int[numEntries]; BLUE = new int[numEntries]; for (int i = 0; i < numEntries; i++) { RED[i] = palette.getSample(INDEX_RED, i); GREEN[i] = palette.getSample(INDEX_GREEN, i); BLUE[i] = palette.getSample(INDEX_BLUE, i); } } /** * Returns a copy of the palette that was given to the * constructor of this class. * @return new copy of the palette this quantizer works on */ public Palette createPalette() { return (Palette)palette.clone(); } public int map(int[] origRgb, int[] quantizedRgb) { int r = origRgb[INDEX_RED]; int g = origRgb[INDEX_GREEN]; int b = origRgb[INDEX_BLUE]; int minIndex = 0; int minDistance = Integer.MAX_VALUE; for (int index = 0; index < numEntries; index++) { int v = r - RED[index]; int distance = v * v; v = g - GREEN[index]; distance += v * v; v = b - BLUE[index]; distance += v * v; if (distance < minDistance) { minDistance = distance; minIndex = index; } } quantizedRgb[INDEX_RED] = RED[minIndex]; quantizedRgb[INDEX_GREEN] = GREEN[minIndex]; quantizedRgb[INDEX_BLUE] = BLUE[minIndex]; return minIndex; } /** * Finds the best match for the argument color in the palette and returns * its index. * Similar to {@link #map(int[], int[])}, the quantized color is not required * and thus a few assignemnts are saved by this method. * @param red red sample of the pixel to be quantized * @param green green sample of the pixel to be quantized * @param blue blue sample of the pixel to be quantized * @return index of the color in the palette that is closest to the argument color */ public int map(int red, int green, int blue) { int minIndex = 0; int minDistance = Integer.MAX_VALUE; for (int index = 0; index < numEntries; index++) { int v = red - RED[index]; int distance = v * v; v = green - GREEN[index]; distance += v * v; v = blue - BLUE[index]; distance += v * v; if (distance < minDistance) { minDistance = distance; minIndex = index; } } return minIndex; } private void process(RGB24Image in, Paletted8Image out) { final int WIDTH = in.getWidth(); final int HEIGHT = in.getHeight(); if (out == null) { out = new MemoryPaletted8Image(WIDTH, HEIGHT, createPalette()); } for (int y = 0; y < HEIGHT; y++) { for (int x = 0; x < WIDTH; x++) { out.putSample(0, x, y, map(in.getSample(INDEX_RED, x, y), in.getSample(INDEX_GREEN, x, y), in.getSample(INDEX_BLUE, x, y))); } setProgress(y, HEIGHT); } setOutputImage(out); } /** * Maps the input image to an output image, using the palette given to the constructor. */ public void process() throws MissingParameterException, WrongParameterException { ensureInputImageIsAvailable(); PixelImage in = getInputImage(); if (!(in instanceof RGB24Image)) { throw new WrongParameterException("Input image must be of type RGB24Image."); } PixelImage out = getOutputImage(); if (out != null && !(out instanceof Paletted8Image)) { throw new WrongParameterException("Output image must be of type Paletted8Image."); } process((RGB24Image)in, (Paletted8Image)out); } } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/adjustment/ 0000775 0000000 0000000 00000000000 10546532076 023332 5 ustar java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/adjustment/Contrast.java 0000664 0000000 0000000 00000012676 10546773064 026012 0 ustar /* * Contrast * * Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.color.adjustment; import net.sourceforge.jiu.data.GrayIntegerImage; import net.sourceforge.jiu.data.IntegerImage; import net.sourceforge.jiu.data.Palette; import net.sourceforge.jiu.data.Paletted8Image; import net.sourceforge.jiu.data.PixelImage; import net.sourceforge.jiu.data.RGBIntegerImage; import net.sourceforge.jiu.ops.LookupTableOperation; import net.sourceforge.jiu.ops.MissingParameterException; import net.sourceforge.jiu.ops.WrongParameterException; /** * Adjusts the contrast of an image. * The amount of adjustment is given to the constructor as a percentage value between -100 and 100. * -100 will make the resulting image middle-gray, 0 will leave it unchanged, 100 will map it to * the eight corners of the color cube. *
* If all you want is to create a new image with adjusted contrast from the image * data of an existing image, simply use the static helper method: *
PixelImage adjustedImage = Contrast.adjust(inputImage, 30);* This leaves the original image inputImage unchanged and allocates a second * image object which is here assigned to the variable adjustedImage. *
* If you want more control over parameters, create your own Contrast object. * You can then reuse image objects, e.g. to write the adjusted image data * to the original image object: *
* Contrast op = new Contrast(); * op.setInputImage(image); * op.setOutputImage(image); * op.setContrast(30); * op.process(); * // at this point, image will contain the adjusted image data, * // the original data wil be overwritten ** @author Marco Schmidt */ public class Contrast extends LookupTableOperation { private int contrast; /** * This static helper method is more simple to use when all * you need are the standard options. * @param input the image to work on * @param percentage contrast modification, from -100 to 100 * @return a new image with adjusted contrast */ public static PixelImage adjust(PixelImage input, int percentage) { try { Contrast op = new Contrast(); op.setInputImage(input); op.setContrast(percentage); op.process(); return op.getOutputImage(); } catch (Exception exc) { return null; } } private int[] createLookupTable(int numSamples, int contrast) { int[] result = new int[numSamples]; final int MAX = numSamples - 1; final float MID = MAX / 2.0f; for (int i = 0; i < numSamples; i++) { if (contrast < 0) { if (i < MID) { result[i] = (int)(i + (MID - i) * (- contrast) / 100.0f); } else { result[i] = (int)(MID + (i - MID) * (100.0f + contrast) / 100.0f); } } else { if (i < MID) { result[i] = (int)(i * (100.0f - contrast) / 100.0f); } else { result[i] = (int)(i + (MAX - i) * contrast / 100.0f); } } } return result; } /** * Returns the contrast adjustment value associated with this opperation. * The value lies between -100 and 100 (including both values). * @return contrast adjustment * @see #setContrast */ public int getContrast() { return contrast; } private void process(Paletted8Image in, Paletted8Image out) { if (out == null) { out = (Paletted8Image)in.createCompatibleImage(in.getWidth(), in.getHeight()); } Palette palette = out.getPalette(); int numSamples = palette.getMaxValue() + 1; final int[] LUT = createLookupTable(numSamples, contrast); for (int c = 0; c < 3; c++) { for (int i = 0; i < palette.getNumEntries(); i++) { palette.putSample(c, i, LUT[palette.getSample(c, i)]); } } for (int y = 0; y < in.getHeight(); y++) { for (int x = 0; x < in.getWidth(); x++) { out.putSample(0, x, y, in.getSample(0, x, y)); } setProgress(y, in.getHeight()); } setOutputImage(out); } public void process() throws MissingParameterException, WrongParameterException { prepareImages(); IntegerImage in = (IntegerImage)getInputImage(); if (in instanceof GrayIntegerImage || in instanceof RGBIntegerImage) { setNumTables(in.getNumChannels()); for (int channelIndex = 0; channelIndex < in.getNumChannels(); channelIndex++) { setTable(channelIndex, createLookupTable(in.getMaxSample(channelIndex) + 1, getContrast())); } super.process(); } else if (in instanceof Paletted8Image) { process((Paletted8Image)in, (Paletted8Image)getOutputImage()); } else { throw new WrongParameterException("Contrast operation cannot operate on input image type: " + in.getClass()); } } /** * Sets the value for contrast adjustment to be used within this operation. * @param newContrast new contrast, between -100 and 100 (including both values) * @throws IllegalArgumentException if the new contrast value is not in the above mentioned interval * @see #getContrast */ public void setContrast(int newContrast) { if (newContrast < -100) { throw new IllegalArgumentException("Contrast must be at least -100: " + newContrast); } if (newContrast > 100) { throw new IllegalArgumentException("Contrast must be at most 100: " + newContrast); } contrast = newContrast; } } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/adjustment/EqualizeHistogram.java 0000664 0000000 0000000 00000003600 07741250131 027621 0 ustar /* * EqualizeHistogram * * Copyright (c) 2001, 2002, 2003 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.color.adjustment; import net.sourceforge.jiu.color.analysis.Histogram1DCreator; import net.sourceforge.jiu.color.data.Histogram1D; import net.sourceforge.jiu.data.IntegerImage; import net.sourceforge.jiu.ops.LookupTableOperation; import net.sourceforge.jiu.ops.OperationFailedException; /** * Equalize the image using histogram information separately for each channel. * Works for intensity-based image types like {@link net.sourceforge.jiu.data.Gray8Image} or * {@link net.sourceforge.jiu.data.RGB24Image}. * * @author Marco Schmidt * @since 0.6.0 */ public class EqualizeHistogram extends LookupTableOperation { /** * Creates an object of this class and initializes the lookup * tables with the argument input image. * @param in the input image */ public EqualizeHistogram(IntegerImage in) throws OperationFailedException { super(in.getNumChannels()); setInputImage(in); initTables(in); } private void initTables(IntegerImage in) throws OperationFailedException { for (int channelIndex = 0; channelIndex < in.getNumChannels(); channelIndex++) { Histogram1DCreator hc = new Histogram1DCreator(); hc.setImage(in, channelIndex); hc.process(); Histogram1D hist = hc.getHistogram(); final int MAX_SAMPLE = in.getMaxSample(channelIndex); int[] data = new int[MAX_SAMPLE + 1]; int NUM_PIXELS = in.getWidth() * in.getHeight(); long sum = 0; for (int i = 0; i < data.length; i++) { sum += hist.getEntry(i); long result = sum * MAX_SAMPLE / NUM_PIXELS; if (result > (long)Integer.MAX_VALUE) { throw new IllegalStateException("Result does not fit into an int."); } data[i] = (int)result; } setTable(channelIndex, data); } } } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/adjustment/package.html 0000664 0000000 0000000 00000000364 07741250131 025606 0 ustar
Contains operations that modify pixel colors independent from other pixels. java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/adjustment/HueSaturationValue.java 0000664 0000000 0000000 00000020220 10546533516 027761 0 ustar /* * HueSaturationValue * * Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Marco Schmidt * All rights reserved. */ package net.sourceforge.jiu.color.adjustment; import net.sourceforge.jiu.data.Palette; import net.sourceforge.jiu.data.Paletted8Image; import net.sourceforge.jiu.data.PixelImage; import net.sourceforge.jiu.data.RGBIndex; import net.sourceforge.jiu.data.RGBIntegerImage; import net.sourceforge.jiu.ops.ImageToImageOperation; import net.sourceforge.jiu.ops.MissingParameterException; import net.sourceforge.jiu.ops.WrongParameterException; /** * Adjusts saturation and value of a color image, optionally hue as well. *
* Supported image types: {@link RGBIntegerImage}, {@link Paletted8Image}. * @author Marco Schmidt * @since 0.5.0 */ public class HueSaturationValue extends ImageToImageOperation implements RGBIndex { private float hue; private boolean modifyHue; private float sMult; private boolean sNegative; private float vMult; private boolean vNegative; private final void adjust(int[] orig, int[] adjusted, final float maxSample) { // get r-g-b as values from 0.0f to 1.0f float r = orig[INDEX_RED] / maxSample; float g = orig[INDEX_GREEN] / maxSample; float b = orig[INDEX_BLUE] / maxSample; // (1) compute h-s-v float max = Math.max(Math.max(r, g), b); float min = Math.min(Math.min(r, g), b); float v = max; float s; if (max != 0.0f) { s = (max - min) / max; } else { s = 0.0f; } float h; if (s == 0.0f) { h = Float.NaN; } else { float delta = max - min; if (r == max) { h = (g - b) / delta; } else if (g == max) { h = 2.0f + (b - r) / delta; } else { h = 4.0f + (r - g) / delta; } h *= 60.0f; if (h < 0.0f) { h += 360.0f; } } // (2) adjust h-s-v if (modifyHue) { h = hue; } if (sNegative) { s *= sMult; } else { s += (1.0f - s) * sMult; } if (vNegative) { v *= vMult; } else { v += (1.0f - v) * vMult; } // (3) convert back to r-g-b if (s == 0.0f) { if (h == Float.NaN) { int value = (int)(v * maxSample); adjusted[INDEX_RED] = value; adjusted[INDEX_GREEN] = value; adjusted[INDEX_BLUE] = value; return; } else { return; } } if (h == 360.0f) { h = 0.0f; } h /= 60.0f; int i = (int)Math.floor(h); float f = h - i; float p = v * (1 - s); float q = v * (1 - (s * f)); float t = v * (1 - (s * (1 - f))); switch(i) { case(0): { adjusted[INDEX_RED] = (int)(v * maxSample); adjusted[INDEX_GREEN] = (int)(t * maxSample); adjusted[INDEX_BLUE] = (int)(p * maxSample); break; } case(1): { adjusted[INDEX_RED] = (int)(q * maxSample); adjusted[INDEX_GREEN] = (int)(v * maxSample); adjusted[INDEX_BLUE] = (int)(p * maxSample); break; } case(2): { adjusted[INDEX_RED] = (int)(p * maxSample); adjusted[INDEX_GREEN] = (int)(v * maxSample); adjusted[INDEX_BLUE] = (int)(t * maxSample); break; } case(3): { adjusted[INDEX_RED] = (int)(p * maxSample); adjusted[INDEX_GREEN] = (int)(q * maxSample); adjusted[INDEX_BLUE] = (int)(v * maxSample); break; } case(4): { adjusted[INDEX_RED] = (int)(t * maxSample); adjusted[INDEX_GREEN] = (int)(p * maxSample); adjusted[INDEX_BLUE] = (int)(v * maxSample); break; } case(5): { adjusted[INDEX_RED] = (int)(v * maxSample); adjusted[INDEX_GREEN] = (int)(p * maxSample); adjusted[INDEX_BLUE] = (int)(q * maxSample); break; } } } private void process(Paletted8Image in, Paletted8Image out) { Palette inPal = in.getPalette(); Palette outPal = out.getPalette(); int[] orig = new int[3]; int[] adjusted = new int[3]; final int MAX = inPal.getMaxValue(); final int WIDTH = in.getWidth(); final int HEIGHT = in.getHeight(); for (int i = 0; i < inPal.getNumEntries(); i++) { orig[INDEX_RED] = inPal.getSample(INDEX_RED, i); orig[INDEX_GREEN] = inPal.getSample(INDEX_GREEN, i); orig[INDEX_BLUE] = inPal.getSample(INDEX_BLUE, i); adjust(orig, adjusted, MAX); outPal.putSample(INDEX_RED, i, adjusted[INDEX_RED]); outPal.putSample(INDEX_GREEN, i, adjusted[INDEX_GREEN]); outPal.putSample(INDEX_BLUE, i, adjusted[INDEX_BLUE]); } for (int y = 0; y < HEIGHT; y++) { for (int x = 0; x < WIDTH; x++) { out.putSample(0, x, y, in.getSample(0, x, y)); } setProgress(y, HEIGHT); } } private void process(RGBIntegerImage in, RGBIntegerImage out) { final int MAX = in.getMaxSample(0); final int WIDTH = in.getWidth(); final int HEIGHT = in.getHeight(); int[] orig = new int[3]; int[] adjusted = new int[3]; for (int y = 0; y < HEIGHT; y++) { for (int x = 0; x < WIDTH; x++) { orig[INDEX_RED] = in.getSample(INDEX_RED, x, y); orig[INDEX_GREEN] = in.getSample(INDEX_GREEN, x, y); orig[INDEX_BLUE] = in.getSample(INDEX_BLUE, x, y); adjust(orig, adjusted, MAX); out.putSample(INDEX_RED, x, y, adjusted[INDEX_RED]); out.putSample(INDEX_GREEN, x, y, adjusted[INDEX_GREEN]); out.putSample(INDEX_BLUE, x, y, adjusted[INDEX_BLUE]); } setProgress(y, HEIGHT); } } public void process() throws MissingParameterException, WrongParameterException { PixelImage in = getInputImage(); if (in == null) { throw new MissingParameterException("Input image missing."); } PixelImage out = getOutputImage(); if (out == null) { out = in.createCompatibleImage(in.getWidth(), in.getHeight()); setOutputImage(out); } if (in instanceof RGBIntegerImage) { process((RGBIntegerImage)in, (RGBIntegerImage)out); } else if (in instanceof Paletted8Image) { process((Paletted8Image)in, (Paletted8Image)out); } else { throw new WrongParameterException("Input image type not supported."); } } /** * Set the values for the adjustment of hue, saturation and value (brightness). * Saturation and value must be from the interval -100 to 100 (also see {@link #setSaturationValue(int, int)}). * Hue must be from the interval 0 to 359. * @param hue the hue to be used for the complete image, between 0 and 359 * @param saturation change of saturation, between -100 and 100 * @param value change of saturation, between -100 and 100 * @throws IllegalArgumentException if one of the arguments does not stay within * the valid interval */ public void setHueSaturationValue(int hue, int saturation, int value) { if (hue < 0 || hue >= 360) { throw new IllegalArgumentException("Hue must be from 0..359; got " + hue); } modifyHue = true; this.hue = hue; setSv(saturation, value); } /** * Set the amount of change to saturation and value (brightness) for this operation, * between -100 and 100. * Calling this method also tells the operation not to modify the hue of the image. * @param saturation change of saturation, between -100 and 100 * @param value change of saturation, between -100 and 100 * @throws IllegalArgumentException if one of the two arguments does not stay within * the -100 .. 100 interval */ public void setSaturationValue(int saturation, int value) { modifyHue = false; setSv(saturation, value); } private void setSv(int saturation, int value) { if (saturation < -100 || saturation > 100) { throw new IllegalArgumentException("Saturation must be from -100..100; got " + saturation); } sNegative = (saturation < 0); if (sNegative) { sMult = (100.0f + saturation) / 100.0f; } else if (saturation > 0) { sMult = ((float)saturation) / 100.0f; } else { sMult = 0.0f; } if (value < -100 || value > 100) { throw new IllegalArgumentException("Saturation must be from -100..100; got " + value); } vNegative = (value < 0); if (vNegative) { vMult = (100.0f + value) / 100.0f; } else if (value > 0) { vMult = ((float)value) / 100.0f; } else { vMult = 0.0f; } } } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/adjustment/NormalizeHistogram.java 0000664 0000000 0000000 00000003441 07741250131 030005 0 ustar /* * NormalizeHistogram * * Copyright (c) 2001, 2002 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.color.adjustment; import net.sourceforge.jiu.color.analysis.Histogram1DCreator; import net.sourceforge.jiu.color.data.Histogram1D; import net.sourceforge.jiu.data.IntegerImage; import net.sourceforge.jiu.ops.LookupTableOperation; import net.sourceforge.jiu.ops.OperationFailedException; /** * Normalize the image using histogram information, separately for each * channel. * Works for intensity-based image types like {@link net.sourceforge.jiu.data.Gray8Image} or * {@link net.sourceforge.jiu.data.RGB24Image}. * * @author Marco Schmidt * @since 0.6.0 */ public class NormalizeHistogram extends LookupTableOperation { /** * Creates an object of this class and initializes the lookup * tables with the argument input image. */ public NormalizeHistogram(IntegerImage in) throws OperationFailedException { super(in.getNumChannels()); setInputImage(in); initTables(in); } private void initTables(IntegerImage in) throws OperationFailedException { for (int channelIndex = 0; channelIndex < in.getNumChannels(); channelIndex++) { Histogram1DCreator hc = new Histogram1DCreator(); hc.setImage(in, channelIndex); hc.process(); Histogram1D hist = hc.getHistogram(); int min = 0; while (hist.getEntry(min) == 0) { min++; } int maxSample = in.getMaxSample(channelIndex); int max = maxSample; while (hist.getEntry(max) == 0) { max--; } int[] data = new int[maxSample + 1]; int usedInterval = max - min + 1; for (int i = 0; i < data.length; i++) { data[i] = min + usedInterval * i / data.length; } setTable(channelIndex, data); } } } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/adjustment/Brightness.java 0000664 0000000 0000000 00000012616 10541052231 026274 0 ustar /* * Brightness * * Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.color.adjustment; import net.sourceforge.jiu.data.GrayIntegerImage; import net.sourceforge.jiu.data.IntegerImage; import net.sourceforge.jiu.data.Palette; import net.sourceforge.jiu.data.Paletted8Image; import net.sourceforge.jiu.data.PixelImage; import net.sourceforge.jiu.data.RGBIntegerImage; import net.sourceforge.jiu.ops.LookupTableOperation; import net.sourceforge.jiu.ops.MissingParameterException; import net.sourceforge.jiu.ops.WrongParameterException; /** * Adjusts the brightness of an image. *
* The brightness change is specified as a percentage value between -100 and 100. * -100 will make the resulting image black, 0 will leave it unchanged, 100 will make it white. *
* If all you want is to create a new image with adjusted brightness from the image * data of an existing image, simply use the static helper method: *
PixelImage adjustedImage = Brightness.adjust(inputImage, 30);* This leaves the original image inputImage unchanged and allocates a second * image object which is here assigned to the variable adjustedImage. *
* If you want more control over parameters, create your own Brightness object. * You can then reuse image objects, e.g. to write the adjusted image data * to the original image object: *
* Brightness brightness = new Brightness(); * brightness.setInputImage(image); * brightness.setOutputImage(image); * brightness.setBrightness(30); * brightness.process(); * // at this point, image will contain the adjusted image data, * // the original data wil be overwritten **
* @author Marco Schmidt */ public class Brightness extends LookupTableOperation { private int brightness; /** * This static helper method is more simple to use when all * you need are the standard options. * @param input the image to work on * @param percentage brightness modification, from -100 to 100 * @return a new image with adjusted brightness */ public static PixelImage adjust(PixelImage input, int percentage) { try { Brightness brightness = new Brightness(); brightness.setInputImage(input); brightness.setBrightness(percentage); brightness.process(); return brightness.getOutputImage(); } catch (Exception exc) { return null; } } /** * Creates a lookup table that holds all new values for samples 0 to * numSamples - 1. */ private int[] createLookupTable(int numSamples, int brightness) { if (brightness < -100 || brightness > 100) { return null; } int[] result = new int[numSamples]; final int MAX = numSamples - 1; for (int i = 0; i < numSamples; i++) { if (brightness < 0) { result[i] = (int)((float)i * (100.0f + brightness) / 100.0f); } else { result[i] = (int)(i + (MAX - i) * brightness / 100.0f); } } return result; } private void process(Paletted8Image in, Paletted8Image out) { if (out == null) { out = (Paletted8Image)in.createCompatibleImage(in.getWidth(), in.getHeight()); } Palette palette = out.getPalette(); int numSamples = palette.getNumEntries(); final int[] LUT = createLookupTable(numSamples, brightness); for (int c = 0; c < 3; c++) { for (int i = 0; i < palette.getNumEntries(); i++) { palette.putSample(c, i, LUT[palette.getSample(c, i)]); } } for (int y = 0; y < in.getHeight(); y++) { for (int x = 0; x < in.getWidth(); x++) { out.putSample(0, x, y, in.getSample(0, x, y)); } setProgress(y, in.getHeight()); } setOutputImage(out); } public void process() throws MissingParameterException, WrongParameterException { prepareImages(); IntegerImage in = (IntegerImage)getInputImage(); if (in instanceof GrayIntegerImage || in instanceof RGBIntegerImage) { setNumTables(in.getNumChannels()); for (int channelIndex = 0; channelIndex < in.getNumChannels(); channelIndex++) { setTable(channelIndex, createLookupTable(in.getMaxSample(channelIndex) + 1, brightness)); } super.process(); } else if (in instanceof Paletted8Image) { process((Paletted8Image)in, (Paletted8Image)getOutputImage()); } else { throw new WrongParameterException("Brightness operation cannot operate on input image type: " + in.getClass()); } } /** * Sets the brightness adjustment value in percent (between -100 and 100). * @param newBrightness the amount of change to be applied to the brightness of the input image * @throws IllegalArgumentException if the argument is smaller than -100 or larger than 100 */ public void setBrightness(int newBrightness) { if (newBrightness < -100) { throw new IllegalArgumentException("Brightness must be at least -100: " + newBrightness); } if (newBrightness > 100) { throw new IllegalArgumentException("Brightness must be at most 100: " + newBrightness); } brightness = newBrightness; } } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/adjustment/GammaCorrection.java 0000664 0000000 0000000 00000011772 07741250131 027247 0 ustar /* * GammaCorrection * * Copyright (c) 2001, 2002, 2003 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.color.adjustment; import net.sourceforge.jiu.data.GrayIntegerImage; import net.sourceforge.jiu.data.IntegerImage; import net.sourceforge.jiu.data.Palette; import net.sourceforge.jiu.data.Paletted8Image; import net.sourceforge.jiu.data.PixelImage; import net.sourceforge.jiu.data.RGBIntegerImage; import net.sourceforge.jiu.ops.LookupTableOperation; import net.sourceforge.jiu.ops.MissingParameterException; import net.sourceforge.jiu.ops.WrongParameterException; /** * Corrects the gamma of an image. * Works with {@link net.sourceforge.jiu.data.GrayIntegerImage}, * {@link net.sourceforge.jiu.data.RGBIntegerImage} and * {@link net.sourceforge.jiu.data.Paletted8Image}. * Only the palette is manipulated for paletted images. *
* Changes intensity values by applying the formula
* f(x) = MAX * (x / MAX)(1 / gamma) to each
* x from [0 ; MAX] to them.
* The MAX value is the maximum value allowed for an intensity value of the
* corresponding channel.
* It is determined by calling {@link net.sourceforge.jiu.data.IntegerImage#getMaxSample} on
* the input image.
* The gamma parameter must be given to a GammaCorrection
operation
* before the call to {@link #process} is made.
* The valid interval for gamma is (0.0 ; {@link #MAX_GAMMA}]
* (so 0.0 is not a valid value).
* Gamma values smaller than 1 will make the image darker, values
* larger than 1 will make it brighter.
*
* GammaCorrection gamma = new GammaCorrection(); * gamma.setInputImage(image); * gamma.setGamma(2.2); * gamma.process(); * PixelImage correctedImage = gamma.getOutputImage(); ** @author Marco Schmidt */ public class GammaCorrection extends LookupTableOperation { /** * The maximum allowed value for gamma. */ public static final double MAX_GAMMA = 10.0; private double gamma; /** * Creates a lookup table that holds all new values for samples 0 to * numSamples - 1. */ private final int[] createLookupTable(int numSamples) { if (numSamples < 1) { throw new IllegalArgumentException("Number of samples argument must be one or larger."); } double g = 1.0 / gamma; int[] result = new int[numSamples]; final int MAX_SAMPLE = numSamples - 1; final double MAX = MAX_SAMPLE; for (int i = 0; i < numSamples; i++) { result[i] = (int)Math.round((MAX * Math.pow((i / MAX), g))); if (result[i] < 0) { result[i] = 0; } if (result[i] > MAX_SAMPLE) { result[i] = MAX_SAMPLE; } } return result; } /** * Returns the gamma value to be used for this operation. * @return gamma value between 0 (not included) and {@link #MAX_GAMMA} */ public double getGamma() { return gamma; } private void process(Paletted8Image in, Paletted8Image out) { if (out == null) { out = (Paletted8Image)in.createCompatibleImage(in.getWidth(), in.getHeight()); setOutputImage(out); } Palette palette = out.getPalette(); int numSamples = palette.getMaxValue() + 1; final int[] LUT = createLookupTable(numSamples); for (int c = 0; c < 3; c++) { for (int i = 0; i < palette.getNumEntries(); i++) { palette.putSample(c, i, LUT[palette.getSample(c, i)]); } } for (int y = 0; y < in.getHeight(); y++) { for (int x = 0; x < in.getWidth(); x++) { out.putSample(x, y, in.getSample(x, y)); } setProgress(y, in.getHeight()); } } public void process() throws MissingParameterException, WrongParameterException { ensureInputImageIsAvailable(); PixelImage in = getInputImage(); if (in instanceof Paletted8Image) { process((Paletted8Image)getInputImage(), (Paletted8Image)getOutputImage()); } else if (in instanceof GrayIntegerImage || in instanceof RGBIntegerImage) { setNumTables(in.getNumChannels()); IntegerImage ii = (IntegerImage)in; for (int channelIndex = 0; channelIndex < in.getNumChannels(); channelIndex++) { int numSamples = ii.getMaxSample(channelIndex) + 1; int[] table = createLookupTable(numSamples); setTable(channelIndex, table); } super.process(); } else { throw new WrongParameterException("Unsupported image type: " + in.getClass().getName()); } } /** * Sets a new gamma value to be used in this operation. * @param newGamma the new gamma value must be > 0.0 and <= MAX_GAMMA * @throws IllegalArgumentException if the argument is not in the described interval */ public void setGamma(double newGamma) { if (newGamma <= 0.0) { throw new IllegalArgumentException("Gamma must be larger than 0.0; got " + newGamma); } if (newGamma > MAX_GAMMA) { throw new IllegalArgumentException("Gamma must be at most " + MAX_GAMMA + "; got " + newGamma); } gamma = newGamma; } } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/promotion/ 0000775 0000000 0000000 00000000000 10546532076 023202 5 ustar java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/promotion/PromotionGray16.java 0000664 0000000 0000000 00000006140 07741250132 027017 0 ustar /* * PromotionGray16 * * Copyright (c) 2003 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.color.promotion; import net.sourceforge.jiu.data.BilevelImage; import net.sourceforge.jiu.data.Gray16Image; import net.sourceforge.jiu.data.Gray8Image; import net.sourceforge.jiu.data.MemoryGray16Image; import net.sourceforge.jiu.data.PixelImage; import net.sourceforge.jiu.ops.ImageToImageOperation; import net.sourceforge.jiu.ops.MissingParameterException; import net.sourceforge.jiu.ops.WrongParameterException; /** * Converts BilevelImage and Gray8Image objects to Gray16Image objects. * Promotion is a lossless operation that will lead to an output image * that holds the same image in a way that demands more memory. * @author Marco Schmidt * @since 0.11.0 */ public class PromotionGray16 extends ImageToImageOperation { private void prepare(PixelImage in) throws MissingParameterException, WrongParameterException { if (in == null) { throw new MissingParameterException("Missing input image."); } if (! ( (in instanceof BilevelImage) || (in instanceof Gray8Image) ) ) { throw new WrongParameterException("Unsupported input image type: " + in.getClass().getName()); } PixelImage out = getOutputImage(); if (out == null) { setOutputImage(new MemoryGray16Image(in.getWidth(), in.getHeight())); } else { if (!(out instanceof Gray16Image)) { throw new WrongParameterException("Specified output image type must be of class Gray16Image; got " + in.getClass().getName()); } if (in.getWidth() != out.getWidth()) { throw new WrongParameterException("Specified output image must have same width as input image."); } if (in.getHeight() != out.getHeight()) { throw new WrongParameterException("Specified output image must have same height as input image."); } } } private void process(BilevelImage in, Gray16Image out) { final int WIDTH = in.getWidth(); final int HEIGHT = in.getHeight(); final short MAX = (short)out.getMaxSample(0); final short MIN = 0; for (int y = 0; y < HEIGHT; y++) { for (int x = 0; x < WIDTH; x++) { if (in.isBlack(x, y)) { out.putShortSample(0, x, y, MIN); } else { out.putShortSample(0, x, y, MAX); } } setProgress(y, HEIGHT); } } private void process(Gray8Image in, Gray16Image out) { final int WIDTH = in.getWidth(); final int HEIGHT = in.getHeight(); for (int y = 0; y < HEIGHT; y++) { for (int x = 0; x < WIDTH; x++) { int sample = in.getSample(x, y); out.putSample(x, y, sample | (sample << 8)); } setProgress(y, HEIGHT); } } public void process() throws MissingParameterException, WrongParameterException { PixelImage in = getInputImage(); prepare(in); Gray16Image out = (Gray16Image)getOutputImage(); if (in instanceof BilevelImage) { process((BilevelImage)in, out); } else if (in instanceof Gray8Image) { process((Gray8Image)in, out); } } } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/promotion/package.html 0000664 0000000 0000000 00000001472 07741250132 025460 0 ustar
Classes to convert JIU image objects to other image types that require more memory.
This is a lossless operation, all information is kept.
However, the new image object typically requires more memory to store the same information.
A promotion operation is necessary if a certain operation cannot be performed on
a smaller
image type, but once the image has been promoted to a larger
type, the operation becomes possible.
Example: Convolution kernel filtering cannot be applied to paletted images. They require intensity information on each pixel. Once a paletted image has been promoted to be an RGB truecolor image, filtering is possible. java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/promotion/PromotionRGB24.java 0000664 0000000 0000000 00000011116 10377270770 026536 0 ustar /* * PromotionRGB24 * * Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.color.promotion; import net.sourceforge.jiu.data.BilevelImage; import net.sourceforge.jiu.data.Gray8Image; import net.sourceforge.jiu.data.MemoryRGB24Image; import net.sourceforge.jiu.data.Palette; import net.sourceforge.jiu.data.Paletted8Image; import net.sourceforge.jiu.data.PixelImage; import net.sourceforge.jiu.data.RGB24Image; import net.sourceforge.jiu.data.RGBIndex; import net.sourceforge.jiu.ops.ImageToImageOperation; import net.sourceforge.jiu.ops.MissingParameterException; import net.sourceforge.jiu.ops.WrongParameterException; /** * Converts several image types to RGB. * Promoting is a lossless operation that will only lead to an output image * that holds the same image in a way that demands more memory. *
* If you give an image implementing RGB24Image to this operation, a * WrongParameterException will be thrown. * This operation could also return the input image, but this might lead * to the wrong impression that a copy of the input was produced which * can be modified without changing the original. * * @author Marco Schmidt */ public class PromotionRGB24 extends ImageToImageOperation { private void prepare(PixelImage in) throws MissingParameterException, WrongParameterException { if (in == null) { throw new MissingParameterException("Missing input image."); } if (! ( (in instanceof BilevelImage) || (in instanceof Paletted8Image) || (in instanceof Gray8Image) ) ) { throw new WrongParameterException("Unsupported input image type: " + in.getClass().getName()); } PixelImage out = getOutputImage(); if (out == null) { setOutputImage(new MemoryRGB24Image(in.getWidth(), in.getHeight())); } else { if (!(out instanceof RGB24Image)) { throw new WrongParameterException("Specified output image type must be of class RGB24Image; got " + in.getClass().getName()); } if (in.getWidth() != out.getWidth()) { throw new WrongParameterException("Specified output image must have same width as input image."); } if (in.getHeight() != out.getHeight()) { throw new WrongParameterException("Specified output image must have same height as input image."); } } } private void process(BilevelImage in, RGB24Image out) { final int HEIGHT = in.getHeight(); final byte MAX = (byte)255; final byte MIN = (byte)0; for (int y = 0; y < HEIGHT; y++) { for (int x = 0; x < in.getWidth(); x++) { if (in.isBlack(x, y)) { out.putByteSample(RGBIndex.INDEX_RED, x, y, MIN); out.putByteSample(RGBIndex.INDEX_GREEN, x, y, MIN); out.putByteSample(RGBIndex.INDEX_BLUE, x, y, MIN); } else { out.putByteSample(RGBIndex.INDEX_RED, x, y, MAX); out.putByteSample(RGBIndex.INDEX_GREEN, x, y, MAX); out.putByteSample(RGBIndex.INDEX_BLUE, x, y, MAX); } } setProgress(y, HEIGHT); } } private void process(Paletted8Image in, RGB24Image out) { final int WIDTH = in.getWidth(); final int HEIGHT = in.getHeight(); final Palette PAL = in.getPalette(); for (int y = 0; y < HEIGHT; y++) { for (int x = 0; x < WIDTH; x++) { int value = in.getSample(0, x, y); out.putSample(RGBIndex.INDEX_RED, x, y, PAL.getSample(RGBIndex.INDEX_RED, value)); out.putSample(RGBIndex.INDEX_GREEN, x, y, PAL.getSample(RGBIndex.INDEX_GREEN, value)); out.putSample(RGBIndex.INDEX_BLUE, x, y, PAL.getSample(RGBIndex.INDEX_BLUE, value)); } setProgress(y, HEIGHT); } } private void process(Gray8Image in, RGB24Image out) { final int WIDTH = in.getWidth(); final int HEIGHT = in.getHeight(); for (int y = 0; y < HEIGHT; y++) { for (int x = 0; x < WIDTH; x++) { int value = in.getSample(0, x, y); out.putSample(RGBIndex.INDEX_RED, x, y, value); out.putSample(RGBIndex.INDEX_GREEN, x, y, value); out.putSample(RGBIndex.INDEX_BLUE, x, y, value); } setProgress(y, HEIGHT); } } public void process() throws MissingParameterException, WrongParameterException { PixelImage in = getInputImage(); prepare(in); RGB24Image out = (RGB24Image)getOutputImage(); if (in instanceof BilevelImage) { process((BilevelImage)in, out); } else if (in instanceof Gray8Image) { process((Gray8Image)in, out); } else if (in instanceof Paletted8Image) { process((Paletted8Image)in, out); } } } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/promotion/PromotionPaletted8.java 0000664 0000000 0000000 00000006552 07741250132 027607 0 ustar /* * PromotionPaletted8 * * Copyright (c) 2001, 2002, 2003 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.color.promotion; import net.sourceforge.jiu.data.BilevelImage; import net.sourceforge.jiu.data.Gray8Image; import net.sourceforge.jiu.data.MemoryPaletted8Image; import net.sourceforge.jiu.data.Palette; import net.sourceforge.jiu.data.Paletted8Image; import net.sourceforge.jiu.data.PixelImage; import net.sourceforge.jiu.ops.ImageToImageOperation; import net.sourceforge.jiu.ops.MissingParameterException; import net.sourceforge.jiu.ops.WrongParameterException; /** * Converts {@link BilevelImage} and {@link Gray8Image} objects to * {@link Paletted8Image} objects. * This lossless operation will only lead to an output image * that holds the input image in a way that demands more memory. * * @author Marco Schmidt * @since 0.8.0 */ public class PromotionPaletted8 extends ImageToImageOperation { private void prepare(PixelImage in) throws MissingParameterException, WrongParameterException { if (in == null) { throw new MissingParameterException("Missing input image."); } Palette palette = null; if (in instanceof BilevelImage) { palette = new Palette(2, 255); palette.put(0, 0, 0, 0); palette.put(1, 255, 255, 255); } else if (in instanceof Gray8Image) { palette = new Palette(256, 255); for (int i = 0; i < 256; i++) { palette.put(i, i, i, i); } } else { throw new WrongParameterException("Unsupported input image type: " + in.getClass().getName()); } PixelImage out = getOutputImage(); if (out == null) { setOutputImage(new MemoryPaletted8Image(in.getWidth(), in.getHeight(), palette)); } else { if (!(out instanceof Paletted8Image)) { throw new WrongParameterException("Specified output image type must be of class Paletted8Image; got " + in.getClass().getName()); } if (in.getWidth() != out.getWidth()) { throw new WrongParameterException("Specified output image must have same width as input image."); } if (in.getHeight() != out.getHeight()) { throw new WrongParameterException("Specified output image must have same height as input image."); } } } private void process(BilevelImage in, Paletted8Image out) { final int WIDTH = in.getWidth(); final int HEIGHT = in.getHeight(); for (int y = 0; y < HEIGHT; y++) { for (int x = 0; x < WIDTH; x++) { if (in.isBlack(x, y)) { out.putByteSample(0, x, y, (byte)0); } else { out.putByteSample(0, x, y, (byte)1); } } setProgress(y, HEIGHT); } } private void process(Gray8Image in, Paletted8Image out) { final int WIDTH = in.getWidth(); final int HEIGHT = in.getHeight(); // simple copy for (int y = 0; y < HEIGHT; y++) { for (int x = 0; x < WIDTH; x++) { out.putSample(0, x, y, in.getSample(0, x, y)); } setProgress(y, HEIGHT); } } public void process() throws MissingParameterException, WrongParameterException { PixelImage in = getInputImage(); prepare(in); Paletted8Image out = (Paletted8Image)getOutputImage(); if (in instanceof BilevelImage) { process((BilevelImage)in, out); } else if (in instanceof Gray8Image) { process((Gray8Image)in, out); } } } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/promotion/PromotionGray8.java 0000664 0000000 0000000 00000005100 07741250132 026733 0 ustar /* * PromotionGray8 * * Copyright (c) 2001, 2002, 2003 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.color.promotion; import net.sourceforge.jiu.data.BilevelImage; import net.sourceforge.jiu.data.Gray8Image; import net.sourceforge.jiu.data.MemoryGray8Image; import net.sourceforge.jiu.data.PixelImage; import net.sourceforge.jiu.ops.ImageToImageOperation; import net.sourceforge.jiu.ops.MissingParameterException; import net.sourceforge.jiu.ops.WrongParameterException; /** * Converts BilevelImage objects to Gray8Image objects. * Promotion is a lossless operation that will lead to an output image * that holds the same image in a way that demands more memory. * * @author Marco Schmidt * @since 0.8.0 */ public class PromotionGray8 extends ImageToImageOperation { private void prepare(PixelImage in) throws MissingParameterException, WrongParameterException { if (in == null) { throw new MissingParameterException("Missing input image."); } if (! ( (in instanceof BilevelImage) ) ) { throw new WrongParameterException("Unsupported input image type: " + in.getClass().getName()); } PixelImage out = getOutputImage(); if (out == null) { setOutputImage(new MemoryGray8Image(in.getWidth(), in.getHeight())); } else { if (!(out instanceof Gray8Image)) { throw new WrongParameterException("Specified output image type must be of class Gray8Image; got " + in.getClass().getName()); } if (in.getWidth() != out.getWidth()) { throw new WrongParameterException("Specified output image must have same width as input image."); } if (in.getHeight() != out.getHeight()) { throw new WrongParameterException("Specified output image must have same height as input image."); } } } private void process(BilevelImage in, Gray8Image out) { final int WIDTH = in.getWidth(); final int HEIGHT = in.getHeight(); final byte MAX = (byte)255; final byte MIN = (byte)0; for (int y = 0; y < HEIGHT; y++) { for (int x = 0; x < WIDTH; x++) { if (in.isBlack(x, y)) { out.putByteSample(0, x, y, MIN); } else { out.putByteSample(0, x, y, MAX); } } setProgress(y, HEIGHT); } } public void process() throws MissingParameterException, WrongParameterException { PixelImage in = getInputImage(); prepare(in); Gray8Image out = (Gray8Image)getOutputImage(); if (in instanceof BilevelImage) { process((BilevelImage)in, out); } } } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/promotion/PromotionRGB48.java 0000664 0000000 0000000 00000013611 10377273656 026554 0 ustar /* * PromotionRGB48 * * Copyright (c) 2003, 2004, 2005, 2006 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.color.promotion; import net.sourceforge.jiu.data.BilevelImage; import net.sourceforge.jiu.data.Gray16Image; import net.sourceforge.jiu.data.Gray8Image; import net.sourceforge.jiu.data.MemoryRGB48Image; import net.sourceforge.jiu.data.Palette; import net.sourceforge.jiu.data.Paletted8Image; import net.sourceforge.jiu.data.PixelImage; import net.sourceforge.jiu.data.RGB24Image; import net.sourceforge.jiu.data.RGB48Image; import net.sourceforge.jiu.data.RGBIndex; import net.sourceforge.jiu.ops.ImageToImageOperation; import net.sourceforge.jiu.ops.MissingParameterException; import net.sourceforge.jiu.ops.WrongParameterException; /** * Converts several image types to {@link net.sourceforge.jiu.data.RGB48Image}. * Promotion is a lossless operation that will only lead to an output image * that holds the same image in a way that demands more memory. *
* If you give an image implementing RGB24Image to this operation, a * WrongParameterException will be thrown. * This operation could also return the input image, but this might lead * to the wrong impression that a copy of the input was produced which * can be modified without changing the original. * @author Marco Schmidt * @since 0.12.0 */ public class PromotionRGB48 extends ImageToImageOperation { private void prepare(PixelImage in) throws MissingParameterException, WrongParameterException { if (! ( (in instanceof BilevelImage) || (in instanceof Paletted8Image) || (in instanceof Gray16Image)|| (in instanceof Gray8Image) || (in instanceof RGB24Image) ) ) { throw new WrongParameterException("Unsupported input image type: " + in.getClass().getName()); } PixelImage out = getOutputImage(); if (out == null) { setOutputImage(new MemoryRGB48Image(in.getWidth(), in.getHeight())); } else { if (!(out instanceof RGB48Image)) { throw new WrongParameterException("Specified output image type " + "must be of class RGB48Image; got " + in.getClass().getName()); } ensureImagesHaveSameResolution(); } } private void process(BilevelImage in, RGB48Image out) { final int HEIGHT = in.getHeight(); final short MAX = (short)65535; final short MIN = (short)0; for (int y = 0; y < HEIGHT; y++) { for (int x = 0; x < in.getWidth(); x++) { if (in.isBlack(x, y)) { out.putShortSample(RGBIndex.INDEX_RED, x, y, MIN); out.putShortSample(RGBIndex.INDEX_GREEN, x, y, MIN); out.putShortSample(RGBIndex.INDEX_BLUE, x, y, MIN); } else { out.putShortSample(RGBIndex.INDEX_RED, x, y, MAX); out.putShortSample(RGBIndex.INDEX_GREEN, x, y, MAX); out.putShortSample(RGBIndex.INDEX_BLUE, x, y, MAX); } } setProgress(y, HEIGHT); } } private void process(Paletted8Image in, RGB48Image out) { final int WIDTH = in.getWidth(); final int HEIGHT = in.getHeight(); final Palette PAL = in.getPalette(); for (int y = 0; y < HEIGHT; y++) { for (int x = 0; x < WIDTH; x++) { int value = in.getSample(0, x, y); int red = PAL.getSample(RGBIndex.INDEX_RED, value); int green = PAL.getSample(RGBIndex.INDEX_GREEN, value); int blue = PAL.getSample(RGBIndex.INDEX_BLUE, value); out.putSample(RGBIndex.INDEX_RED, x, y, red | red << 8); out.putSample(RGBIndex.INDEX_GREEN, x, y, green | green << 8); out.putSample(RGBIndex.INDEX_BLUE, x, y, blue | blue << 8); } setProgress(y, HEIGHT); } } private void process(Gray16Image in, RGB48Image out) { final int WIDTH = in.getWidth(); final int HEIGHT = in.getHeight(); for (int y = 0; y < HEIGHT; y++) { for (int x = 0; x < WIDTH; x++) { int value = in.getSample(0, x, y); out.putSample(RGBIndex.INDEX_RED, x, y, value); out.putSample(RGBIndex.INDEX_GREEN, x, y, value); out.putSample(RGBIndex.INDEX_BLUE, x, y, value); } setProgress(y, HEIGHT); } } private void process(Gray8Image in, RGB48Image out) { final int WIDTH = in.getWidth(); final int HEIGHT = in.getHeight(); for (int y = 0; y < HEIGHT; y++) { for (int x = 0; x < WIDTH; x++) { int value = in.getSample(0, x, y); value = value | value << 8; out.putSample(RGBIndex.INDEX_RED, x, y, value); out.putSample(RGBIndex.INDEX_GREEN, x, y, value); out.putSample(RGBIndex.INDEX_BLUE, x, y, value); } setProgress(y, HEIGHT); } } private void process(RGB24Image in, RGB48Image out) { final int WIDTH = in.getWidth(); final int HEIGHT = in.getHeight(); for (int y = 0; y < HEIGHT; y++) { for (int x = 0; x < WIDTH; x++) { int red = in.getSample(RGBIndex.INDEX_RED, x, y); red = red << 8 | red; int green = in.getSample(RGBIndex.INDEX_GREEN, x, y); green = green << 8 | green; int blue = in.getSample(RGBIndex.INDEX_BLUE, x, y); blue = blue << 8 | blue; out.putSample(RGBIndex.INDEX_RED, x, y, red); out.putSample(RGBIndex.INDEX_GREEN, x, y, green); out.putSample(RGBIndex.INDEX_BLUE, x, y, blue); } setProgress(y, HEIGHT); } } public void process() throws MissingParameterException, WrongParameterException { ensureInputImageIsAvailable(); PixelImage in = getInputImage(); prepare(in); RGB48Image out = (RGB48Image)getOutputImage(); if (in instanceof BilevelImage) { process((BilevelImage)in, out); } else if (in instanceof Gray16Image) { process((Gray16Image)in, out); } else if (in instanceof Gray8Image) { process((Gray8Image)in, out); } else if (in instanceof Paletted8Image) { process((Paletted8Image)in, out); } else if (in instanceof RGB24Image) { process((RGB24Image)in, out); } } } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/conversion/ 0000775 0000000 0000000 00000000000 10546532076 023341 5 ustar java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/conversion/LogLuvConversion.java 0000664 0000000 0000000 00000026553 07741250131 027465 0 ustar /* * LogLuvConversion * * Copyright (c) 2002, 2003 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.color.conversion; /** * Convert from LogLuv color representation to RGB color space and * from LogL to grayscale. *
* This implementation is based on the file tif_luv.c
which
* is part of the TIFF library libtiff.
* The original implementation was written by Greg W. Larson.
*
* Learn more about the color type and its encoding on Greg's page
* LogLuv
* Encoding for TIFF Images.
* @author Marco Schmidt
* @since 0.10.0
*/
public class LogLuvConversion
{
private static final double M_LN2 = 0.69314718055994530942;
private static final double UVSCALE = 410.0;
// constants from libtiff's uv_decode.h
private static final float UV_SQSIZ = 0.003500f;
private static final int UV_NDIVS = 16289;
private static final float UV_VSTART = 0.016940f;
private static final int UV_NVS = 163;
private static final double U_NEU = 0.210526316;
private static final double V_NEU = 0.473684211;
private static final double[] USTART =
{
0.247663,
0.243779,
0.241684,
0.237874,
0.235906,
0.232153,
0.228352,
0.226259,
0.222371,
0.220410,
0.214710,
0.212714,
0.210721,
0.204976,
0.202986,
0.199245,
0.195525,
0.193560,
0.189878,
0.186216,
0.186216,
0.182592,
0.179003,
0.175466,
0.172001,
0.172001,
0.168612,
0.168612,
0.163575,
0.158642,
0.158642,
0.158642,
0.153815,
0.153815,
0.149097,
0.149097,
0.142746,
0.142746,
0.142746,
0.138270,
0.138270,
0.138270,
0.132166,
0.132166,
0.126204,
0.126204,
0.126204,
0.120381,
0.120381,
0.120381,
0.120381,
0.112962,
0.112962,
0.112962,
0.107450,
0.107450,
0.107450,
0.107450,
0.100343,
0.100343,
0.100343,
0.095126,
0.095126,
0.095126,
0.095126,
0.088276,
0.088276,
0.088276,
0.088276,
0.081523,
0.081523,
0.081523,
0.081523,
0.074861,
0.074861,
0.074861,
0.074861,
0.068290,
0.068290,
0.068290,
0.068290,
0.063573,
0.063573,
0.063573,
0.063573,
0.057219,
0.057219,
0.057219,
0.057219,
0.050985,
0.050985,
0.050985,
0.050985,
0.050985,
0.044859,
0.044859,
0.044859,
0.044859,
0.040571,
0.040571,
0.040571,
0.040571,
0.036339,
0.036339,
0.036339,
0.036339,
0.032139,
0.032139,
0.032139,
0.032139,
0.027947,
0.027947,
0.027947,
0.023739,
0.023739,
0.023739,
0.023739,
0.019504,
0.019504,
0.019504,
0.016976,
0.016976,
0.016976,
0.016976,
0.012639,
0.012639,
0.012639,
0.009991,
0.009991,
0.009991,
0.009016,
0.009016,
0.009016,
0.006217,
0.006217,
0.005097,
0.005097,
0.005097,
0.003909,
0.003909,
0.002340,
0.002389,
0.001068,
0.001653,
0.000717,
0.001614,
0.000270,
0.000484,
0.001103,
0.001242,
0.001188,
0.001011,
0.000709,
0.000301,
0.002416,
0.003251,
0.003246,
0.004141,
0.005963,
0.008839,
0.010490,
0.016994,
0.023659,
};
private static final short[] NCUM =
{
0,
4,
10,
17,
26,
36,
48,
62,
77,
94,
112,
133,
155,
178,
204,
231,
260,
291,
323,
357,
393,
429,
467,
507,
549,
593,
637,
683,
729,
778,
830,
882,
934,
989,
1044,
1102,
1160,
1222,
1284,
1346,
1411,
1476,
1541,
1610,
1679,
1752,
1825,
1898,
1975,
2052,
2129,
2206,
2288,
2370,
2452,
2538,
2624,
2710,
2796,
2887,
2978,
3069,
3164,
3259,
3354,
3449,
3549,
3649,
3749,
3849,
3954,
4059,
4164,
4269,
4379,
4489,
4599,
4709,
4824,
4939,
5054,
5169,
5288,
5407,
5526,
5645,
5769,
5893,
6017,
6141,
6270,
6399,
6528,
6657,
6786,
6920,
7054,
7188,
7322,
7460,
7598,
7736,
7874,
8016,
8158,
8300,
8442,
8588,
8734,
8880,
9026,
9176,
9326,
9476,
9630,
9784,
9938,
10092,
10250,
10408,
10566,
10727,
10888,
11049,
11210,
11375,
11540,
11705,
11873,
12041,
12209,
12379,
12549,
12719,
12892,
13065,
13240,
13415,
13590,
13767,
13944,
14121,
14291,
14455,
14612,
14762,
14905,
15041,
15170,
15293,
15408,
15517,
15620,
15717,
15806,
15888,
15964,
16033,
16095,
16150,
16197,
16237,
16268,
};
private LogLuvConversion()
{
}
/**
* Converts an unsigned 10 bit value (the argument must lie in the
* interval 0 to 1023) to a double
luminance
* (brightness) value between 0.0
and 1.0
.
* This conversion is needed by both LogLuv to XYZ and LogL to grayscale.
* @param p10 input LogL value
* @return double value with luminance, between 0 and 1
*/
public static double convertLogL10toY(int p10)
{
if (p10 == 0)
{
return 0.0;
}
else
{
return Math.exp(M_LN2 / 64.0 * (p10 + 0.5) - M_LN2 * 12.0);
}
}
/**
* Converts a signed 16 bit value (the argument must lie in the
* interval -32768 to 32767) to a double
luminance
* (brightness) value between 0.0
and 1.0
.
* This conversion is needed by both LogLuv to XYZ and LogL to grayscale.
* @param p16 input LogL value
* @return double value with luminance, between 0 and 1
*/
public static double convertLogL16toY(int p16)
{
int Le = p16 & 0x7fff;
if (Le == 0)
{
return 0.0;
}
double Y = Math.exp(M_LN2 / 256.0 * (Le + 0.5) - M_LN2 * 64.0);
if ((p16 & 0x8000) == 0)
{
return Y;
}
else
{
return -Y;
}
}
private static byte convertDoubleToByte(double d)
{
if (d <= 0.0)
{
return 0;
}
else
if (d >= 1.0)
{
return (byte)255;
}
else
{
double result = 255.0 * Math.sqrt(d);
return (byte)result;
}
}
/**
* Converts a number of 24 bit LogLuv pixels to 24 bit RGB pixels.
* Each LogLuv pixel is stored as three consecutive bytes in the logluv
byte array.
* The first byte and the top two bits of the second are the LogL value, the remaining
* 14 bits are an index that encodes u and v.
* @param logluv byte array with LogLuv data, must be at least num * 3 bytes large
* @param red the byte samples for the red channel will be written to this array
* @param green the byte samples for the green channel will be written to this array
* @param blue the byte samples for the blue channel will be written to this array
* @param num number of pixels to be converted
*/
public static void convertLogLuv24InterleavedtoRGB24Planar(byte[] logluv, byte[] red, byte[] green, byte[] blue, int num)
{
int srcOffs = 0;
int destOffs = 0;
while (num-- != 0)
{
// convert from LogLuv24 to XYZ
float X = 0.0f;
float Y = 0.0f;
float Z = 0.0f;
// first byte and top two bits of second make 10 bit value L10
int v1 = logluv[srcOffs++] & 0xff;
int v2 = logluv[srcOffs++] & 0xff;
int v3 = logluv[srcOffs++] & 0xff;
double L = convertLogL10toY(v1 << 2 | ((v2 >> 6) & 0x03));
if (L > 0.0)
{
int c = ((v2 & 0x3f) << 8) | v3;
double u = U_NEU;
double v = V_NEU;
// uv_decode in tif_luv.c
int upper = UV_NVS;
int lower = 0;
if (c >= 0 && c < UV_NDIVS)
{
lower = 0;
upper = UV_NVS;
int ui = 0;
int vi = 0;
while (upper - lower > 1)
{
vi = (lower + upper) >> 1;
ui = c - NCUM[vi];
if (ui > 0)
{
lower = vi;
}
else
if (ui < 0)
{
upper = vi;
}
else
{
lower = vi;
break;
}
}
vi = lower;
ui = c - NCUM[vi];
u = USTART[vi] + (ui + 0.5) * UV_SQSIZ;
v = UV_VSTART + (vi + 0.5) * UV_SQSIZ;
}
double s = 1.0 / (6.0 * u - 16.0 * v + 12.0);
double x = 9.0 * u * s;
double y = 4.0 * v * s;
X = (float)(x / y * L);
Y = (float)L;
Z = (float)((1.0 - x - y) / y * L);
}
// convert from XYZ to RGB
double r = 2.690 * X + -1.276 * Y + -0.414 * Z;
double g = -1.022 * X + 1.978 * Y + 0.044 * Z;
double b = 0.061 * X + -0.224 * Y + 1.163 * Z;
red[destOffs] = convertDoubleToByte(r);
green[destOffs] = convertDoubleToByte(g);
blue[destOffs] = convertDoubleToByte(b);
destOffs++;
}
}
/**
* Converts a number of 32 bit LogLuv pixels to 24 bit RGB pixels.
* Each LogLuv pixel is stored as four consecutive bytes in the logluv
byte array.
* The first two bytes represent the LogL value (most significant bytefirst), followed
* by the u value and then the v value.
* @param logluv byte array with LogLuv data, must be at least num * 4 bytes large
* @param red the byte samples for the red channel will be written to this array
* @param green the byte samples for the green channel will be written to this array
* @param blue the byte samples for the blue channel will be written to this array
* @param num number of pixels to be converted
*/
public static void convertLogLuv32InterleavedtoRGB24Planar(byte[] logluv, byte[] red, byte[] green, byte[] blue, int num)
{
int srcOffs = 0;
int destOffs = 0;
while (num-- != 0)
{
// convert from LogLuv32 to XYZ
float X = 0.0f;
float Y = 0.0f;
float Z = 0.0f;
int v1 = logluv[srcOffs++] & 0xff;
int v2 = logluv[srcOffs++] & 0xff;
double L = convertLogL16toY((short)((v1 << 8) | v2));
if (L > 0.0)
{
// decode color
double u = 1.0 / UVSCALE * ((logluv[srcOffs++] & 0xff) + 0.5);
double v = 1.0 / UVSCALE * ((logluv[srcOffs++] & 0xff) + 0.5);
double s = 1.0 / (6.0 * u - 16.0 * v + 12.0);
double x = 9.0 * u * s;
double y = 4.0 * v * s;
X = (float)(x / y * L);
Y = (float)L;
Z = (float)((1.0 - x - y) / y * L);
}
// convert from XYZ to RGB
double r = 2.690 * X + -1.276 * Y + -0.414 * Z;
double g = -1.022 * X + 1.978 * Y + 0.044 * Z;
double b = 0.061 * X + -0.224 * Y + 1.163 * Z;
red[destOffs] = convertDoubleToByte(r);
green[destOffs] = convertDoubleToByte(g);
blue[destOffs] = convertDoubleToByte(b);
destOffs++;
}
}
/**
* Converts a number of 16 bit LogL samples to 8 bit grayscale samples.
* @param logl byte array with LogL samples, each 16 bit sample is stored as
* two consecutive bytes in order most-significant-byte least-significant-byte (network byte order);
* the array must be at least num * 2 entries large
* @param gray the byte array to which the converted samples will be written
* @param num the number of samples to be converted
*/
public static void convertLogL16toGray8(byte[] logl, byte[] gray, int num)
{
int srcOffs = 0;
int destOffs = 0;
while (num-- != 0)
{
int v1 = logl[srcOffs++] & 0xff;
int v2 = logl[srcOffs++] & 0xff;
double L = convertLogL16toY((short)((v1 << 8) | v2));
gray[destOffs++] = convertDoubleToByte(L);
}
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/conversion/PCDYCbCrConversion.java 0000664 0000000 0000000 00000012641 07741250132 027540 0 ustar /*
* PCDYCbCrConversion
*
* Copyright (c) 2001, 2002 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.color.conversion;
import net.sourceforge.jiu.color.YCbCrIndex;
import net.sourceforge.jiu.data.RGBIndex;
/**
* Convert from YCbCr color space (as used in Kodak PCD files) to
* RGB. Only works for 24 bits per pixel (8 bits per channel) image
* data.
*
* @author Marco Schmidt
*/
public class PCDYCbCrConversion implements
RGBIndex,
YCbCrIndex
{
// color conversion coefficients (YCbCr to RGB)
private static final float c11 = 0.0054980f * 256;
private static final float c12 = 0.0000000f * 256;
private static final float c13 = 0.0051681f * 256;
private static final float c21 = 0.0054980f * 256;
private static final float c22 = -0.0015446f * 256;
private static final float c23 = -0.0026325f * 256;
private static final float c31 = 0.0054980f * 256;
private static final float c32 = 0.0079533f * 256;
private static final float c33 = 0.0000000f * 256;
private PCDYCbCrConversion()
{
}
private static byte floatToByte(float f)
{
if (f <= 0.0)
{
return 0;
}
if (f >= 255.0)
{
return (byte)255;
}
return (byte)((int)f);
}
/*
* Converts the color given by (y, cb, cr) to RGB color space.
* The three int variables y, cb and cr must be from the
* interval 0 to 255 (this is not checked).
* The rgb array will get the resulting RGB color, so it must
* have at least three entries.
* The three entries in that array will also be from 0 to 255 each.
*
public static void convertYCbCrToRgb(int y, int cb, int cr, int[] rgb)
{
int cr137 = cr - 137;
int cb156 = cb - 156;
rgb[INDEX_RED] = floatToInt(c11 * y + c12 * (cb156) + c13 * (cr137));
rgb[INDEX_GREEN] = floatToInt(c21 * y + c22 * (cb156) + c23 * (cr137));
rgb[INDEX_BLUE] = floatToInt(c31 * y + c32 * (cb156) + c33 * (cr137));
}
public static int[] convertToRgb(byte[][] data, int width, int height)
throws IllegalArgumentException
{
if (width < 1 || height < 1)
{
throw new IllegalArgumentException("Error -- width and height must be larger " +
"than 0 (width=" + width + ", height=" + height);
}
if (data == null)
{
throw new IllegalArgumentException("Error -- data array must not be null.");
}
if (data.length < 3)
{
throw new IllegalArgumentException("Error -- data array must have at least " +
"three items (has " + data.length);
}
int numPixels = width * height;
int[] result = new int[numPixels];
int[] rgb = new int[3];
for (int i = 0; i < numPixels; i++)
{
int gray = data[INDEX_Y][i] & 0xff;
int cb = data[INDEX_CB][i] & 0xff;
int cr = data[INDEX_CR][i] & 0xff;
convertYCbCrToRgb(gray, cb, cr, rgb);
result[i] = 0xff000000 | rgb[0] << 16 | (rgb[1] << 8) | (rgb[2]);
}
return result;
}*/
private static void checkArray(byte[] data, int offset, int num) throws IllegalArgumentException
{
if (data == null)
{
throw new IllegalArgumentException("Data array must be initialized.");
}
if (offset < 0 || offset + num > data.length)
{
throw new IllegalArgumentException("Invalid combination of " +
"offset, number and array length: offset=" + offset +
", num=" + num + ", data.length=" + data.length);
}
}
/**
* Converts pixels from YCbCr to RGB color space.
* Input pixels are given as three byte arrays for luminance and the
* two chroma components.
* Same for output pixels, three other arrays for red, green and blue.
* Offset values can be specified separately for the YCbCr and the RGB
* arrays.
* @param y the array of gray source samples
* @param cb the array of chroma blue source samples
* @param cr the array of chroma red source samples
* @param yccOffset offset value into the arrays y, cb and cr; color
* conversion will be started at the yccOffset'th value of each array
* @param r the array of red destination samples
* @param g the array of green destination samples
* @param b the array of blue destination samples
* @param rgbOffset offset value into the arrays r, g and b; destination samples
* will be written to the three arrays starting at the rgbOffset'th value of each array
* @param num the number of pixels to be converted
* @throws IllegalArgumentException if one of the int values is negative or one
* of the arrays is null or too small
*/
public static void convertYccToRgb(
byte[] y,
byte[] cb,
byte[] cr,
int yccOffset,
byte[] r,
byte[] g,
byte[] b,
int rgbOffset,
int num)
throws IllegalArgumentException
{
if (num < 0)
{
throw new IllegalArgumentException("Negative number of pixels " +
"to be converted is invalid: " + num);
}
checkArray(y, yccOffset, num);
checkArray(cb, yccOffset, num);
checkArray(cr, yccOffset, num);
checkArray(r, rgbOffset, num);
checkArray(g, rgbOffset, num);
checkArray(b, rgbOffset, num);
while (num-- > 0)
{
int gray = y[yccOffset] & 0xff;
int chromaBlue = cb[yccOffset] & 0xff;
int chromaRed = cr[yccOffset++] & 0xff;
int cr137 = chromaRed - 137;
int cb156 = chromaBlue - 156;
r[rgbOffset] = floatToByte(c11 * gray + c12 * (cb156) + c13 * (cr137));
g[rgbOffset] = floatToByte(c21 * gray + c22 * (cb156) + c23 * (cr137));
b[rgbOffset++] = floatToByte(c31 * gray + c32 * (cb156) + c33 * (cr137));
}
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/conversion/CMYKConversion.java 0000664 0000000 0000000 00000007505 07741250131 027014 0 ustar /*
* CMYKConversion
*
* Copyright (c) 2002 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.color.conversion;
import net.sourceforge.jiu.data.RGBIndex;
/**
* Convert from CMYK color space to RGB color space.
* @author Marco Schmidt
* @since 0.10.0
*/
public class CMYKConversion
{
private CMYKConversion()
{
}
private static int convertToByte(int value)
{
if (value <= 0)
{
return 0;
}
else
if (value >= 255)
{
return 255;
}
else
{
return value;
}
}
/**
* Converts a 32 bit CMYK pixel to a 24 bit RGB pixel.
* Red, green and blue sample will be written at the indexes that {@link net.sourceforge.jiu.data.RGBIndex} defines for them.
* @param cyan the cyan sample, must lie in the interval 0 to 255
* @param magenta the magenta sample, must lie in the interval 0 to 255
* @param yellow the yellow sample, must lie in the interval 0 to 255
* @param black the black sample, must lie in the interval 0 to 255
* @param rgb byte array for the destination R-G-B pixel, must have length 3 or larger, will be accessed using RGBIndex, each sample will lie in the interval 0 to 255
*/
public static void convertCMYK32ToRGB24(int cyan, int magenta, int yellow, int black, int[] rgb)
{
int red = 255 - cyan;
int green = 255 - magenta;
int blue = 255 - yellow;
red -= black;
green -= black;
blue -= black;
rgb[RGBIndex.INDEX_RED] = convertToByte(red);
rgb[RGBIndex.INDEX_GREEN] = convertToByte(green);
rgb[RGBIndex.INDEX_BLUE] = convertToByte(blue);
}
/**
* Converts a number of CMYK pixels stored in interleaved order (all samples of one pixel
* together: CMYKCMYKCMYK...) to RGB pixels which are stored as planes (all red samples
* together, etc.).
* @param cmyk a byte array with numPixels times four samples stored in order C-M-Y-K
* @param cmykOffset the index of the first byte that is to be accessed
* @param red the byte array to which the red samples will be written by this method
* @param redOffset the offset into the red array of the first sample to be written
* @param green the byte array to which the green samples will be written by this method
* @param greenOffset the offset into the green array of the first sample to be written
* @param blue the byte array to which the blue samples will be written by this method
* @param blueOffset the offset into the blue array of the first sample to be written
*/
public static void convertCMYK32InterleavedToRGB24Planar(
byte[] cmyk, int cmykOffset,
byte[] red, int redOffset,
byte[] green, int greenOffset,
byte[] blue, int blueOffset,
int numPixels)
{
int[] rgb = new int[3];
while (numPixels-- != 0)
{
convertCMYK32ToRGB24(
cmyk[cmykOffset] & 0xff,
cmyk[cmykOffset + 1] & 0xff,
cmyk[cmykOffset + 2] & 0xff,
cmyk[cmykOffset + 3] & 0xff,
rgb);
cmykOffset += 4;
red[redOffset++] = (byte)rgb[RGBIndex.INDEX_RED];
green[greenOffset++] = (byte)rgb[RGBIndex.INDEX_GREEN];
blue[blueOffset++] = (byte)rgb[RGBIndex.INDEX_BLUE];
}
}
public static void convertCMYK32PlanarToRGB24Planar(
byte[] cyan, int cyanOffset,
byte[] magenta, int magentaOffset,
byte[] yellow, int yellowOffset,
byte[] black, int blackOffset,
byte[] red, int redOffset,
byte[] green, int greenOffset,
byte[] blue, int blueOffset,
int numPixels)
{
int[] rgb = new int[3];
while (numPixels-- != 0)
{
convertCMYK32ToRGB24(
cyan[cyanOffset++] & 0xff,
magenta[magentaOffset++] & 0xff,
yellow[yellowOffset++] & 0xff,
black[blackOffset++] & 0xff,
rgb);
red[redOffset++] = (byte)rgb[RGBIndex.INDEX_RED];
green[greenOffset++] = (byte)rgb[RGBIndex.INDEX_GREEN];
blue[blueOffset++] = (byte)rgb[RGBIndex.INDEX_BLUE];
}
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/conversion/package.html 0000664 0000000 0000000 00000000653 07741250131 025616 0 ustar
Classes to improve the results of color reduction algorithms. Some algorithms work by modifying pixel values before they are reduced, others compute the error of a pixel reduction and distributes that error over neighboring pixels that are yet to be reduced. java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/reduction/ 0000775 0000000 0000000 00000000000 10546532076 023150 5 ustar java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/reduction/ReduceRGB.java 0000664 0000000 0000000 00000011165 10104713600 025541 0 ustar /* * ReduceRGB * * Copyright (c) 2003, 2004 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.color.reduction; import net.sourceforge.jiu.data.IntegerImage; import net.sourceforge.jiu.data.MemoryRGB24Image; import net.sourceforge.jiu.data.MemoryRGB48Image; import net.sourceforge.jiu.data.PixelImage; import net.sourceforge.jiu.data.RGB24Image; import net.sourceforge.jiu.data.RGB48Image; import net.sourceforge.jiu.ops.ImageToImageOperation; import net.sourceforge.jiu.ops.MissingParameterException; import net.sourceforge.jiu.ops.WrongParameterException; /** * Reduces the color depth of RGB truecolor images. * This class uses a simple approach, it just drops some of the * lowest bits and scales the value back to eight or sixteen bits per sample. *
* PixelImage inputImage = ...; // initialize * ReduceRGB reduce = new ReduceRGB(); * reduce.setBitsPerSample(5); * reduce.setInputImage(inputImage); * reduce.process(); * PixelImage reducedImage = reduce.getOutputImage(); ** @author Marco Schmidt * @since 0.12.0 * @see net.sourceforge.jiu.color.reduction.ReduceShadesOfGray */ public class ReduceRGB extends ImageToImageOperation { /** * Number of significant bits per channel in the destination RGB image. */ private Integer destBits; /*private byte[] createByteLut(int inDepth) { int outDepth = destBits.intValue(); lut = new int[1 << inDepth]; final int SHIFT = inDepth - outDepth; final int MAX_IN_VALUE = (1 << inDepth) - 1; final int MAX_OUT_VALUE = (1 << outDepth) - 1; for (int i = 0; i < lut.length; i++) { int value = i >> SHIFT; lut[i] = (value * MAX_IN_VALUE) / MAX_OUT_VALUE; } }*/ public void process() throws MissingParameterException, WrongParameterException { if (destBits == null) { throw new MissingParameterException( "The number of destination bits has not been specified."); } int bits = destBits.intValue(); ensureInputImageIsAvailable(); ensureImagesHaveSameResolution(); PixelImage in = getInputImage(); boolean rgb24 = in instanceof RGB24Image; boolean rgb48 = in instanceof RGB48Image; if (!(rgb24 || rgb48)) { throw new WrongParameterException( "Input image must be either RGB24Image or RGB48Image."); } if (rgb24 && bits >= 8) { throw new WrongParameterException( "Number of output bits per sample must be 7 or lower for RGB24Image."); } PixelImage out = getOutputImage(); int inDepth = 0; if (rgb24) { inDepth = 8; } if (rgb48) { inDepth = 16; } int maxOutputValue = 1; int maxShiftedValue = (1 << bits) - 1; if (bits <= 8) { if (out == null) { out = new MemoryRGB24Image(in.getWidth(), in.getHeight()); } else { if (!(out instanceof RGB24Image)) { throw new WrongParameterException( "Output image must be of type RGB24Image."); } } maxOutputValue = 255; } else if (bits <= 16) { if (out == null) { out = new MemoryRGB48Image(in.getWidth(), in.getHeight()); } else { if (!(out instanceof RGB48Image)) { throw new WrongParameterException( "Output image must be of type RGB48Image."); } } maxOutputValue = 65535; } else { throw new WrongParameterException("Can only process up to 16 bits per sample."); } final int SHIFT = inDepth - bits; IntegerImage ii = (IntegerImage)in; IntegerImage oo = (IntegerImage)out; for (int y = 0; y < in.getHeight(); y++) { for (int x = 0; x < in.getWidth(); x++) { for (int c = 0; c < 3; c++) { int inputSample = ii.getSample(c, x, y); int outputSample = ((inputSample >> SHIFT) * maxOutputValue) / maxShiftedValue; oo.putSample(c, x, y, outputSample); } } setProgress(y, in.getHeight()); } } /** * Specifies the number of bits per sample in the output image. * @param bits number of bits in output image, from 1 to 15 * @throws IllegalArgumentException if bits is smaller than 1 or larger than 15 */ public void setBitsPerSample(int bits) { if (bits < 1) { throw new IllegalArgumentException("Number of bits must be 1 or larger."); } if (bits > 15) { throw new IllegalArgumentException("Number of bits must be 15 or smaller."); } destBits = new Integer(bits); } } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/reduction/AutoDetectColorType.java 0000664 0000000 0000000 00000043120 10546763021 027711 0 ustar /* * AutoDetectColorType * * Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.color.reduction; import net.sourceforge.jiu.color.data.Histogram3D; import net.sourceforge.jiu.color.data.OnDemandHistogram3D; import net.sourceforge.jiu.data.BilevelImage; import net.sourceforge.jiu.data.Gray16Image; import net.sourceforge.jiu.data.Gray8Image; import net.sourceforge.jiu.data.IntegerImage; import net.sourceforge.jiu.data.MemoryBilevelImage; import net.sourceforge.jiu.data.MemoryGray8Image; import net.sourceforge.jiu.data.MemoryPaletted8Image; import net.sourceforge.jiu.data.MemoryRGB24Image; import net.sourceforge.jiu.data.Palette; import net.sourceforge.jiu.data.Paletted8Image; import net.sourceforge.jiu.data.PixelImage; import net.sourceforge.jiu.data.RGB24Image; import net.sourceforge.jiu.data.RGB48Image; import net.sourceforge.jiu.data.RGBIndex; import net.sourceforge.jiu.data.RGBIntegerImage; import net.sourceforge.jiu.ops.MissingParameterException; import net.sourceforge.jiu.ops.Operation; import net.sourceforge.jiu.ops.WrongParameterException; /** * Detects the minimum (in terms of memory) color type of an image. * Can convert the original image to that new input type on demand. *
* Input parameters: image to be examined, boolean that specifies whether * conversion will be performed (default is true, conversion is performed). * Output parameters: converted image, boolean that expresses whether * a conversion was possible. *
* Supported types for input image: RGB24Image, Gray8Image, Paletted8Image. *
* BilevelImage is not supported because there is no smaller image type, * so bilevel images cannot be reduced. *
* This operation is not a {@link net.sourceforge.jiu.ops.ImageToImageOperation} because this * class need not necessarily produce a new image * (with {@link #setConversion}(false)). *
* PixelImage image = ImageLoader.load("test.bmp"); * AutoDetectColorType op = new AutoDetectColorType(); * op.setInputImage(image); * op.process(); * if (op.isReducible()) * { * image = op.getOutputImage(); * } ** * @author Marco Schmidt */ public class AutoDetectColorType extends Operation { public static final int TYPE_UNKNOWN = -1; public static final int TYPE_BILEVEL = 0; public static final int TYPE_GRAY16 = 4; public static final int TYPE_GRAY8 = 1; public static final int TYPE_PALETTED8 = 2; public static final int TYPE_RGB24 = 3; public static final int TYPE_RGB48 = 5; private PixelImage inputImage; private PixelImage outputImage; private boolean doConvert; private int type; private Histogram3D hist; public AutoDetectColorType() { doConvert = true; type = TYPE_UNKNOWN; } /** * Creates a bilevel image from any grayscale (or RGB) image * that has been checked to be bilevel. */ private void createBilevelFromGrayOrRgb(IntegerImage in) { MemoryBilevelImage out = new MemoryBilevelImage(in.getWidth(), in.getHeight()); out.clear(BilevelImage.BLACK); for (int y = 0; y < in.getHeight(); y++) { for (int x = 0; x < in.getWidth(); x++) { if (in.getSample(0, x, y) != 0) { out.putWhite(x, y); } } setProgress(y, in.getHeight()); } outputImage = out; } private void createBilevelFromPaletted(Paletted8Image in) { Palette palette = in.getPalette(); MemoryBilevelImage out = new MemoryBilevelImage(in.getWidth(), in.getHeight()); out.clear(BilevelImage.BLACK); for (int y = 0; y < in.getHeight(); y++) { for (int x = 0; x < in.getWidth(); x++) { if (palette.getSample(RGBIndex.INDEX_RED, in.getSample(0, x, y)) != 0) { out.putWhite(x, y); } } setProgress(y, in.getHeight()); } outputImage = out; } // works for RGB24 and RGB48 input image, assumed that // a matching output image type was chosen (Gray8 for RGB24, Gray16 for // RGB48) private void createGrayFromRgb(IntegerImage in, IntegerImage out) { for (int y = 0; y < in.getHeight(); y++) { for (int x = 0; x < in.getWidth(); x++) { out.putSample(0, x, y, in.getSample(0, x, y)); } setProgress(y, in.getHeight()); } outputImage = out; } private void createGray8FromGray16(Gray16Image in) { Gray8Image out = new MemoryGray8Image(in.getWidth(), in.getHeight()); for (int y = 0; y < in.getHeight(); y++) { for (int x = 0; x < in.getWidth(); x++) { out.putSample(0, x, y, in.getSample(0, x, y) & 0xff); } setProgress(y, in.getHeight()); } outputImage = out; } // assumes that in fact has a palette with gray colors only private void createGray8FromPaletted8(Paletted8Image in, Gray8Image out) { Palette palette = in.getPalette(); for (int y = 0; y < in.getHeight(); y++) { for (int x = 0; x < in.getWidth(); x++) { out.putSample(0, x, y, palette.getSample(0, in.getSample(0, x, y))); } setProgress(y, in.getHeight()); } outputImage = out; } private void createPaletted8FromRgb24(RGB24Image in) { // create palette from histogram int uniqueColors = hist.getNumUsedEntries(); Palette palette = new Palette(uniqueColors, 255); int index = 0; for (int r = 0; r < 256; r++) { for (int g = 0; g < 256; g++) { for (int b = 0; b < 256; b++) { if (hist.getEntry(r, g, b) != 0) { hist.setEntry(r, g, b, index); palette.putSample(RGBIndex.INDEX_RED, index, r); palette.putSample(RGBIndex.INDEX_GREEN, index, g); palette.putSample(RGBIndex.INDEX_BLUE, index, b); index++; } } } } Paletted8Image out = new MemoryPaletted8Image(in.getWidth(), in.getHeight(), palette); for (int y = 0; y < in.getHeight(); y++) { for (int x = 0; x < in.getWidth(); x++) { int red = in.getSample(RGBIndex.INDEX_RED, x, y); int green = in.getSample(RGBIndex.INDEX_GREEN, x, y); int blue = in.getSample(RGBIndex.INDEX_BLUE, x, y); out.putSample(0, x, y, hist.getEntry(red, green, blue)); } setProgress(y, in.getHeight()); } outputImage = out; } private void createPaletted8FromRgb48(RGB48Image in) { // create palette from histogram int uniqueColors = hist.getNumUsedEntries(); Palette palette = new Palette(uniqueColors, 255); int index = 0; for (int r = 0; r < 256; r++) { for (int g = 0; g < 256; g++) { for (int b = 0; b < 256; b++) { if (hist.getEntry(r, g, b) != 0) { hist.setEntry(r, g, b, index); palette.putSample(RGBIndex.INDEX_RED, index, r); palette.putSample(RGBIndex.INDEX_GREEN, index, g); palette.putSample(RGBIndex.INDEX_BLUE, index, b); index++; } } } } Paletted8Image out = new MemoryPaletted8Image(in.getWidth(), in.getHeight(), palette); for (int y = 0; y < in.getHeight(); y++) { for (int x = 0; x < in.getWidth(); x++) { int red = in.getSample(RGBIndex.INDEX_RED, x, y) >> 8; int green = in.getSample(RGBIndex.INDEX_GREEN, x, y) >> 8; int blue = in.getSample(RGBIndex.INDEX_BLUE, x, y) >> 8; out.putSample(0, x, y, hist.getEntry(red, green, blue)); } setProgress(y, in.getHeight()); } outputImage = out; } private void createRgb24FromRgb48(RGB48Image in, RGB24Image out) { for (int y = 0; y < in.getHeight(); y++) { for (int x = 0; x < in.getWidth(); x++) { out.putSample(RGBIndex.INDEX_RED, x, y, in.getSample(RGBIndex.INDEX_RED, x, y) >> 8); out.putSample(RGBIndex.INDEX_GREEN, x, y, in.getSample(RGBIndex.INDEX_GREEN, x, y) >> 8); out.putSample(RGBIndex.INDEX_BLUE, x, y, in.getSample(RGBIndex.INDEX_BLUE, x, y) >> 8); } setProgress(y, in.getHeight()); } outputImage = out; } /** * Returns the reduced output image if one was created in {@link #process()}. * @return newly-created output image */ public PixelImage getOutputImage() { return outputImage; } /** * Returns the type of the minimum image type found (one of the TYPE_xyz constants * of this class). * Can only be called after a successful call to process. */ public int getType() { return type; } /** * This method can be called after {@link #process()} to find out if the input * image in fact can be reduced to a "smaller" image type. * If this method returns
true
and if conversion was desired by the
* user (can be specified via {@link #setConversion}), the reduced image can
* be retrieved via {@link #getOutputImage()}.
* @return if image was found to be reducible in process()
*/
public boolean isReducible()
{
return type != TYPE_UNKNOWN;
}
// works for Gray8 and Gray16
private boolean isGrayBilevel(IntegerImage in)
{
final int HEIGHT = in.getHeight();
final int MAX = in.getMaxSample(0);
for (int y = 0; y < HEIGHT; y++)
{
for (int x = 0; x < in.getWidth(); x++)
{
int value = in.getSample(0, x, y);
if (value != 0 && value != MAX)
{
return false; // not a grayscale image
}
}
}
return true;
}
private boolean isGray16Gray8(Gray16Image in)
{
final int HEIGHT = in.getHeight();
final int WIDTH = in.getWidth();
for (int y = 0; y < HEIGHT; y++)
{
for (int x = 0; x < WIDTH; x++)
{
int value = in.getSample(0, x, y);
int lsb = value & 0xff;
int msb = (value >> 8) & 0xff;
if (lsb != msb)
{
return false;
}
}
}
return true;
}
private boolean isRgb48Gray8(RGB48Image in)
{
final int HEIGHT = in.getHeight();
for (int y = 0; y < HEIGHT; y++)
{
for (int x = 0; x < in.getWidth(); x++)
{
int red = in.getSample(RGBIndex.INDEX_RED, x, y);
int green = in.getSample(RGBIndex.INDEX_GREEN, x, y);
int blue = in.getSample(RGBIndex.INDEX_BLUE, x, y);
if (red != green || green != blue)
{
return false;
}
int lsb = red & 0xff;
int msb = red >> 8;
if (lsb != msb)
{
return false;
}
}
}
return true;
}
/**
* Assumes that it has already been verified that the input 48 bpp
* RGB image is also a 24 bpp RGB image.
* @param in input image to be checked
* @return if this image can be losslessly converted to a Paletted8Image
*/
private boolean isRgb48Paletted8(RGB48Image in)
{
int uniqueColors = 0;
hist = new OnDemandHistogram3D(255, 255, 255);
for (int y = 0; y < in.getHeight(); y++)
{
for (int x = 0; x < in.getWidth(); x++)
{
int red = in.getSample(RGBIndex.INDEX_RED, x, y) >> 8;
int green = in.getSample(RGBIndex.INDEX_GREEN, x, y) >> 8;
int blue = in.getSample(RGBIndex.INDEX_BLUE, x, y) >> 8;
if (hist.getEntry(red, green, blue) == 0)
{
hist.increaseEntry(red, green, blue);
uniqueColors++;
if (uniqueColors > 256)
{
return false;
}
}
}
}
return true;
}
private boolean isRgb48Rgb24(RGB48Image in)
{
final int HEIGHT = in.getHeight();
for (int y = 0; y < HEIGHT; y++)
{
for (int x = 0; x < in.getWidth(); x++)
{
for (int channel = 0; channel < 3; channel++)
{
int sample = in.getSample(channel, x, y);
if ((sample & 0xff) != ((sample & 0xff00) >> 8))
{
return false;
}
}
}
}
return true;
}
// works for RGB24 and RGB48
private boolean isRgbBilevel(IntegerImage in)
{
final int HEIGHT = in.getHeight();
final int MAX = in.getMaxSample(0);
for (int y = 0; y < HEIGHT; y++)
{
for (int x = 0; x < in.getWidth(); x++)
{
int red = in.getSample(RGBIndex.INDEX_RED, x, y);
int green = in.getSample(RGBIndex.INDEX_GREEN, x, y);
int blue = in.getSample(RGBIndex.INDEX_BLUE, x, y);
if (red != green || green != blue || (blue != 0 && blue != MAX))
{
return false;
}
}
}
return true;
}
/**
* Returns if the input RGB image can be losslessly converted to
* a grayscale image.
* @param in RGB image to be checked
* @return true if input is gray, false otherwise
*/
private boolean isRgbGray(RGBIntegerImage in)
{
final int HEIGHT = in.getHeight();
for (int y = 0; y < HEIGHT; y++)
{
for (int x = 0; x < in.getWidth(); x++)
{
int red = in.getSample(RGBIndex.INDEX_RED, x, y);
int green = in.getSample(RGBIndex.INDEX_GREEN, x, y);
int blue = in.getSample(RGBIndex.INDEX_BLUE, x, y);
if (red != green || green != blue)
{
return false;
}
}
}
return true;
}
private boolean isRgb24Paletted8(RGB24Image in)
{
int uniqueColors = 0;
hist = new OnDemandHistogram3D(255, 255, 255);
for (int y = 0; y < in.getHeight(); y++)
{
for (int x = 0; x < in.getWidth(); x++)
{
int red = in.getSample(RGBIndex.INDEX_RED, x, y);
int green = in.getSample(RGBIndex.INDEX_GREEN, x, y);
int blue = in.getSample(RGBIndex.INDEX_BLUE, x, y);
if (hist.getEntry(red, green, blue) == 0)
{
hist.increaseEntry(red, green, blue);
uniqueColors++;
if (uniqueColors > 256)
{
return false;
}
}
}
}
return true;
}
public void process() throws
MissingParameterException,
WrongParameterException
{
if (inputImage == null)
{
throw new MissingParameterException("No input image available");
}
// GRAY8
if (inputImage instanceof Gray8Image)
{
if (isGrayBilevel((Gray8Image)inputImage))
{
type = TYPE_BILEVEL;
if (doConvert)
{
createBilevelFromGrayOrRgb((Gray8Image)inputImage);
}
}
}
else
// GRAY16
if (inputImage instanceof Gray16Image)
{
if (isGrayBilevel((Gray16Image)inputImage))
{
type = TYPE_BILEVEL;
if (doConvert)
{
createBilevelFromGrayOrRgb((Gray16Image)inputImage);
}
}
else
if (isGray16Gray8((Gray16Image)inputImage))
{
type = TYPE_GRAY16;
if (doConvert)
{
createGray8FromGray16((Gray16Image)inputImage);
}
}
}
else
// RGB24
if (inputImage instanceof RGB24Image)
{
if (isRgbBilevel((RGB24Image)inputImage))
{
type = TYPE_BILEVEL;
if (doConvert)
{
createBilevelFromGrayOrRgb((RGB24Image)inputImage);
}
}
else
if (isRgbGray((RGB24Image)inputImage))
{
type = TYPE_GRAY8;
if (doConvert)
{
outputImage = new MemoryGray8Image(inputImage.getWidth(), inputImage.getHeight());
createGrayFromRgb((RGB24Image)inputImage, (Gray8Image)outputImage);
}
}
else
if (isRgb24Paletted8((RGB24Image)inputImage))
{
type = TYPE_PALETTED8;
if (doConvert)
{
createPaletted8FromRgb24((RGB24Image)inputImage);
}
}
}
else
// RGB48
if (inputImage instanceof RGB48Image)
{
if (isRgbBilevel((RGB48Image)inputImage))
{
type = TYPE_BILEVEL;
if (doConvert)
{
createBilevelFromGrayOrRgb((RGB48Image)inputImage);
}
}
else
if (isRgb48Gray8((RGB48Image)inputImage))
{
type = TYPE_GRAY8;
if (doConvert)
{
outputImage = new MemoryGray8Image(inputImage.getWidth(), inputImage.getHeight());
// this create method works because it works with int and the least significant 8
// bits are equal to the most significant 8 bits if isRgb48Gray8 returned true
createGrayFromRgb((RGB48Image)inputImage, (Gray8Image)outputImage);
}
}
else
if (isRgbGray((RGB48Image)inputImage))
{
type = TYPE_GRAY16;
if (doConvert)
{
outputImage = new MemoryGray8Image(inputImage.getWidth(), inputImage.getHeight());
createGrayFromRgb((RGB24Image)inputImage, (Gray8Image)outputImage);
}
}
else
if (isRgb48Rgb24((RGB48Image)inputImage))
{
// RGB48 input is RGB24; is it also Paletted8?
if (isRgb48Paletted8((RGB48Image)inputImage))
{
type = TYPE_PALETTED8;
if (doConvert)
{
createPaletted8FromRgb48((RGB48Image)inputImage);
}
}
else
{
type = TYPE_RGB24;
if (doConvert)
{
outputImage = new MemoryRGB24Image(inputImage.getWidth(), inputImage.getHeight());
createRgb24FromRgb48((RGB48Image)inputImage, (RGB24Image)outputImage);
}
}
}
}
else
// PALETTED8
if (inputImage instanceof Paletted8Image)
{
Paletted8Image in = (Paletted8Image)inputImage;
Palette palette = in.getPalette();
if (palette.isBlackAndWhite())
{
type = TYPE_BILEVEL;
if (doConvert)
{
createBilevelFromPaletted(in);
}
}
else
if (palette.isGray())
{
type = TYPE_GRAY8;
if (doConvert)
{
Gray8Image out = new MemoryGray8Image(in.getWidth(), in.getHeight());
createGray8FromPaletted8(in, out);
}
}
}
else
{
throw new WrongParameterException("Not a supported or reducible image type: " + inputImage.toString());
}
}
/**
* This method can be used to specify whether the input image is to be converted
* to the minimum image type if it is clear that such a conversion is possible.
* The default value is true
.
* If this is set to false
, it can still be
* @param convert if true, the conversion will be performed
*/
public void setConversion(boolean convert)
{
doConvert = convert;
}
/**
* This method must be used to specify the mandatory input image.
* @param image PixelImage object to be examined
*/
public void setInputImage(PixelImage image)
{
inputImage = image;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/reduction/package.html 0000664 0000000 0000000 00000001150 07741250132 025417 0 ustar
Classes to convert images to a lower
color type.
Usually, that conversion is lossy (e.g. from RGB truecolor to
grayscale, or from shades of gray to black and white).
However, the {@link net.sourceforge.jiu.color.reduction.AutoDetectColorType} class reduces only if
an image can be converted to a lower
color type
without losing information.
This is the inverse operation to color promotion,
provided by another package.
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/reduction/ReduceShadesOfGray.java 0000664 0000000 0000000 00000012651 10377271207 027465 0 ustar /*
* ReduceShadesOfGray
*
* Copyright (c) 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.color.reduction;
import net.sourceforge.jiu.data.BilevelImage;
import net.sourceforge.jiu.data.Gray16Image;
import net.sourceforge.jiu.data.Gray8Image;
import net.sourceforge.jiu.data.GrayIntegerImage;
import net.sourceforge.jiu.data.MemoryBilevelImage;
import net.sourceforge.jiu.data.MemoryGray16Image;
import net.sourceforge.jiu.data.MemoryGray8Image;
import net.sourceforge.jiu.data.PixelImage;
import net.sourceforge.jiu.ops.ImageToImageOperation;
import net.sourceforge.jiu.ops.MissingParameterException;
import net.sourceforge.jiu.ops.WrongParameterException;
/**
* Reduces the number of shades of gray of a grayscale image.
* This class uses the most simple possible algorithm.
* Only the most significant N bits are kept (where N is the
* number specified with {@link #setBits}), the others are dropped
* and the result is scaled back to either 8 or 16 bits to fit
* into the two grayscale image types.
*
* ReduceShadesOfGray reduce = new ReduceShadesOfGray(); * reduce.setBits(3); * reduce.setInputImage(image); // some Gray8Image or Gray16Image * reduce.process(); * PixelImage reducedImage = reduce.getOutputImage(); ** @author Marco Schmidt * @since 0.3.0 */ public class ReduceShadesOfGray extends ImageToImageOperation { /** * Number of significant bits in the destination grayscale image. */ private Integer destBits; /** * Lookup table, for each possible input sample stores the * corresponding output sample. */ private int[] lut; private void createLut(int inDepth) { int outDepth = destBits.intValue(); lut = new int[1 << inDepth]; final int SHIFT = inDepth - outDepth; final int MAX_IN_VALUE = (1 << inDepth) - 1; final int MAX_OUT_VALUE = (1 << outDepth) - 1; for (int i = 0; i < lut.length; i++) { int value = i >> SHIFT; lut[i] = (value * MAX_IN_VALUE) / MAX_OUT_VALUE; } } private void process(GrayIntegerImage in, final int MASK, BilevelImage out) { if (out == null) { out = new MemoryBilevelImage(in.getWidth(), in.getHeight()); } out.clear(BilevelImage.BLACK); for (int y = 0; y < in.getHeight(); y++) { for (int x = 0; x < in.getWidth(); x++) { if ((in.getSample(x, y) & MASK) != 0) { out.putWhite(x, y); } } setProgress(y, in.getHeight()); } setOutputImage(out); } private void process(GrayIntegerImage in, GrayIntegerImage out) { //int bits = destBits.intValue(); for (int y = 0; y < in.getHeight(); y++) { for (int x = 0; x < in.getWidth(); x++) { out.putSample(x, y, lut[in.getSample(0, x, y)]); } setProgress(y, in.getHeight()); } setOutputImage(out); } public void process() throws MissingParameterException, WrongParameterException { if (destBits == null) { throw new MissingParameterException("The number of destination bits has not been specified."); } ensureInputImageIsAvailable(); ensureImagesHaveSameResolution(); PixelImage in = getInputImage(); boolean gray8 = in instanceof Gray8Image; boolean gray16 = in instanceof Gray16Image; if (!(gray8 || gray16)) { throw new WrongParameterException("Input image must be either Gray8Image or Gray16Image."); } if (destBits.intValue() == 1) { process((GrayIntegerImage)in, gray8 ? 0x80 : 0x8000, (BilevelImage)getOutputImage()); } else if (gray8) { if (destBits.intValue() > 7) { throw new WrongParameterException("For a Gray8Image destination bits must be 7 or less."); } PixelImage out = getOutputImage(); if (out == null) { out = new MemoryGray8Image(in.getWidth(), in.getHeight()); } else { if (!(out instanceof Gray8Image)) { throw new WrongParameterException("For this input image, output image must be a Gray8Image."); } } createLut(8); process((GrayIntegerImage)in, (GrayIntegerImage)out); } else if (gray16) { PixelImage out = getOutputImage(); if (out == null) { out = new MemoryGray16Image(in.getWidth(), in.getHeight()); } else { if (destBits.intValue() <= 8 && !(out instanceof Gray8Image)) { throw new WrongParameterException("For this input image, output image must be a Gray8Image."); } if (destBits.intValue() <= 15 && !(out instanceof Gray16Image)) { throw new WrongParameterException("For this input image, output image must be a Gray16Image."); } } createLut(16); process((GrayIntegerImage)in, (GrayIntegerImage)out); } } /** * Specifies the number of bits the output image is supposed to have. * @param bits number of bits in output image, from 1 to 15 * @throws IllegalArgumentException if bits is smaller than 1 or larger than 15 */ public void setBits(int bits) { if (bits < 1) { throw new IllegalArgumentException("Number of bits must be 1 or larger."); } if (bits > 15) { throw new IllegalArgumentException("Number of bits must be 15 or smaller."); } destBits = new Integer(bits); } } ././@LongLink 0000000 0000000 0000000 00000000147 00000000000 011567 L ustar root root java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/reduction/ReduceToBilevelThreshold.java java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/reduction/ReduceToBilevelThreshold.ja0000664 0000000 0000000 00000007440 07741250132 030354 0 ustar /* * ReduceToBilevelThreshold * * Copyright (c) 2001, 2002, 2003 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.color.reduction; import net.sourceforge.jiu.data.BilevelImage; import net.sourceforge.jiu.data.GrayIntegerImage; import net.sourceforge.jiu.data.MemoryBilevelImage; import net.sourceforge.jiu.data.PixelImage; import net.sourceforge.jiu.ops.ImageToImageOperation; import net.sourceforge.jiu.ops.MissingParameterException; import net.sourceforge.jiu.ops.WrongParameterException; /** * Reduces a {@link net.sourceforge.jiu.data.GrayIntegerImage} to a * {@link net.sourceforge.jiu.data.BilevelImage} by setting all values below * a certain threshold value to black and everything else to white. *
* GrayIntegerImage image = ...; * ReduceToBilevelThreshold red = new ReduceToBilevelThreshold(); * red.setInputImage(image); * red.setThreshold(image.getMaxSample(0) / 3); * red.process(); * BilevelImage reducedImage= (BilevelImage)red.getOutputImage(); ** @author Marco Schmidt */ public class ReduceToBilevelThreshold extends ImageToImageOperation { private Integer threshold; /** * Returns the current threshold value, or
null
if
* none was specified and the operation's process method was not
* run yet.
* @return threshold value
*/
public Integer getThreshold()
{
return threshold;
}
private void process(GrayIntegerImage in, BilevelImage out) throws WrongParameterException
{
final int MAX_SAMPLE = in.getMaxSample(0);
if (threshold == null)
{
threshold = new Integer((MAX_SAMPLE + 1) / 2);
}
final int THRESHOLD = threshold.intValue();
if (THRESHOLD > MAX_SAMPLE)
{
throw new WrongParameterException("Threshold must be smaller than or equal to the maximum sample of the input image.");
}
final int WIDTH = in.getWidth();
final int HEIGHT = in.getHeight();
out.clear(BilevelImage.BLACK);
for (int y = 0; y < HEIGHT; y++)
{
for (int x = 0; x < WIDTH; x++)
{
if (in.getSample(0, x, y) >= THRESHOLD)
{
out.putWhite(x, y);
}
}
setProgress(y, HEIGHT);
}
}
public void process() throws
MissingParameterException,
WrongParameterException
{
PixelImage in = getInputImage();
if (in == null)
{
throw new MissingParameterException("Input image missing.");
}
if (!(in instanceof GrayIntegerImage))
{
throw new WrongParameterException("Input image must implement GrayIntegerImage.");
}
PixelImage out = getOutputImage();
if (out == null)
{
out = new MemoryBilevelImage(in.getWidth(), in.getHeight());
setOutputImage(out);
}
if (out != null && !(out instanceof BilevelImage))
{
throw new WrongParameterException("Output image must implement BilevelImage.");
}
if (out != null && (in.getWidth() != out.getWidth() || in.getHeight() != out.getHeight()))
{
throw new WrongParameterException("Input and output images must have the same resolution.");
}
process((GrayIntegerImage)in, (BilevelImage)out);
}
/**
* Sets a new threshold value.
* @param newThreshold the new threshold value to be used for this operation
* @throws IllegalArgumentException if the threshold value is negative
*/
public void setThreshold(int newThreshold)
{
if (newThreshold < 0)
{
throw new IllegalArgumentException("New threshold value must be 0 or larger.");
}
threshold = new Integer(newThreshold);
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/reduction/RGBToGrayConversion.java 0000664 0000000 0000000 00000021646 10611702335 027620 0 ustar /*
* RGBToGrayConversion
*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.color.reduction;
import net.sourceforge.jiu.data.Gray16Image;
import net.sourceforge.jiu.data.Gray8Image;
import net.sourceforge.jiu.data.GrayIntegerImage;
import net.sourceforge.jiu.data.MemoryGray16Image;
import net.sourceforge.jiu.data.MemoryGray8Image;
import net.sourceforge.jiu.data.Palette;
import net.sourceforge.jiu.data.Paletted8Image;
import net.sourceforge.jiu.data.PixelImage;
import net.sourceforge.jiu.data.RGB24Image;
import net.sourceforge.jiu.data.RGB48Image;
import net.sourceforge.jiu.data.RGBIndex;
import net.sourceforge.jiu.data.RGBIntegerImage;
import net.sourceforge.jiu.ops.ImageToImageOperation;
import net.sourceforge.jiu.ops.MissingParameterException;
import net.sourceforge.jiu.ops.WrongParameterException;
/**
* Converts RGB color images (both truecolor and paletted) to grayscale images.
* The weights to be used with the three base colors red, green and blue can be
* modified with a call to
* {@link #setColorWeights(float, float, float)}.
* * Could be optimized to use int multiplication instead of float multiplication. *
PixelImage grayImg = RGBToGrayConversion.convert(rgbImage);* Using your own color weights can be done like this. * You may also want to specify an output grayscale image if you have * one to reuse. *
* RGBToGrayConversion rgbtogray = new RGBToGrayConversion(); * rgbtogray.setInputImage(image); * rgbtogray.setColorWeights(0.3f, 0.3f, 0.4f); * rgbtogray.process(); * PixelImage grayImage = rgbtogray.getOutputImage(); ** @author Marco Schmidt */ public class RGBToGrayConversion extends ImageToImageOperation { /** * The default weight for red samples in the conversion, 0.3f. */ public static final float DEFAULT_RED_WEIGHT = 0.3f; /** * The default weight for green samples in the conversion, 0.59f. */ public static final float DEFAULT_GREEN_WEIGHT = 0.59f; /** * The default weight for blue samples in the conversion, 0.11f. */ public static final float DEFAULT_BLUE_WEIGHT = 0.11f; private float redWeight = DEFAULT_RED_WEIGHT; private float greenWeight = DEFAULT_GREEN_WEIGHT; private float blueWeight = DEFAULT_BLUE_WEIGHT; /** * Static convenience method to convert an RGB image to a grayscale image. * @param rgbImage input RGB image to be converted * @return a new grayscale image, created from the RGB input image * @throws MissingParameterException rgbImage is null * @throws WrongParameterException rgbImage's type is unsupported * @since 0.14.2 */ public static PixelImage convert(PixelImage rgbImage) throws MissingParameterException, WrongParameterException { RGBToGrayConversion op = new RGBToGrayConversion(); op.setInputImage(rgbImage); op.process(); return op.getOutputImage(); } private void process(RGBIntegerImage in, GrayIntegerImage out) { final int WIDTH = in.getWidth(); final int HEIGHT = in.getHeight(); for (int y = 0; y < HEIGHT; y++) { for (int x = 0; x < WIDTH; x++) { int red = in.getSample(RGBIndex.INDEX_RED, x, y); int green = in.getSample(RGBIndex.INDEX_GREEN, x, y); int blue = in.getSample(RGBIndex.INDEX_BLUE, x, y); out.putSample(x, y, (int)(red * redWeight + green * greenWeight + blue * blueWeight)); } setProgress(y, HEIGHT); } setOutputImage(out); } public void process() throws MissingParameterException, WrongParameterException { ensureInputImageIsAvailable(); PixelImage in = getInputImage(); if (in instanceof RGB24Image) { process((RGB24Image)in); } else if (in instanceof RGB48Image) { process((RGB48Image)in); } else if (in instanceof Paletted8Image) { process((Paletted8Image)in); } else { throw new WrongParameterException("Type of input image unsupported: " + in.getImageType().getName()); } } private void process(Paletted8Image in) throws MissingParameterException, WrongParameterException { PixelImage image = getOutputImage(); Gray8Image out = null; if (image == null) { out = new MemoryGray8Image(in.getWidth(), in.getHeight()); } else { if (!(image instanceof Gray8Image)) { throw new WrongParameterException("Specified output image must be of type Gray8Image for input image of type Paletted8Image."); } out = (Gray8Image)image; ensureImagesHaveSameResolution(); } Palette palette = in.getPalette(); int[] lut = new int[palette.getNumEntries()]; for (int i = 0; i < lut.length; i++) { int red = palette.getSample(RGBIndex.INDEX_RED, i); int green = palette.getSample(RGBIndex.INDEX_GREEN, i); int blue = palette.getSample(RGBIndex.INDEX_BLUE, i); lut[i] = (int)(red * redWeight + green * greenWeight + blue * blueWeight); } final int WIDTH = in.getWidth(); final int HEIGHT = in.getHeight(); for (int y = 0; y < HEIGHT; y++) { for (int x = 0; x < WIDTH; x++) { try { out.putSample(0, x, y, lut[in.getSample(0, x, y)]); } catch (ArrayIndexOutOfBoundsException aioobe) { } } setProgress(y, HEIGHT); } setOutputImage(out); } private void process(RGB24Image in) throws WrongParameterException { PixelImage out = getOutputImage(); if (out == null) { out = new MemoryGray8Image(in.getWidth(), in.getHeight()); } else { if (!(out instanceof Gray8Image)) { throw new WrongParameterException("Specified output image must be of type Gray8Image for input image of type RGB24Image."); } ensureImagesHaveSameResolution(); } process(in, (GrayIntegerImage)out); } private void process(RGB48Image in) throws WrongParameterException { PixelImage out = getOutputImage(); if (out == null) { out = new MemoryGray16Image(in.getWidth(), in.getHeight()); } else { if (!(out instanceof Gray16Image)) { throw new WrongParameterException("Specified output image must be of type Gray16Image for input image of type RGB48Image."); } ensureImagesHaveSameResolution(); } process(in, (GrayIntegerImage)out); } /** * Sets the weights for the three colors red, green and blue used in the conversion procedure. * For each RGB value
(r, g, b)
to be converted (whether in a truecolor
* image or in the palette), the formula is gray = r * red + g * green + b * blue
.
* The default values for these weights are {@link #DEFAULT_RED_WEIGHT},
* {@link #DEFAULT_GREEN_WEIGHT} and {@link #DEFAULT_BLUE_WEIGHT}.
* This method lets the user change these values.
* Each of these arguments must be >= 0.0f and <= 1.0f.
* The sum of the three must be <= 1.0f.
* For any resulting gray value to be spread over the complete scale from 0.0f to 1.0f it is
* preferable for the sum to be equal to or at least close to 1.0f.
* However, this is not checked.
* The smaller the sum of the weights is, the darker the resulting gray image will become.
* @param red weight of the red sample in the conversion, between 0.0f
and 1.0f
* @param green weight of the green sample in the conversion, between 0.0f
and 1.0f
* @param blue weight of the blue sample in the conversion, between 0.0f
and 1.0f
* @throws IllegalArgumentException if any one of the above mentioned constraints for the arguments is not met
*/
public void setColorWeights(float red, float green, float blue)
{
if (red < 0.0f)
{
throw new IllegalArgumentException("The red weight must be larger than or equal to 0; got " + red);
}
if (green < 0.0f)
{
throw new IllegalArgumentException("The green weight must be larger than or equal to 0; got " + green);
}
if (blue < 0.0f)
{
throw new IllegalArgumentException("The blue weight must be larger than or equal to 0; got " + blue);
}
if (red > 1.0f)
{
throw new IllegalArgumentException("The red weight must be smaller than or equal to 1.0f; got " + red);
}
if (green > 1.0f)
{
throw new IllegalArgumentException("The green weight must be smaller than or equal to 1.0f; got " + green);
}
if (blue > 1.0f)
{
throw new IllegalArgumentException("The blue weight must be smaller than or equal to 1.0f; got " + blue);
}
float sum = red + green + blue;
if (sum > 1.0f)
{
throw new IllegalArgumentException("The sum of the three weights must be smaller than or equal to 1.0f; got " + sum);
}
redWeight = red;
greenWeight = green;
blueWeight = blue;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/Invert.java 0000664 0000000 0000000 00000012432 10522413415 023255 0 ustar /*
* Invert
*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.color;
import net.sourceforge.jiu.data.PixelImage;
import net.sourceforge.jiu.data.Palette;
import net.sourceforge.jiu.data.Paletted8Image;
import net.sourceforge.jiu.data.IntegerImage;
import net.sourceforge.jiu.ops.ImageToImageOperation;
import net.sourceforge.jiu.ops.MissingParameterException;
import net.sourceforge.jiu.ops.OperationFailedException;
import net.sourceforge.jiu.ops.WrongParameterException;
/**
* Creates an inverted (negated) version of an image.
* This is done by subtracting each sample value of a channel
* from the maximum sample for that channel.
* The maximum sample for a channel is given by
* {@link net.sourceforge.jiu.data.IntegerImage#getMaxSample}.
* For paletted images, just the palette is treated that way.
* Supported image types: {@link net.sourceforge.jiu.data.IntegerImage}.
* Input and output image can be the same object.
* * Invert invert = new Invert(); * invert.setInputImage(image); * invert.addProgressListener(listener); // this is optional * invert.process(); * PixelImage invertedImage = invert.getOutputImage(); ** The other method is by sing the static convenience method *
* PixelImage invertedImage = Invert.invert(someImage); ** You will have to catch the potential exceptions in both cases. * @author Marco Schmidt */ public class Invert extends ImageToImageOperation { /** * Helper method to return an inverted image from the argument image. * @param inputImage image to be inverted * @return new image object with inverted image * @throws OperationFailedException on operation errors */ public static PixelImage invert(PixelImage inputImage) throws OperationFailedException { Invert invert = new Invert(); invert.setInputImage(inputImage); invert.process(); return invert.getOutputImage(); } private void prepare(PixelImage in) throws MissingParameterException, WrongParameterException { if (in == null) { throw new MissingParameterException("Missing input image."); } PixelImage out = getOutputImage(); if (out == null) { setOutputImage(in.createCompatibleImage(in.getWidth(), in.getHeight())); } else { if (in.getClass() != out.getClass()) { throw new WrongParameterException("Specified output image type must be the same as input image type."); } if (in.getWidth() != out.getWidth()) { throw new WrongParameterException("Specified output image must have same width as input image."); } if (in.getHeight() != out.getHeight()) { throw new WrongParameterException("Specified output image must have same height as input image."); } } } private void process(Paletted8Image in) { // prepare(PixelImage) has made sure that we have a compatible output image Paletted8Image out = (Paletted8Image)getOutputImage(); // invert palette of output image Palette pal = out.getPalette(); final int MAX = pal.getMaxValue(); for (int entryIndex = 0; entryIndex < pal.getNumEntries(); entryIndex++) { for (int channelIndex = 0; channelIndex < 3; channelIndex++) { pal.putSample(channelIndex, entryIndex, MAX - pal.getSample(channelIndex, entryIndex)); } } // copy image content final int WIDTH = in.getWidth(); final int HEIGHT = in.getHeight(); for (int y = 0; y < HEIGHT; y++) { for (int x = 0; x < WIDTH; x++) { out.putSample(0, x, y, in.getSample(0, x, y)); } setProgress(y, HEIGHT); } } private void process(IntegerImage in) { IntegerImage out = (IntegerImage)getOutputImage(); final int WIDTH = in.getWidth(); final int HEIGHT = in.getHeight(); final int CHANNELS = in.getNumChannels(); final int TOTAL_ITEMS = CHANNELS * HEIGHT; int processedItems = 0; for (int channel = 0; channel < CHANNELS; channel++) { final int MAX = in.getMaxSample(channel); for (int y = 0; y < HEIGHT; y++) { for (int x = 0; x < WIDTH; x++) { out.putSample(channel, x, y, MAX - in.getSample(channel, x, y)); } setProgress(processedItems++, TOTAL_ITEMS); } } } /** * Inverts the input image, reusing an output image if one has been specified. * For paletted images, inverts the palette. * For all other types, subtracts each sample of each channel from the maximum * value of that channel. * @throws MissingParameterException if the input image is missing * @throws WrongParameterException if any of the specified image parameters are unsupported or of the wrong width or height */ public void process() throws MissingParameterException, WrongParameterException { PixelImage in = getInputImage(); prepare(in); if (in instanceof Paletted8Image) { process((Paletted8Image)in); } else if (in instanceof IntegerImage) { process((IntegerImage)in); } else { throw new WrongParameterException("Input image type unsupported: " + in.toString()); } } } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/dithering/ 0000775 0000000 0000000 00000000000 10546532076 023131 5 ustar java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/dithering/LineSpotFunction.java 0000664 0000000 0000000 00000001061 07741250132 027226 0 ustar /* * LineSpotFunction * * Copyright (c) 2002, 2003 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.color.dithering; import net.sourceforge.jiu.color.dithering.SpotFunction; /** * A line spot function. * @author Marco Schmidt * @since 0.9.0 * @see ClusteredDotDither */ public class LineSpotFunction implements SpotFunction { public double compute(double x, double y) { if (y < 0) { return -y; } else { return y; } } public boolean isBalanced() { return true; } } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/dithering/ClusteredDotDither.java 0000664 0000000 0000000 00000022422 07741250132 027530 0 ustar /* * ClusteredDotDither * * Copyright (c) 2002, 2003 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.color.dithering; import net.sourceforge.jiu.data.BilevelImage; import net.sourceforge.jiu.data.GrayIntegerImage; import net.sourceforge.jiu.data.MemoryBilevelImage; import net.sourceforge.jiu.data.PixelImage; import net.sourceforge.jiu.ops.ImageToImageOperation; import net.sourceforge.jiu.ops.MissingParameterException; import net.sourceforge.jiu.ops.WrongParameterException; import net.sourceforge.jiu.util.ComparatorInterface; import net.sourceforge.jiu.util.Sort; /** * Apply a clustered dot ordered dither to a grayscale image, converting * it to a bilevel image in the process. * Works with {@link net.sourceforge.jiu.data.GrayIntegerImage} objects * as input and {@link net.sourceforge.jiu.data.BilevelImage} objects * as output. * Resolution of both must be the same. * Use one of the predefined dither matrices or have one compiled from * a spot function (given by an object of a class implementing * {@link net.sourceforge.jiu.color.dithering.SpotFunction}). * There are a couple of classes implementing that spot function interface * in the dithering package. * If no matrix is specified, {@link #process()} creates a default matrix * by calling {@link #setOrder3DitherMatrix()}. *
* ClusteredDotDither dither = new ClusteredDotDither(); * dither.setInputImage(image); // some GrayIntegerImage * dither.setDitherMatrix(8, 8, new DiamondSpotFunction()); * dither.process(); * PixelImage ditheredImage = dither.getOutputImage(); ** *
pgmtopbm
program (the matrices are stored in the
* file dithers.h
).
*
* I learned about spot functions and their use from Austin Donnelly's
* GIMP plugin newsprint - it has extensive comments, and the
* newsprint website
* explains the
* theoretical background.
* @author Marco Schmidt
* @since 0.9.0
*/
public class ClusteredDotDither extends ImageToImageOperation
{
private int ditherHeight;
private int ditherWidth;
private int[] ditherData;
public void process() throws
MissingParameterException,
WrongParameterException
{
if (ditherData == null)
{
setDefaults();
}
ensureInputImageIsAvailable();
PixelImage in = getInputImage();
if (!(in instanceof GrayIntegerImage))
{
throw new WrongParameterException("Input image must implement GrayIntegerImage.");
}
PixelImage out = getOutputImage();
if (out == null)
{
out = new MemoryBilevelImage(in.getWidth(), in.getHeight());
setOutputImage(out);
}
else
{
if (!(out instanceof BilevelImage))
{
throw new WrongParameterException("Output image must implement BilevelImage.");
}
ensureOutputImageResolution(in.getWidth(), in.getHeight());
}
process((GrayIntegerImage)in, (BilevelImage)out);
}
private void process(GrayIntegerImage in, BilevelImage out)
{
// find maximum entry in dither matrix
int maxTableValue = 1;
for (int i = 0; i < ditherData.length; i++)
{
if (ditherData[i] > maxTableValue)
{
maxTableValue = ditherData[i];
}
}
maxTableValue++;
// create adjusted dither matrix data
final int MAX_SAMPLE = in.getMaxSample(0) + 1;
final int[] data = new int[ditherData.length];
for (int i = 0; i < data.length; i++)
{
data[i] = ditherData[i] * MAX_SAMPLE / maxTableValue;
}
// do the actual dithering
final int HEIGHT = in.getHeight();
final int WIDTH = in.getWidth();
for (int y = 0; y < HEIGHT; y++)
{
int ditherOffset = (y % ditherHeight) * ditherWidth;
int samplesLeft = ditherWidth;
for (int x = 0; x < WIDTH; x++)
{
if (in.getSample(0, x, y) >= data[ditherOffset++])
{
out.putWhite(x, y);
}
else
{
out.putBlack(x, y);
}
if (--samplesLeft == 0)
{
samplesLeft = ditherWidth;
ditherOffset -= ditherWidth;
}
}
setProgress(y, HEIGHT);
}
}
private void setDefaults()
{
setOrder3DitherMatrix();
}
/**
* Sets the dither matrix to be used in this operation.
* @param width number of entries in horizontal direction
* @param height number of entries in vertical direction
* @param data matrix entries, in order top to bottom, and in each row left to right
* @throws IllegalArgumentException if width or height are smaller than one or data
* is null
or has not at least width times height entries
*/
public void setDitherMatrix(int width, int height, int[] data)
{
if (width < 1)
{
throw new IllegalArgumentException("Width must be one or larger.");
}
if (height < 1)
{
throw new IllegalArgumentException("Height must be one or larger.");
}
if (data == null)
{
throw new IllegalArgumentException("Data must not be null.");
}
if (data.length < width * height)
{
throw new IllegalArgumentException("Data must have at least width times height entries.");
}
ditherWidth = width;
ditherHeight = height;
ditherData = data;
}
/**
* Creates and sets a dither matrix of user-defined size and
* compiles it from a spot function.
* Creates a matrix from the spot function and calls {@link #setDitherMatrix(int, int, int[])}.
* @param width width of matrix, must be one or larger
* @param height height of matrix, must be one or larger
* @param f the spot function to be used for compiling the matrix
*/
public void setDitherMatrix(int width, int height, SpotFunction f)
{
class MatrixElement implements ComparatorInterface
{
int index;
double value;
public int compare(Object o1, Object o2)
{
MatrixElement e1 = (MatrixElement)o1;
MatrixElement e2 = (MatrixElement)o2;
if (e1.value < e2.value)
{
return -1;
}
else
if (e1.value == e2.value)
{
return 0;
}
else
{
return 1;
}
}
}
int[] data = new int[width * height];
MatrixElement[] matrixElements = new MatrixElement[data.length];
for (int i = 0; i < data.length; i++)
{
matrixElements[i] = new MatrixElement();
matrixElements[i].index = i;
}
int index = 0;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
double sx = ((double)x / (width - 1) - 0.5) * 2;
double sy = ((double)y / (height - 1) - 0.5) * 2;
double value = f.compute(sx, sy);
if (value < -1.0)
{
value = -1.0;
}
else
if (value > 1.0)
{
value = 1.0;
}
matrixElements[index++].value = value;
}
}
boolean balanced = f.isBalanced();
if (!balanced)
{
Sort.sort(matrixElements, matrixElements[0]);
}
for (int i = 0; i < data.length; i++)
{
MatrixElement elem = matrixElements[i];
if (balanced)
{
data[elem.index] = (int)(elem.value * 254);
}
else
{
data[elem.index] = i * 255 / data.length;
}
}
setDitherMatrix(width, height, data);
}
/**
* Sets a 6 times 6 elements matrix to be used for dithering.
*/
public void setOrder3DitherMatrix()
{
setDitherMatrix(6, 6, new int[]
{ 9, 11, 10, 8, 6, 7,
12, 17, 16, 5, 0, 1,
13, 14, 15, 4, 3, 2,
8, 6, 7, 9, 11, 10,
5, 0, 1, 12, 17, 16,
4, 3, 2, 13, 14, 15});
}
/**
* Sets an 8 times 8 elements matrix to be used for dithering.
*/
public void setOrder4DitherMatrix()
{
setDitherMatrix(8, 8, new int[]
{18,20,19,16,13,11,12,15,
27,28,29,22, 4, 3, 2, 9,
26,31,30,21, 5, 0, 1,10,
23,25,24,17, 8, 6, 7,14,
13,11,12,15,18,20,19,16,
4, 3, 2, 9,27,28,29,22,
5, 0, 1,10,26,31,30,21,
8, 6, 7,14,23,25,24,17});
}
/**
* Sets a 16 times 16 elements matrix to be used for dithering.
*/
public void setOrder8DitherMatrix()
{
setDitherMatrix(16, 16, new int[] {
64, 69, 77, 87, 86, 76, 68, 67, 63, 58, 50, 40, 41, 51, 59, 60,
70, 94,100,109,108, 99, 93, 75, 57, 33, 27, 18, 19, 28, 34, 52,
78,101,114,116,115,112, 98, 83, 49, 26, 13, 11, 12, 15, 29, 44,
88,110,123,124,125,118,107, 85, 39, 17, 4, 3, 2, 9, 20, 42,
89,111,122,127,126,117,106, 84, 38, 16, 5, 0, 1, 10, 21, 43,
79,102,119,121,120,113, 97, 82, 48, 25, 8, 6, 7, 14, 30, 45,
71, 95,103,104,105, 96, 92, 74, 56, 32, 24, 23, 22, 31, 35, 53,
65, 72, 80, 90, 91, 81, 73, 66, 62, 55, 47, 37, 36, 46, 54, 61,
63, 58, 50, 40, 41, 51, 59, 60, 64, 69, 77, 87, 86, 76, 68, 67,
57, 33, 27, 18, 19, 28, 34, 52, 70, 94,100,109,108, 99, 93, 75,
49, 26, 13, 11, 12, 15, 29, 44, 78,101,114,116,115,112, 98, 83,
39, 17, 4, 3, 2, 9, 20, 42, 88,110,123,124,125,118,107, 85,
38, 16, 5, 0, 1, 10, 21, 43, 89,111,122,127,126,117,106, 84,
48, 25, 8, 6, 7, 14, 30, 45, 79,102,119,121,120,113, 97, 82,
56, 32, 24, 23, 22, 31, 35, 53, 71, 95,103,104,105, 96, 92, 74,
62, 55, 47, 37, 36, 46, 54, 61, 65, 72, 80, 90, 91, 81, 73, 66});
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/dithering/DiamondSpotFunction.java 0000664 0000000 0000000 00000001253 07741250132 027715 0 ustar /*
* DiamondSpotFunction
*
* Copyright (c) 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.color.dithering;
import net.sourceforge.jiu.color.dithering.SpotFunction;
/**
* A diamond spot function.
* @author Marco Schmidt
* @since 0.9.0
* @see ClusteredDotDither
*/
public class DiamondSpotFunction implements SpotFunction
{
public double compute(double x, double y)
{
double xy = Math.abs(x) + Math.abs(y);
if (xy <= 1)
{
return 0.5 * xy * xy;
}
else
{
double xy1 = xy - 1;
return (2 * xy * xy - 4 * xy1 * xy1) / 4;
}
}
public boolean isBalanced()
{
return false;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/dithering/SpotFunction.java 0000664 0000000 0000000 00000001405 07741250132 026420 0 ustar /*
* SpotFunction
*
* Copyright (c) 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.color.dithering;
/**
* An interface for spot functions to be used for clustered dot dithering.
* @author Marco Schmidt
* @since 0.9.0
* @see ClusteredDotDither
*/
public interface SpotFunction
{
/**
* Compute the spot intensity at the given position.
* @param x horizontal position, must be between -1.0 and 1.0 (including both)
* @param y vertical position, must be between -1.0 and 1.0 (including both)
* @return the function value, must be between 0.0 and 1.0 (including both)
*/
double compute(double x, double y);
/**
* Returns if this spot function is balanced.
*/
boolean isBalanced();
}
././@LongLink 0000000 0000000 0000000 00000000146 00000000000 011566 L ustar root root java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/dithering/ErrorDiffusionDithering.java java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/dithering/ErrorDiffusionDithering.jav0000664 0000000 0000000 00000070204 10546765207 030440 0 ustar /*
* ErrorDiffusionDithering
*
* Copyright (c) 2001, 2002, 2003, 2004 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.color.dithering;
import net.sourceforge.jiu.color.quantization.RGBQuantizer;
import net.sourceforge.jiu.data.BilevelImage;
import net.sourceforge.jiu.data.Gray8Image;
import net.sourceforge.jiu.data.IntegerImage;
import net.sourceforge.jiu.data.MemoryBilevelImage;
import net.sourceforge.jiu.data.MemoryGray8Image;
import net.sourceforge.jiu.data.MemoryPaletted8Image;
import net.sourceforge.jiu.data.Paletted8Image;
import net.sourceforge.jiu.data.PixelImage;
import net.sourceforge.jiu.data.RGB24Image;
import net.sourceforge.jiu.data.RGBIndex;
import net.sourceforge.jiu.ops.ImageToImageOperation;
import net.sourceforge.jiu.ops.MissingParameterException;
import net.sourceforge.jiu.ops.WrongParameterException;
/**
* This class is used to apply error diffusion dithering to images that are being reduced in their color depth.
* Works with {@link net.sourceforge.jiu.data.GrayIntegerImage} and
* {@link net.sourceforge.jiu.data.RGBIntegerImage} objects.
* For RGB images, a quantizer must be specified via {@link #setQuantizer}.
* That quantizer must have been initialized (it must have searched for / given a palette that it can map to).
*
* This class offers six predefined types of error diffusion dithering. * In addition, user-defined types can be integrated by providing a * information on how the error is to be distributed; see the * description of {@link #setTemplateData}. * *
* MemoryRGB24Image image = ...; // some RGB image * OctreeColorQuantizer quantizer = new OctreeColorQuantizer(); * quantizer.setInputImage(image); * quantizer.setPaletteSize(120); * quantizer.init(); * ErrorDiffusionDithering edd = new ErrorDiffusionDithering(); * edd.setTemplateType(ErrorDiffusionDithering.TYPE_STUCKI); * edd.setQuantizer(quantizer); * edd.setInputImage(image); * edd.process(); * PixelImage quantizedImage = edd.getOutputImage(); **
* Gray8Image image = ...; // some grayscale image * ErrorDiffusionDithering edd = new ErrorDiffusionDithering(); * edd.setGrayscaleOutputBits(1); * edd.setInputImage(image); * edd.process(); * PixelImage ditheredImage = edd.getOutputImage(); * // if you need something more specific than PixelImage: * BilevelImage output = null; * // ditheredImage should be a BilevelImage... * if (ditheredImage instanceof BilevelImage * { * // ... and it is! * output = (BilevelImage)ditheredImage; * } **
* Several sources recommend Robert Ulichney's book * Digital * Halftoning for this topic (published by The MIT Press, ISBN 0-262-21009-6). * Unfortunately, I wasn't able to get a copy (or the CD-ROM version published by * Dr. Dobb's Journal). * * @since 0.5.0 * @author Marco Schmidt */ public class ErrorDiffusionDithering extends ImageToImageOperation implements RGBIndex { /** * Constant for Floyd-Steinberg error diffusion. * The quantization error is distributed to four neighboring pixels. */ public static final int TYPE_FLOYD_STEINBERG = 0; /** * Constant for Stucki error diffusion. * The quantization error is distributed to twelve neighboring pixels. */ public static final int TYPE_STUCKI = 1; /** * Constant for Burkes error diffusion. * The quantization error is distributed to seven neighboring pixels. */ public static final int TYPE_BURKES = 2; /** * Constant for Burkes error diffusion. * The quantization error is distributed to ten neighboring pixels. */ public static final int TYPE_SIERRA = 3; /** * Constant for Burkes error diffusion. * The quantization error is distributed to twelve neighboring pixels. */ public static final int TYPE_JARVIS_JUDICE_NINKE= 4; /** * Constant for Burkes error diffusion. * The quantization error is distributed to twelve neighboring pixels. */ public static final int TYPE_STEVENSON_ARCE = 5; /** * The default error diffusion type, to be used if none is specified by the user: * (@link #TYPE_FLOYD_STEINBERG}. */ public static final int DEFAULT_TYPE = TYPE_FLOYD_STEINBERG; /** * The index for the horizontal position of a neighbor pixel. * For a description, see the constructor {@link #setTemplateData}. */ public static final int INDEX_X_POS = 0; /** * The index for the vertical position of a neighbor pixel. * For a description, see the constructor {@link #setTemplateData}. */ public static final int INDEX_Y_POS = 1; /** * The index of the numerator of the relative part of the error of a neighbor pixel. * For a description, see the constructor {@link #setTemplateData}. */ public static final int INDEX_ERROR_NUMERATOR = 2; /** * The index of the denominator of the relative part of the error of a neighbor pixel. * For a description, see the constructor {@link #setTemplateData}. */ public static final int INDEX_ERROR_DENOMINATOR = 3; private static final int[][] FLOYD_STEINBERG_DATA = {{ 1, 0, 7, 16}, {-1, 1, 3, 16}, { 0, 1, 5, 16}, { 1, 1, 1, 16}}; private static final int[][] STUCKI_DATA = {{ 1, 0, 8, 42}, { 2, 0, 4, 42}, {-2, 1, 2, 42}, {-1, 1, 4, 42}, { 0, 1, 8, 42}, { 1, 1, 4, 42}, { 2, 1, 2, 42}, {-2, 2, 1, 42}, {-1, 2, 2, 42}, { 0, 2, 4, 42}, { 1, 2, 2, 42}, { 2, 2, 1, 42}}; private static final int[][] BURKES_DATA = {{ 1, 0, 8, 32}, { 2, 0, 4, 32}, {-2, 1, 2, 32}, {-1, 1, 4, 32}, { 0, 1, 8, 32}, { 1, 1, 4, 32}, { 2, 1, 2, 32}}; private static final int[][] SIERRA_DATA = {{ 1, 0, 5, 32}, { 2, 1, 3, 32}, {-2, 1, 2, 32}, {-1, 1, 4, 32}, { 0, 1, 5, 32}, { 1, 1, 4, 32}, { 2, 1, 2, 32}, {-1, 2, 2, 32}, { 0, 2, 3, 32}, { 1, 2, 2, 32}}; private static final int[][] JARVIS_JUDICE_NINKE_DATA = {{ 1, 0, 7, 48}, { 2, 0, 5, 48}, {-2, 1, 3, 48}, {-1, 1, 5, 48}, { 0, 1, 7, 48}, { 1, 1, 5, 48}, { 2, 1, 3, 48}, {-2, 2, 1, 48}, {-1, 2, 3, 48}, { 0, 2, 5, 48}, { 1, 2, 3, 48}, { 2, 2, 1, 48}}; private static final int[][] STEVENSON_ARCE_DATA = {{ 2, 0, 32, 200}, {-3, 1, 12, 200}, {-1, 1, 26, 200}, { 1, 1, 30, 200}, { 3, 1, 16, 200}, {-2, 2, 12, 200}, { 0, 2, 26, 200}, { 2, 2, 12, 200}, {-3, 3, 5, 200}, {-1, 3, 12, 200}, { 1, 3, 12, 200}, { 3, 3, 5, 200}}; private int grayBits; private int imageWidth; private int leftColumns; private int rightColumns; private int newWidth; private int numRows; private int[][] templateData; private int[] errorNum; private int[] errorDen; private int[] indexLut; private RGBQuantizer quantizer; private boolean useTruecolorOutput; /** * Creates a new object of this class and set the dithering type to * {@link #DEFAULT_TYPE}. */ public ErrorDiffusionDithering() { setTemplateType(DEFAULT_TYPE); } /** * Clamps the argument value to interval 0..max. * @param value the value to be adjusted * @param max the maximum allowed value (minimum is always 0) * @return the adjusted value */ private static int adjust(int value, int max) { if (value <= 0) { return 0; } else if (value >= max) { return max; } else { return value; } } /** * Copies data from input image to argument buffer. * @param channelIndex index of the channel of the input image from which data is to be copied * @param rowIndex index of the row of the input image from which data is to be copied * @param dest the array to which data is to be copied * @param destOffset index of the first element in the dest array to which data will be copied */ private void fillBuffer(int channelIndex, int rowIndex, int[] dest, int destOffset) { IntegerImage in = (IntegerImage)getInputImage(); final int LAST = destOffset + imageWidth; int x = 0; while (destOffset != LAST) { dest[destOffset++] = in.getSample(channelIndex, x++, rowIndex); } } private void init(int[][] data, int imageWidth) { if (data == null) { throw new IllegalArgumentException("Data must not be null."); } if (imageWidth < 1) { throw new IllegalArgumentException("Image width must be larger than 0."); } this.imageWidth = imageWidth; leftColumns = 0; rightColumns = 0; numRows = 1; errorNum = new int[data.length]; errorDen = new int[data.length]; for (int i = 0; i < data.length; i++) { if (data[i] == null) { throw new IllegalArgumentException("Each int[] array of data must be initialized; array #" + i + " is not."); } if (data[i].length != 4) { throw new IllegalArgumentException("Each int[] array of data must be of length 4; array #" + i + " has length " + data[i].length + "."); } int x = data[i][INDEX_X_POS]; if (x < 0) { x = - x; if (x > leftColumns) { leftColumns = x; } } else if (x > 0) { if (x > rightColumns) { rightColumns = x; } } int y = data[i][INDEX_Y_POS]; if (y < 0) { throw new IllegalArgumentException("The y values must be >= 0; that is not true for array index #" + i + "."); } if (y > numRows - 1) { numRows = y + 1; } if (x <= 0 && y == 0) { throw new IllegalArgumentException("If y is equal to 0, x must not be <= 0; this is true for array index #" + i + "."); } if (data[i][INDEX_ERROR_NUMERATOR] == 0 || data[i][INDEX_ERROR_DENOMINATOR] == 0) { throw new IllegalArgumentException("Neither numerator nor denominator can be 0; this is the case for array index #" + i + "."); } errorNum[i] = data[i][INDEX_ERROR_NUMERATOR]; errorDen[i] = data[i][INDEX_ERROR_DENOMINATOR]; } newWidth = imageWidth + leftColumns + rightColumns; //System.out.println("new width=" + newWidth); indexLut = new int[data.length]; for (int i = 0; i < indexLut.length; i++) { indexLut[i] = data[i][INDEX_Y_POS] * newWidth + data[i][INDEX_X_POS]; //System.out.println("lut i=" + i + "=" + indexLut[i]); } } /** * Quantizes the input image, distributing quantization errors to neighboring * pixels. * Works for {@link Gray8Image} (then {@link #setGrayscaleOutputBits(int)} * must have been called to set a number of output bits between 1 and 7) objects and * {@link RGB24Image} (then a quantizer must be specified using * {@link #setQuantizer(RGBQuantizer)}) objects. */ public void process() throws MissingParameterException, WrongParameterException { ensureInputImageIsAvailable(); ensureImagesHaveSameResolution(); PixelImage in = getInputImage(); PixelImage out = getOutputImage(); if (in instanceof Gray8Image) { init(templateData, in.getWidth()); if (grayBits == 1) { process((Gray8Image)in, (BilevelImage)out); } else if (grayBits > 1 && grayBits < 8) { process((Gray8Image)in, (Gray8Image)out); } else { throw new WrongParameterException("Cannot handle gray bits other than 1..7."); } } else if (in instanceof RGB24Image) { init(templateData, in.getWidth()); if (quantizer == null) { throw new MissingParameterException("No quantizer was specified."); } if (useTruecolorOutput) { process((RGB24Image)in, (RGB24Image)out); } else { process((RGB24Image)in, (Paletted8Image)out); } } else { throw new WrongParameterException("Cannot handle this image: " + in.toString()); } } private void process(Gray8Image in, BilevelImage out) { final int HEIGHT = in.getHeight(); final int WIDTH = in.getWidth(); if (out == null) { out = new MemoryBilevelImage(WIDTH, HEIGHT); } final int NUM_ERROR_PIXELS = errorNum.length; // create buffer int[] buffer = new int[newWidth * numRows]; //System.out.println("buffer length=" + buffer.length); // fill buffer with numRows (or HEIGHT, whatever is smaller) rows of data int n = Math.min(numRows, HEIGHT); int offset = leftColumns; int bufferYIndex = 0; while (n-- > 0) { fillBuffer(0, bufferYIndex++, buffer, offset); offset += newWidth; } int bufferLastRowOffset = offset - newWidth; // set complete output image to black out.clear(BilevelImage.BLACK); for (int y = 0; y < HEIGHT; y++) { int bufferIndex = leftColumns; for (int x = 0; x < WIDTH; x++) { int value = buffer[bufferIndex]; if (value < 0) { value = 0; } else if (value > 255) { value = 255; } int error; if ((value & 0x80) == 0) { // black pixel need not be written to output image // because all of its pixels have initially been set // to that color error = value; } else { // white out.putWhite(x, y); error = value - 255; } for (int i = 0; i < NUM_ERROR_PIXELS; i++) { int errorPart = error * errorNum[i] / errorDen[i]; buffer[bufferIndex + indexLut[i]] += errorPart; } bufferIndex++; } for (int i = 0, j = newWidth; j < buffer.length; i++, j++) { buffer[i] = buffer[j]; } if (bufferYIndex < HEIGHT) { fillBuffer(0, bufferYIndex++, buffer, bufferLastRowOffset); } setProgress(y, HEIGHT); } setOutputImage(out); } private void process(Gray8Image in, Gray8Image out) { final int HEIGHT = in.getHeight(); final int WIDTH = in.getWidth(); final int RIGHT_SHIFT = 8 - grayBits; final int[] GRAY_LUT = new int[1 << grayBits]; for (int i = 0; i < GRAY_LUT.length; i++) { GRAY_LUT[i] = i * 255 / (GRAY_LUT.length - 1); } if (out == null) { out = new MemoryGray8Image(WIDTH, HEIGHT); } final int NUM_ERROR_PIXELS = errorNum.length; // create buffer int[] buffer = new int[newWidth * numRows]; // fill buffer with numRows (or HEIGHT, whatever is smaller) rows of data int n = Math.min(numRows, HEIGHT); int offset = leftColumns; int bufferYIndex = 0; while (n-- > 0) { fillBuffer(0, bufferYIndex++, buffer, offset); offset += newWidth; } int bufferLastRowOffset = offset - newWidth; for (int y = 0; y < HEIGHT; y++) { int bufferIndex = leftColumns; for (int x = 0; x < WIDTH; x++) { int value = buffer[bufferIndex]; if (value < 0) { value = 0; } else if (value > 255) { value = 255; } int quantized = GRAY_LUT[value >> RIGHT_SHIFT]; out.putSample(0, x, y, quantized); int error = value - quantized; for (int i = 0; i < NUM_ERROR_PIXELS; i++) { int errorPart = error * errorNum[i] / errorDen[i]; buffer[bufferIndex + indexLut[i]] += errorPart; } bufferIndex++; } for (int i = 0, j = newWidth; j < buffer.length; i++, j++) { buffer[i] = buffer[j]; } if (bufferYIndex < HEIGHT) { fillBuffer(0, bufferYIndex++, buffer, bufferLastRowOffset); } setProgress(y, HEIGHT); } setOutputImage(out); } private void process(RGB24Image in, Paletted8Image out) { final int HEIGHT = in.getHeight(); final int WIDTH = in.getWidth(); final int MAX = 255; if (out == null) { out = new MemoryPaletted8Image(WIDTH, HEIGHT, quantizer.createPalette()); } final int NUM_ERROR_PIXELS = errorNum.length; // create buffers int[] redBuffer = new int[newWidth * numRows]; int[] greenBuffer = new int[newWidth * numRows]; int[] blueBuffer = new int[newWidth * numRows]; //System.out.println("buffer length=" + buffer.length); // fill buffer with numRows (or HEIGHT, whatever is smaller) rows of data int n = Math.min(numRows, HEIGHT); int offset = leftColumns; int bufferYIndex = 0; while (n-- > 0) { fillBuffer(INDEX_RED, bufferYIndex, redBuffer, offset); fillBuffer(INDEX_GREEN, bufferYIndex, greenBuffer, offset); fillBuffer(INDEX_BLUE, bufferYIndex++, blueBuffer, offset); offset += newWidth; } int bufferLastRowOffset = offset - newWidth; int[] originalRgb = new int[3]; int[] quantizedRgb = new int[3]; for (int y = 0; y < HEIGHT; y++) { int bufferIndex = leftColumns; for (int x = 0; x < WIDTH; x++) { originalRgb[INDEX_RED] = adjust(redBuffer[bufferIndex], MAX); originalRgb[INDEX_GREEN] = adjust(greenBuffer[bufferIndex], MAX); originalRgb[INDEX_BLUE] = adjust(blueBuffer[bufferIndex], MAX); int paletteIndex = quantizer.map(originalRgb, quantizedRgb); out.putSample(0, x, y, paletteIndex); // red int error = originalRgb[INDEX_RED] - quantizedRgb[INDEX_RED]; for (int i = 0; i < NUM_ERROR_PIXELS; i++) { int errorPart = error * errorNum[i] / errorDen[i]; redBuffer[bufferIndex + indexLut[i]] += errorPart; } // green error = originalRgb[INDEX_GREEN] - quantizedRgb[INDEX_GREEN]; for (int i = 0; i < NUM_ERROR_PIXELS; i++) { int errorPart = error * errorNum[i] / errorDen[i]; greenBuffer[bufferIndex + indexLut[i]] += errorPart; } // blue error = originalRgb[INDEX_BLUE] - quantizedRgb[INDEX_BLUE]; for (int i = 0; i < NUM_ERROR_PIXELS; i++) { int errorPart = error * errorNum[i] / errorDen[i]; blueBuffer[bufferIndex + indexLut[i]] += errorPart; } bufferIndex++; } System.arraycopy(redBuffer, newWidth, redBuffer, 0, redBuffer.length - newWidth); System.arraycopy(greenBuffer, newWidth, greenBuffer, 0, greenBuffer.length - newWidth); System.arraycopy(blueBuffer, newWidth, blueBuffer, 0, blueBuffer.length - newWidth); if (bufferYIndex < HEIGHT) { fillBuffer(INDEX_RED, bufferYIndex, redBuffer, bufferLastRowOffset); fillBuffer(INDEX_GREEN, bufferYIndex, greenBuffer, bufferLastRowOffset); fillBuffer(INDEX_BLUE, bufferYIndex++, blueBuffer, bufferLastRowOffset); } setProgress(y, HEIGHT); } setOutputImage(out); } private void process(RGB24Image in, RGB24Image out) { final int HEIGHT = in.getHeight(); final int WIDTH = in.getWidth(); final int MAX = 255; if (out == null) { out = (RGB24Image)in.createCompatibleImage(WIDTH, HEIGHT); } final int NUM_ERROR_PIXELS = errorNum.length; // create buffers int[] redBuffer = new int[newWidth * numRows]; int[] greenBuffer = new int[newWidth * numRows]; int[] blueBuffer = new int[newWidth * numRows]; // fill buffer with numRows (or HEIGHT, whatever is smaller) rows of data int n = Math.min(numRows, HEIGHT); int offset = leftColumns; int bufferYIndex = 0; while (n-- > 0) { fillBuffer(INDEX_RED, bufferYIndex, redBuffer, offset); fillBuffer(INDEX_GREEN, bufferYIndex, greenBuffer, offset); fillBuffer(INDEX_BLUE, bufferYIndex++, blueBuffer, offset); offset += newWidth; } int bufferLastRowOffset = offset - newWidth; int[] originalRgb = new int[3]; int[] quantizedRgb = new int[3]; for (int y = 0; y < HEIGHT; y++) { int bufferIndex = leftColumns; for (int x = 0; x < WIDTH; x++) { originalRgb[INDEX_RED] = adjust(redBuffer[bufferIndex], MAX); originalRgb[INDEX_GREEN] = adjust(greenBuffer[bufferIndex], MAX); originalRgb[INDEX_BLUE] = adjust(blueBuffer[bufferIndex], MAX); /*int paletteIndex = quantizer.map(originalRgb, quantizedRgb); out.putSample(0, x, y, paletteIndex);*/ out.putSample(INDEX_RED, x, y, quantizedRgb[INDEX_RED]); out.putSample(INDEX_GREEN, x, y, quantizedRgb[INDEX_GREEN]); out.putSample(INDEX_BLUE, x, y, quantizedRgb[INDEX_BLUE]); // red int error = originalRgb[INDEX_RED] - quantizedRgb[INDEX_RED]; for (int i = 0; i < NUM_ERROR_PIXELS; i++) { int errorPart = error * errorNum[i] / errorDen[i]; redBuffer[bufferIndex + indexLut[i]] += errorPart; } // green error = originalRgb[INDEX_GREEN] - quantizedRgb[INDEX_GREEN]; for (int i = 0; i < NUM_ERROR_PIXELS; i++) { int errorPart = error * errorNum[i] / errorDen[i]; greenBuffer[bufferIndex + indexLut[i]] += errorPart; } // blue error = originalRgb[INDEX_BLUE] - quantizedRgb[INDEX_BLUE]; for (int i = 0; i < NUM_ERROR_PIXELS; i++) { int errorPart = error * errorNum[i] / errorDen[i]; blueBuffer[bufferIndex + indexLut[i]] += errorPart; } bufferIndex++; } /*for (int i = 0, j = newWidth; j < buffer.length; i++, j++) { buffer[i] = buffer[j]; }*/ System.arraycopy(redBuffer, newWidth, redBuffer, 0, redBuffer.length - newWidth); System.arraycopy(greenBuffer, newWidth, greenBuffer, 0, greenBuffer.length - newWidth); System.arraycopy(blueBuffer, newWidth, blueBuffer, 0, blueBuffer.length - newWidth); if (bufferYIndex < HEIGHT) { fillBuffer(INDEX_RED, bufferYIndex, redBuffer, bufferLastRowOffset); fillBuffer(INDEX_GREEN, bufferYIndex, greenBuffer, bufferLastRowOffset); fillBuffer(INDEX_BLUE, bufferYIndex++, blueBuffer, bufferLastRowOffset); } setProgress(y, HEIGHT); } setOutputImage(out); } /** * Sets the number of bits to be in the output image when a grayscale image * is quantized. * If the input image is of type {@link Gray8Image}, only values between 1 and 7 * are valid. * @param numBits the number of bits in the output image */ public void setGrayscaleOutputBits(int numBits) { grayBits = numBits; } /** * Sets the color quantizer to be used (if the input image is * a truecolor image). * @param q an object of a class implementing the RGBQuantizer interface */ public void setQuantizer(RGBQuantizer q) { quantizer = q; } /** * Set information on how errors are to be distributed by this error diffusion * dithering operation. *
* Error diffusion dithering works by quantizing each pixel and distributing the * resulting error to neighboring pixels. * Quantizing maps a pixel to another pixel. * Each pixel is made up of one or more samples (as an example, three samples * rorig, gorig and borig for the * original pixel of an RGB image and rquant, gquant and * bquant for the quantized pixel). *
* The process of quantization attempts to find a quantized pixel that is as * close to the original as possible. * In the ideal case, the difference between original and quantized pixel is * zero for each sample. * Otherwise, this quantization error is non-zero, positive or negative. * Example: original pixel (12, 43, 33), quantized pixel (10, 47, 40); the * error is (12 - 10, 43 - 47, 40 - 33) = (2, -4, 7). * The error (2, -4, 7) is to be distributed to neighboring pixels. *
* The data
argument of this constructor describes how to do that.
* It is a two-dimensional array of int values.
* Each of the one-dimensional int arrays of data
describe
* one neighboring pixel and the relative amount of the error that it gets.
* That is why data.length
specifies the number of neighboring
* pixels involved in distributing the error.
* Let's call the pixel that was just quantized the current pixel.
* It is at image position (x, y).
*
* Each of the one-dimensional arrays that are part of data
* must have a length of 4.
* The meaning of these four values is now described.
* The values can be accessed by the INDEX_xyz constants of this class.
* These four values describe the position of one neighboring pixel and
* the relative amount of the error that will be added to or subtracted
* from it.
*
data
array:
* * int[][] FLOYD_STEINBERG = {{ 1, 0, 7, 16}, * {-1, 1, 3, 16}, * { 0, 1, 5, 16}, * { 1, 1, 1, 16}}; ** Each of the one-dimensional arrays is of length 4. * Accidentally, there are also four one-dimensional arrays. * The number of arrays is up to the designer. * The first array {1, 0, 7, 16} is interpreted as follows--go to * the pixel with a horizontal difference of 1 and a vertical difference of 0 * (so, the pixel to the right of the current pixel) and add 7 / 16th of the * quantization error to it. * Then go to the pixel at position (-1, 1) (one to the left, one row below the * current row) and add 3 / 16th of the error to it. * The other two one-dimensional arrays are processed just like that. *
* As you can see, the four relative errors 1/16, 3/16, 5/16 and 7/16 sum up to
* 1 (or 16/16); this is in a precondition to make sure that the error
* is distributed completely.
*
* @param data contains a description of how the error is to be distributed
*/
public void setTemplateData(int[][] data)
{
templateData = data;
}
/**
* When dithering an RGB input image, this method specifies whether the
* output will be an {@link net.sourceforge.jiu.data.RGBIntegerImage}
* (true
) or a {@link net.sourceforge.jiu.data.Paletted8Image} (false
).
* @param truecolor true if truecolor output is wanted
*/
public void setTruecolorOutput(boolean truecolor)
{
useTruecolorOutput = truecolor;
}
/**
* Sets a new template type.
* The argument must be one of the TYPE_xyz constants of this class.
* @param type int value, one of the TYPE_xyz constants of this class
* @throws IllegalArgumentException if the argument is not of the TYPE_xyz constants
*/
public void setTemplateType(int type)
{
switch(type)
{
case(TYPE_FLOYD_STEINBERG):
{
templateData = FLOYD_STEINBERG_DATA;
break;
}
case(TYPE_STUCKI):
{
templateData = STUCKI_DATA;
break;
}
case(TYPE_BURKES):
{
templateData = BURKES_DATA;
break;
}
case(TYPE_SIERRA):
{
templateData = SIERRA_DATA;
break;
}
case(TYPE_JARVIS_JUDICE_NINKE):
{
templateData = JARVIS_JUDICE_NINKE_DATA;
break;
}
case(TYPE_STEVENSON_ARCE):
{
templateData = STEVENSON_ARCE_DATA;
break;
}
default:
{
throw new IllegalArgumentException("Unknown template type: " + type + ".");
}
}
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/dithering/RoundSpotFunction.java 0000664 0000000 0000000 00000001015 07741250132 027425 0 ustar /*
* RoundSpotFunction
*
* Copyright (c) 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.color.dithering;
import net.sourceforge.jiu.color.dithering.SpotFunction;
/**
* A round spot function.
* @author Marco Schmidt
* @since 0.9.0
* @see ClusteredDotDither
*/
public class RoundSpotFunction implements SpotFunction
{
public double compute(double x, double y)
{
return 1.0 - x * x - y * y;
}
public boolean isBalanced()
{
return false;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/dithering/package.html 0000664 0000000 0000000 00000000455 07741250132 025407 0 ustar
Classes for conversion between color spaces. Right now, this mostly includes conversion to the RGB (red / green / blue) color space. java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/dithering/OrderedDither.java 0000664 0000000 0000000 00000035675 10572434070 026532 0 ustar /* * OrderedDither * * Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.color.dithering; import net.sourceforge.jiu.color.quantization.UniformPaletteQuantizer; import net.sourceforge.jiu.data.BilevelImage; import net.sourceforge.jiu.data.Gray8Image; import net.sourceforge.jiu.data.MemoryBilevelImage; import net.sourceforge.jiu.data.MemoryGray8Image; import net.sourceforge.jiu.data.MemoryPaletted8Image; import net.sourceforge.jiu.data.MemoryRGB24Image; import net.sourceforge.jiu.data.PixelImage; import net.sourceforge.jiu.data.Paletted8Image; import net.sourceforge.jiu.data.RGB24Image; import net.sourceforge.jiu.data.RGBIndex; import net.sourceforge.jiu.ops.ImageToImageOperation; import net.sourceforge.jiu.ops.MissingParameterException; import net.sourceforge.jiu.ops.WrongParameterException; /** * This operation reduces the color depth of RGB truecolor images and grayscale images * by applying ordered dithering. * A relatively nice output image (for a human observer) will be created at the * cost of introducing noise into the output image. * The algorithm is relatively fast, but its quality is usually inferior to what * can be reached by using {@link ErrorDiffusionDithering} or similar other methods. *
* OrderedDither od = new OrderedDither(); * od.setRgbBits(3, 3, 2); * od.setInputImage(image); * od.process(); * Paletted8Image ditheredImage = (Paletted8Image)od.getOutputImage(); ** @author Marco Schmidt */ public class OrderedDither extends ImageToImageOperation implements RGBIndex { private int[] values; private int valueWidth; private int valueHeight; private int grayBits = 3; private int redBits = 3; private int greenBits = 3; private int blueBits = 2; private void process(Gray8Image in, Gray8Image out) { if (out == null) { out = new MemoryGray8Image(in.getWidth(), in.getHeight()); setOutputImage(out); } int D1 = 4; int D2 = 4; int D1D2 = D1 * D2; final int[] DITHER_MATRIX = {0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5}; final int SPACE = 255 / ((1 << grayBits) - 1); final int SHIFT = 8 - grayBits; final int NUM_VALUES = 1 << grayBits; final byte[] OUTPUT_SAMPLES = new byte[NUM_VALUES]; for (int i = 0; i < OUTPUT_SAMPLES.length; i++) { OUTPUT_SAMPLES[i] = (byte)((i * 255) / NUM_VALUES); } final int[] DITHER_SIGNAL = new int[D1D2]; for (int i = 0; i < D1D2; i++) { DITHER_SIGNAL[i] = (2 * DITHER_MATRIX[i] - D1D2 + 1) * SPACE / (2 * D1D2); } final int HEIGHT = in.getHeight(); final int WIDTH = in.getWidth(); int rowOffset = 0; for (int y = 0; y < HEIGHT; y++) { int offset = rowOffset; final int MAX_OFFSET = rowOffset + D1; for (int x = 0; x < WIDTH; x++) { int sample = in.getSample(0, x, y); sample = sample + DITHER_SIGNAL[ offset++ ]; if (offset == MAX_OFFSET) { offset = rowOffset; } if (sample < 0) { sample = 0; } else if (sample > 255) { sample = 255; } out.putByteSample(0, x, y, OUTPUT_SAMPLES[sample >> SHIFT]); } rowOffset += D1; if (rowOffset >= DITHER_SIGNAL.length) { rowOffset = 0; } setProgress(y, HEIGHT); } } private void process(Gray8Image in, BilevelImage out) { if (out == null) { out = new MemoryBilevelImage(in.getWidth(), in.getHeight()); setOutputImage(out); } if (values == null) { setStandardThresholdValues(); } out.clear(BilevelImage.BLACK); int rowOffset = 0; final int HEIGHT = in.getHeight(); for (int y = 0; y < HEIGHT; y++) { int offset = rowOffset; final int MAX_OFFSET = rowOffset + valueWidth; for (int x = 0; x < in.getWidth(); x++) { if (in.getSample(x, y) >= values[offset++]) { out.putWhite(x, y); } if (offset == MAX_OFFSET) { offset = rowOffset; } } setProgress(y, HEIGHT); rowOffset += valueWidth; if (rowOffset >= values.length) { rowOffset = 0; } } } private void process(RGB24Image in, Paletted8Image out) { UniformPaletteQuantizer upq = new UniformPaletteQuantizer(redBits, greenBits, blueBits); if (out == null) { out = new MemoryPaletted8Image(in.getWidth(), in.getHeight(), upq.createPalette()); setOutputImage(out); } int D1 = 4; int D2 = 4; int D1D2 = D1 * D2; final int[] DITHER_MATRIX = {0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5}; final int RED_SPACE = 255 / ((1 << redBits) - 1); final int GREEN_SPACE = 255 / ((1 << greenBits) - 1); final int BLUE_SPACE = 255 / ((1 << blueBits) - 1); /*final int RED_SHIFT = 8 - redBits; final int GREEN_SHIFT = 8 - redBits; final int BLUE_SHIFT = 8 - redBits; final int NUM_RED_VALUES = 1 << redBits; final int NUM_GREEN_VALUES = 1 << greenBits; final int NUM_BLUE_VALUES = 1 << blueBits;*/ final int[] RED_DITHER_SIGNAL = new int[D1D2]; final int[] GREEN_DITHER_SIGNAL = new int[D1D2]; final int[] BLUE_DITHER_SIGNAL = new int[D1D2]; for (int i = 0; i < D1D2; i++) { RED_DITHER_SIGNAL[i] = (2 * DITHER_MATRIX[i] - D1D2 + 1) * RED_SPACE / (2 * D1D2); GREEN_DITHER_SIGNAL[i] = (2 * DITHER_MATRIX[i] - D1D2 + 1) * GREEN_SPACE / (2 * D1D2); BLUE_DITHER_SIGNAL[i] = (2 * DITHER_MATRIX[i] - D1D2 + 1) * BLUE_SPACE / (2 * D1D2); } final int HEIGHT = in.getHeight(); final int WIDTH = in.getWidth(); int rowOffset = 0; for (int y = 0; y < HEIGHT; y++) { int offset = rowOffset; final int MAX_OFFSET = rowOffset + D1; for (int x = 0; x < WIDTH; x++) { int redSample = in.getSample(INDEX_RED, x, y); redSample = redSample + RED_DITHER_SIGNAL[ offset ]; if (redSample < 0) { redSample = 0; } else if (redSample > 255) { redSample = 255; } int greenSample = in.getSample(INDEX_GREEN, x, y); greenSample = greenSample + GREEN_DITHER_SIGNAL[ offset ]; if (greenSample < 0) { greenSample = 0; } else if (greenSample > 255) { greenSample = 255; } int blueSample = in.getSample(INDEX_BLUE, x, y); blueSample = blueSample + BLUE_DITHER_SIGNAL[ offset ]; if (blueSample < 0) { blueSample = 0; } else if (blueSample > 255) { blueSample = 255; } out.putSample(0, x, y, upq.mapToIndex(redSample, greenSample, blueSample)); offset++; if (offset == MAX_OFFSET) { offset = rowOffset; } } rowOffset += D1; if (rowOffset >= DITHER_MATRIX.length) { rowOffset = 0; } setProgress(y, HEIGHT); } } private void process(RGB24Image in, RGB24Image out) { //UniformPaletteQuantizer upq = new UniformPaletteQuantizer(redBits, greenBits, blueBits); //System.out.println("RGB=>RGB, r=" + redBits+ ", g=" + greenBits + ", b=" + blueBits); if (out == null) { out = new MemoryRGB24Image(in.getWidth(), in.getHeight()); setOutputImage(out); } int D1 = 4; int D2 = 4; int D1D2 = D1 * D2; final int[] DITHER_MATRIX = {0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5}; final int RED_SPACE = 255 / ((1 << redBits) - 1); final int GREEN_SPACE = 255 / ((1 << greenBits) - 1); final int BLUE_SPACE = 255 / ((1 << blueBits) - 1); final int RED_SHIFT = 8 - redBits; final int GREEN_SHIFT = 8 - greenBits; final int BLUE_SHIFT = 8 - blueBits; final int MAX_RED = (1 << redBits) - 1; final int MAX_GREEN = (1 << greenBits) - 1; final int MAX_BLUE = (1 << blueBits) - 1; /*final int NUM_RED_VALUES = 1 << redBits; final int NUM_GREEN_VALUES = 1 << greenBits; final int NUM_BLUE_VALUES = 1 << blueBits;*/ final int[] RED_DITHER_SIGNAL = new int[D1D2]; final int[] GREEN_DITHER_SIGNAL = new int[D1D2]; final int[] BLUE_DITHER_SIGNAL = new int[D1D2]; for (int i = 0; i < D1D2; i++) { RED_DITHER_SIGNAL[i] = (2 * DITHER_MATRIX[i] - D1D2 + 1) * RED_SPACE / (2 * D1D2); GREEN_DITHER_SIGNAL[i] = (2 * DITHER_MATRIX[i] - D1D2 + 1) * GREEN_SPACE / (2 * D1D2); BLUE_DITHER_SIGNAL[i] = (2 * DITHER_MATRIX[i] - D1D2 + 1) * BLUE_SPACE / (2 * D1D2); } final int HEIGHT = in.getHeight(); final int WIDTH = in.getWidth(); int rowOffset = 0; for (int y = 0; y < HEIGHT; y++) { int offset = rowOffset; final int MAX_OFFSET = rowOffset + D1; for (int x = 0; x < WIDTH; x++) { // RED int redSample = in.getSample(INDEX_RED, x, y); redSample = redSample + RED_DITHER_SIGNAL[ offset ]; if (redSample < 0) { redSample = 0; } else if (redSample > 255) { redSample = 255; } redSample >>= RED_SHIFT; out.putSample(RGBIndex.INDEX_RED, x, y, redSample * 255 / MAX_RED); // GREEN int greenSample = in.getSample(INDEX_GREEN, x, y); greenSample = greenSample + GREEN_DITHER_SIGNAL[ offset ]; if (greenSample < 0) { greenSample = 0; } else if (greenSample > 255) { greenSample = 255; } greenSample >>= GREEN_SHIFT; out.putSample(RGBIndex.INDEX_GREEN, x, y, greenSample * 255 / MAX_GREEN); // BLUE int blueSample = in.getSample(INDEX_BLUE, x, y); blueSample = blueSample + BLUE_DITHER_SIGNAL[offset]; if (blueSample < 0) { blueSample = 0; } else if (blueSample > 255) { blueSample = 255; } blueSample >>= BLUE_SHIFT; out.putSample(RGBIndex.INDEX_BLUE, x, y, blueSample * 255 / MAX_BLUE); //out.putSample(0, x, y, upq.mapToIndex(redSample, greenSample, blueSample)); offset++; if (offset == MAX_OFFSET) { offset = rowOffset; } } rowOffset += D1; if (rowOffset >= DITHER_MATRIX.length) { rowOffset = 0; } setProgress(y, HEIGHT); } } public void process() throws MissingParameterException, WrongParameterException { ensureInputImageIsAvailable(); ensureImagesHaveSameResolution(); PixelImage in = getInputImage(); PixelImage out = getOutputImage(); if (in instanceof RGB24Image) { int sum = redBits + greenBits + blueBits; if (sum > 8) { process((RGB24Image)in, (RGB24Image)out); } else { process((RGB24Image)in, (Paletted8Image)out); } } else if (grayBits == 1) { process((Gray8Image)in, (BilevelImage)out); } else if (grayBits >= 2 && grayBits <= 7) { process((Gray8Image)in, (Gray8Image)out); } } public void setOutputBits(int bits) { if (bits >= 1 && bits <= 7) { grayBits = bits; } else { throw new IllegalArgumentException("Grayscale output bits must be from 1..7; got " + bits); } } /** * Sets the number of bits to be used for each RGB component in the output image. * Each argument must be one or larger. * The values defined by this method are only used if the input image implements * RGBIntegerImage. * Later, in {@link #process}, these values are checked against * the actual number of bits per component in the input image. * If any of the arguments of this method is equal to or larger * than those actual bits per channel values, a WrongParameterException * will then be thrown. * Right now, there is no way how this can be checked, because * the input image may not have been defined yet. * @param red number of bits for the red channel in the output image * @param green number of bits for the green channel in the output image * @param blue number of bits for the blue channel in the output image * @throws IllegalArgumentException if at least one argument is smaller than
1
*/
public void setRgbBits(int red, int green, int blue)
{
if (red > 0 && green > 0 && blue > 0)
{
redBits = red;
greenBits = green;
blueBits = blue;
}
else
{
throw new IllegalArgumentException("All parameters must be 1 or larger.");
}
}
/**
* Calls {@link #setThresholdValues} with a 16 x 16 matrix.
*/
public void setStandardThresholdValues()
{
final int[] VALUES =
{
0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255,
128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127,
32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223,
160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95,
8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247,
136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119,
40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215,
168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87,
2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253,
130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125,
34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221,
162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93,
10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245,
138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117,
42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213,
170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85
};
setThresholdValues(VALUES, 16, 16);
}
/**
* Defines a matrix of threshold values that will be used for grayscale
* dithering.
* @param values the int values to use for comparing
* @param valueWidth
* @param valueHeight
*/
public void setThresholdValues(int[] values, int valueWidth, int valueHeight)
{
if (values == null)
{
throw new IllegalArgumentException("The value array must be non-null.");
}
if (valueWidth < 1)
{
throw new IllegalArgumentException("The width argument must be at least 1.");
}
if (valueHeight < 1)
{
throw new IllegalArgumentException("The height argument must be at least 1.");
}
this.values = values;
this.valueWidth = valueWidth;
this.valueHeight = valueHeight;
if (this.valueHeight * this.valueWidth < this.values.length)
{
throw new IllegalArgumentException("The array must have at least valuesWidth * valuesHeight elements..");
}
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/analysis/ 0000775 0000000 0000000 00000000000 10546532076 022777 5 ustar java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/analysis/TextureAnalysis.java 0000664 0000000 0000000 00000016736 10611674621 027017 0 ustar /*
* TextureAnalysis
*
* Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.color.analysis;
import net.sourceforge.jiu.color.data.CoOccurrenceMatrix;
import net.sourceforge.jiu.data.IntegerImage;
import net.sourceforge.jiu.ops.MissingParameterException;
import net.sourceforge.jiu.ops.Operation;
/**
* This class determines a number of properties for a given co-occurrence matrix.
* The only input parameter is a mandatory co-occurrence matrix object
* to be specified using {@link #setMatrix}.
* Then {@link #process} must be called.
* After that, the various properties can be retrieved using the
* corresponding get methods, e.g. {@link #getContrast},
* {@link #getEnergy} etc.
* * Static convenience methods {@link #compute(CoOccurrenceMatrix)} and * {@link #compute(IntegerImage, int)} exist for simplified usage. * You may need to cast your {@link net.sourceforge.jiu.data.PixelImage} to * {@link net.sourceforge.jiu.data.IntegerImage} first. *
GrayIntegerImage img = ...; TextureAnalysis op = TextureAnalysis.compute(img); System.out.println("Entropy=" + op.getEntropy());* Use the compute method that takes a {@link net.sourceforge.jiu.color.data.CoOccurrenceFrequencyMatrix} * if you want to reuse a matrix object. *
*
* Will not work with 16 bit image objects because {@link net.sourceforge.jiu.color.data.MemoryCoOccurrenceMatrix} * is rather unsophisticated, trying to allocate 4 * 65536 * 65536 bytes (16 GB). * Solution is an implementation of {@link net.sourceforge.jiu.color.data.CoOccurrenceMatrix} * which creates element counters on demand. * * The following resources were helpful when creating this class: *
Double meanDifference = MeanDifference.compute(image1, image2);* @author Marco Schmidt * @since 0.11.0 */ public class MeanDifference extends Operation { private double diff; private PixelImage image1; private PixelImage image2; /** * Compute the mean difference between two images. * @param image1 first image to be examined * @param image2 second image to be examined * @return sum of all differences divided by number of pixels * as Double or
null
on failure (image types
* are incompatible)
* @since 0.15.0
*/
public static Double compute(PixelImage image1, PixelImage image2)
{
MeanDifference diff = new MeanDifference();
diff.setImages(image1, image2);
try
{
diff.process();
return new Double(diff.getDifference());
}
catch (Exception e)
{
return null;
}
}
/**
* Returns abs(a - b).
* @param a first number
* @param b second number
* @return abs(a - b)
*/
private static int computeDiff(int a, int b)
{
// code is equal to Math.abs(a - b);
int diff = a - b;
if (diff < 0)
{
return -diff;
}
else
{
return diff;
}
}
/**
* After a call to process, returns the determined mean difference value.
* @return difference value, 0.0 or larger
*/
public double getDifference()
{
return diff;
}
public void process() throws MissingParameterException, WrongParameterException
{
if (image1 == null)
{
throw new MissingParameterException("You must specify images using setImages.");
}
boolean sameType = image1.getImageType() == image2.getImageType();
if (image1 instanceof RGB24Image && image2 instanceof Paletted8Image)
{
process((RGB24Image)image1, (Paletted8Image)image2);
}
else
if (image2 instanceof RGB24Image && image1 instanceof Paletted8Image)
{
process((RGB24Image)image2, (Paletted8Image)image1);
}
else
if (sameType && image1 instanceof RGBIntegerImage)
{
process((RGBIntegerImage)image1, (RGBIntegerImage)image2);
}
else
if (sameType && image1 instanceof GrayIntegerImage)
{
process((GrayIntegerImage)image1, (GrayIntegerImage)image2);
}
else
{
throw new WrongParameterException("Not a supported image type combination.");
}
}
private void process(GrayIntegerImage image1, GrayIntegerImage image2)
{
final int HEIGHT = image1.getHeight();
final int WIDTH = image1.getWidth();
long sum = 0;
for (int y = 0; y < HEIGHT; y++)
{
for (int x = 0; x < WIDTH; x++)
{
sum += computeDiff(image1.getSample(x, y), image2.getSample(x, y));
}
setProgress(y, HEIGHT);
}
setDifference((double)sum / (WIDTH * HEIGHT));
}
private void process(RGB24Image image1, Paletted8Image image2)
{
final int HEIGHT = image1.getHeight();
final int WIDTH = image1.getWidth();
long sum = 0;
Palette pal = image2.getPalette();
int[] red = pal.getSamples(RGBIndex.INDEX_RED);
int[] green = pal.getSamples(RGBIndex.INDEX_GREEN);
int[] blue = pal.getSamples(RGBIndex.INDEX_BLUE);
for (int y = 0; y < HEIGHT; y++)
{
for (int x = 0; x < WIDTH; x++)
{
int palSample = image2.getSample(x, y);
sum += computeDiff(image1.getSample(RGBIndex.INDEX_RED, x, y), red[palSample]);
sum += computeDiff(image1.getSample(RGBIndex.INDEX_GREEN, x, y), green[palSample]);
sum += computeDiff(image1.getSample(RGBIndex.INDEX_BLUE, x, y), blue[palSample]);
}
setProgress(y, HEIGHT);
}
setDifference((double)sum / (WIDTH * HEIGHT * 3));
}
private void process(RGBIntegerImage image1, RGBIntegerImage image2)
{
final int HEIGHT = image1.getHeight();
final int WIDTH = image1.getWidth();
long sum = 0;
for (int y = 0; y < HEIGHT; y++)
{
for (int x = 0; x < WIDTH; x++)
{
sum += computeDiff(image1.getSample(RGBIndex.INDEX_RED, x, y), image2.getSample(RGBIndex.INDEX_RED, x, y));
sum += computeDiff(image1.getSample(RGBIndex.INDEX_GREEN, x, y), image2.getSample(RGBIndex.INDEX_GREEN, x, y));
sum += computeDiff(image1.getSample(RGBIndex.INDEX_BLUE, x, y), image2.getSample(RGBIndex.INDEX_BLUE, x, y));
}
setProgress(y, HEIGHT);
}
setDifference((double)sum / (WIDTH * HEIGHT * 3));
}
private void setDifference(double newValue)
{
diff = newValue;
}
/**
* Sets the two images for which the mean difference is to be
* determined.
* @param firstImage first image
* @param secondImage second image
* @throws IllegalArgumentException if either of the images is null,
* if their resolution is different or if their types are not supported
* by this operation
*/
public void setImages(PixelImage firstImage, PixelImage secondImage)
{
if (firstImage == null || secondImage == null)
{
throw new IllegalArgumentException("Both image arguments must be non-null.");
}
if (firstImage.getWidth() != secondImage.getWidth())
{
throw new IllegalArgumentException("The images must have the same width.");
}
if (firstImage.getHeight() != secondImage.getHeight())
{
throw new IllegalArgumentException("The images must have the same height.");
}
image1 = firstImage;
image2 = secondImage;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/analysis/package.html 0000664 0000000 0000000 00000000412 07741250131 025245 0 ustar
Contains classes that analyze pixel or sample values and thus determine certain image properties. java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/analysis/MatrixCreator.java 0000664 0000000 0000000 00000015543 10546742753 026443 0 ustar /* * MatrixCreator * * Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.color.analysis; import net.sourceforge.jiu.data.Gray16Image; import net.sourceforge.jiu.data.Gray8Image; import net.sourceforge.jiu.data.IntegerImage; import net.sourceforge.jiu.data.Paletted8Image; import net.sourceforge.jiu.color.data.CoOccurrenceMatrix; import net.sourceforge.jiu.color.data.CoOccurrenceFrequencyMatrix; import net.sourceforge.jiu.color.data.MemoryCoOccurrenceMatrix; import net.sourceforge.jiu.color.data.MemoryCoOccurrenceFrequencyMatrix; /** * This class creates and initializes co-occurrence matrices and co-occurrence * frequency matrices. * @author Marco Schmidt */ public class MatrixCreator { private MatrixCreator() { // to prevent instantiation } /** * Create a co-occurrence matrix for a 16 bit grayscale image. * @param image the image for which the matrix is created * @return the resulting matrix * @since 0.15.0 */ public static CoOccurrenceMatrix createCoOccurrenceMatrix(Gray16Image image) { return createCoOccurrenceMatrix(image, 0); } public static CoOccurrenceMatrix createCoOccurrenceMatrix(Gray8Image image) { return createCoOccurrenceMatrix(image, 0); } public static CoOccurrenceMatrix createCoOccurrenceMatrix(Paletted8Image image) { return createCoOccurrenceMatrix(image, 0); } public static CoOccurrenceMatrix createCoOccurrenceMatrix(IntegerImage image, int channelIndex) { if (image == null) { throw new IllegalArgumentException("The image must non-null."); } if (channelIndex < 0) { throw new IllegalArgumentException("The channel index must be zero or larger."); } if (channelIndex >= image.getNumChannels()) { throw new IllegalArgumentException("The channel index must be smaller than the number of channels in the image (" + image.getNumChannels() + ")."); } int dim = image.getMaxSample(channelIndex) + 1; MemoryCoOccurrenceMatrix matrix = new MemoryCoOccurrenceMatrix(dim); initCoOccurrenceMatrix(image, channelIndex, matrix); return matrix; } /** * Initializes a co-occurrence matrix from the input image, using the direct * four neighbor pixels. * The number of entries in the palette of the argument image must be equal to the dimension * of the argument matrix. * @param image the image that will be used to initialize the matrix * @param matrix the matrix that will first be cleared and then initialized from the image * @throws IllegalArgumentException if at least one of the arguments is null or if the * palette size is not equal to the matrix dimension */ public static void initCoOccurrenceMatrix(IntegerImage image, int channelIndex, CoOccurrenceMatrix matrix) { if (image == null) { throw new IllegalArgumentException("The image must non-null."); } if (channelIndex < 0) { throw new IllegalArgumentException("The channel index must be zero or larger."); } if (channelIndex >= image.getNumChannels()) { throw new IllegalArgumentException("The channel index must be smaller than the number of channels in the image (" + image.getNumChannels() + ")."); } int dim = image.getMaxSample(channelIndex) + 1; if (matrix == null) { throw new IllegalArgumentException("The matrix must non-null."); } if (matrix.getDimension() != dim) { throw new IllegalArgumentException("Dimension of matrix (" + matrix.getDimension() + " must be exactly one larger than " + "maximum sample value (" + (dim - 1) + ")."); } matrix.clear(); int maxX = image.getWidth() - 1; int maxY = image.getHeight() - 1; for (int y = 0; y <= maxY; y++) { for (int x = 0; x <= maxX; x++) { int index = image.getSample(channelIndex, x, y); if (x > 0) { int leftNeighbor = image.getSample(channelIndex, x - 1, y); matrix.incValue(index, leftNeighbor); } if (x < maxX) { int rightNeighbor = image.getSample(channelIndex, x + 1, y); matrix.incValue(index, rightNeighbor); } if (y > 0) { int topNeighbor = image.getSample(channelIndex, x, y - 1); matrix.incValue(index, topNeighbor); } if (y < maxY) { int bottomNeighbor = image.getSample(channelIndex, x, y + 1); matrix.incValue(index, bottomNeighbor); } } } } /** * Creates a new co-occurrence frequency with the same dimension as the argument co-occurrence * matrix, calls {@link #initCoOccurrenceFrequencyMatrix} with them to initialize the new matrix, * then returns it. * A {@link MemoryCoOccurrenceFrequencyMatrix} is created. * @param A the co-occurrence matrix from which the resulting matrix will be initialized * @return the newly-created co-occurrence frequency matrix * @throws IllegalArgumentException if the argument matrix is null */ public static CoOccurrenceFrequencyMatrix createCoOccurrenceFrequencyMatrix(final CoOccurrenceMatrix A) { if (A == null) { throw new IllegalArgumentException("Matrix argument must be non-null."); } int dimension = A.getDimension(); MemoryCoOccurrenceFrequencyMatrix matrix = new MemoryCoOccurrenceFrequencyMatrix(dimension); initCoOccurrenceFrequencyMatrix(A, matrix); return matrix; } /** * Initializes a co-occurrence frequency matrix from a co-occurrence matrix. * The two argument matrices must be non-null and have the same dimension. * @param A co-occurrence matrix used as input * @param cofm co-occurrence matrix, will be initialized by this method * @throws IllegalArgumentException if either matrix is null or if the dimensions are not equal */ public static void initCoOccurrenceFrequencyMatrix(final CoOccurrenceMatrix A, CoOccurrenceFrequencyMatrix cofm) { if (A == null) { throw new IllegalArgumentException("Co-occurrence matrix A argument must not be null."); } if (cofm == null) { throw new IllegalArgumentException("Co-occurrence frequency matrix cofm argument must not be null."); } final int DIMENSION = A.getDimension(); if (DIMENSION != cofm.getDimension()) { throw new IllegalArgumentException("Dimension of matrices A (" + DIMENSION + ") and cofm (" + cofm.getDimension() + ") must " + "be equal."); } cofm.clear(); double totalSum = 0.0; for (int i = 0; i < DIMENSION; i++) { // first sum up A[i, k], k = 0..dimension-1 double sum = 0.0; for (int k = 0; k < DIMENSION; k++) { sum += A.getValue(i, k); } totalSum += sum; for (int j = 0; j < DIMENSION; j++) { double value = A.getValue(i, j); double result; if (sum == 0.0) { result = 0.0; } else { result = value / sum; } cofm.setValue(i, j, result); } } cofm.computeStatistics(); } } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/analysis/Histogram3DCreator.java 0000664 0000000 0000000 00000011754 10546523562 027316 0 ustar /* * Histogram3DCreator * * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.color.analysis; import net.sourceforge.jiu.color.data.Histogram3D; import net.sourceforge.jiu.color.data.NaiveHistogram3D; import net.sourceforge.jiu.color.data.OnDemandHistogram3D; import net.sourceforge.jiu.data.IntegerImage; import net.sourceforge.jiu.data.RGBIntegerImage; import net.sourceforge.jiu.ops.Operation; import net.sourceforge.jiu.ops.MissingParameterException; import net.sourceforge.jiu.ops.WrongParameterException; /** * This class creates three-dimensional histograms for images with integer samples. * Only {@link net.sourceforge.jiu.data.IntegerImage} is supported. * Existing histogram objects can be given to this operation to be reused. *
* Note: Before JIU 0.10.0 there was a single HistogramCreator class. * @author Marco Schmidt * @since 0.10.0 */ public class Histogram3DCreator extends Operation { private Histogram3D hist; private IntegerImage image; private int index1; private int index2; private int index3; private boolean naive; /** * Static convenience method to count the number of colors in * any three channel {@link IntegerImage} object. * @param image the IntegerImage whose number of used colors is to be determined * @return the number of colors or null on failure (image does not have three * channels, etc.) * @since 0.15.0 */ public static Integer count(IntegerImage image) { if (image.getNumChannels() == 3) { try { Histogram3DCreator hc = new Histogram3DCreator(); hc.setImage((RGBIntegerImage)image); hc.process(); Histogram3D hist = hc.getHistogram(); return new Integer(hist.getNumUsedEntries()); } catch (Exception e) { return null; } } else { return null; } } private void createHistogramIfNecessary() { if (hist == null) { if (naive) { hist = new NaiveHistogram3D(image.getMaxSample(index1) + 1, image.getMaxSample(index2) + 1, image.getMaxSample(index3) + 1); } else { hist = new OnDemandHistogram3D(image.getMaxSample(index1) + 1, image.getMaxSample(index2) + 1, image.getMaxSample(index3) + 1); } } } /** * Returns the histogram initialized in this operation. */ public Histogram3D getHistogram() { return hist; } public void process() throws MissingParameterException, WrongParameterException { if (image == null) { throw new MissingParameterException("Image parameter missing."); } createHistogramIfNecessary(); if (hist.getMaxValue(0) < image.getMaxSample(index1) || hist.getMaxValue(1) < image.getMaxSample(index2) || hist.getMaxValue(2) < image.getMaxSample(index3)) { throw new WrongParameterException("Histogram is not large enough for image (hist max value / image max samples)."); } hist.clear(); final int WIDTH = image.getWidth(); final int HEIGHT = image.getHeight(); for (int y = 0; y < HEIGHT; y++) { for (int x = 0; x < WIDTH; x++) { hist.increaseEntry( image.getSample(index1, x, y), image.getSample(index2, x, y), image.getSample(index3, x, y)); } setProgress(y, HEIGHT); } } /** * Sets the histogram object to be reused for this operation. * If this method is not called, a new histogram will be created. * @param histogram the histogram object to be used in this operation */ public void setHistogram3D(Histogram3D histogram) { hist = histogram; } /** * The image for which a histogram will be initialized. * Simply calls {@link #setImage(IntegerImage, int, int, int)} * with 0, 1 and 2 as parameters. * @param newImage the image for the histogram initialization */ public void setImage(IntegerImage newImage) { setImage(newImage, 0, 1, 2); } /** * The image for which a histogram will be initialized. * Simply calls {@link #setImage(IntegerImage, int, int, int)} * with 0, 1 and 2 as parameters. * @param newImage */ public void setImage(IntegerImage newImage, int channelIndex1, int channelIndex2, int channelIndex3) { if (newImage == null) { throw new IllegalArgumentException("Image argument must not be null."); } if (channelIndex1 < 0 || channelIndex1 >= newImage.getNumChannels() || channelIndex2 < 0 || channelIndex2 >= newImage.getNumChannels() || channelIndex3 < 0 || channelIndex3 >= newImage.getNumChannels()) { throw new IllegalArgumentException("The three index arguments must be >= 0 and < the number of channels."); } if (channelIndex1 == channelIndex2 || channelIndex2 == channelIndex3 || channelIndex1 == channelIndex3) { throw new IllegalArgumentException("The three index arguments must be different from each other."); } image = newImage; index1 = channelIndex1; index2 = channelIndex2; index3 = channelIndex3; } } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/analysis/Histogram1DCreator.java 0000664 0000000 0000000 00000013010 10546742235 027277 0 ustar /* * Histogram1DCreator * * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.color.analysis; import net.sourceforge.jiu.color.data.ArrayHistogram1D; import net.sourceforge.jiu.color.data.Histogram1D; import net.sourceforge.jiu.data.IntegerImage; import net.sourceforge.jiu.data.RGBIntegerImage; import net.sourceforge.jiu.ops.Operation; import net.sourceforge.jiu.ops.MissingParameterException; import net.sourceforge.jiu.ops.WrongParameterException; /** * This class creates one-dimensional histograms for images with integer samples. * Only {@link net.sourceforge.jiu.data.IntegerImage} objects are supported. *
* Existing histogram objects can be given to this operation to be reused. * Give an existing {@link net.sourceforge.jiu.color.data.Histogram1D} object to this operation via * {@link #setHistogram(Histogram1D)}. *
* The histogram can be created for any channel of an IntegerImage. * The first channel (index 0) is the default channel. * Use {@link #setImage(IntegerImage, int)} to specify another one. *
* Note: Before JIU 0.10.0 there was a single HistogramCreator class. *
* Histogram1DCreator hc = new Histogram1DCreator(); * hc.setImage(image, 2); * hc.process(); * Histogram1D hist = hc.getHistogram(); ** If you just want to learn the number of different samples in an image, * there's a static convenience method count for that. Again, we use the * third channel: *
Integer numUsedSamples = Histogram1DCreator.count(image, 2);* @author Marco Schmidt * @since 0.10.0 */ public class Histogram1DCreator extends Operation { private Histogram1D hist; private int channelIndex; private IntegerImage image; /** * Static convenience method to count the number of different samples * in the first channel of the argument image. * @param image the IntegerImage to be examined * @return the number of different values or null on failure * (image is
null
, histogram data structure could not
* be allocated)
* @since 0.15.0
*/
public static Integer count(IntegerImage image)
{
return count(image, 0);
}
/**
* Static convenience method to count the number of different samples
* in one of the channels of the argument image.
* @param image the IntegerImage to be examined
* @param channelIndex the zero-based index of the channel to use
* @return the number of different values or null on failure
* (image is null
, channel index is invalid,
* histogram data structure could not be allocated)
* @since 0.15.0
*/
public static Integer count(IntegerImage image, int channelIndex)
{
if (image != null && channelIndex >= 0 && channelIndex < image.getNumChannels())
{
try
{
Histogram1DCreator hc = new Histogram1DCreator();
hc.setImage((RGBIntegerImage)image);
hc.process();
Histogram1D hist = hc.getHistogram();
return new Integer(hist.getNumUsedEntries());
}
catch (Exception e)
{
return null;
}
}
else
{
return null;
}
}
private void createHistogramIfNecessary()
{
if (hist == null)
{
hist = new ArrayHistogram1D(image.getMaxSample(0) + 1);
}
}
/**
* Returns the histogram used in this operation.
* @return histogram object, newly-created or reused one
* @see #setHistogram
*/
public Histogram1D getHistogram()
{
return hist;
}
public void process() throws
MissingParameterException,
WrongParameterException
{
if (image == null)
{
throw new MissingParameterException("Image parameter missing.");
}
createHistogramIfNecessary();
if (hist.getMaxValue() < image.getMaxSample(channelIndex))
{
throw new WrongParameterException("Histogram does not have enough entries.");
}
hist.clear();
final int WIDTH = image.getWidth();
final int HEIGHT = image.getHeight();
for (int y = 0; y < HEIGHT; y++)
{
for (int x = 0; x < WIDTH; x++)
{
hist.increaseEntry(image.getSample(channelIndex, x, y));
}
setProgress(y, HEIGHT);
}
}
/**
* Sets a histogram object to be used for this operation.
* Within {@link #process} it will be checked if this histogram is large enough
* for the image.
* @see #getHistogram
*/
public void setHistogram(Histogram1D histogram)
{
hist = histogram;
}
/**
* Set the image for which the histogram is to be initialized.
* The first channel (index 0) is used by default.
* @param newImage image object to be used
* @see #setImage(IntegerImage, int)
*/
public void setImage(IntegerImage newImage)
{
setImage(newImage, 0);
}
/**
* Set the image and the channel index for which the histogram is to be initialized.
* @param newImage image object to be used
* @param imageChannelIndex must not be negative and must be smaller than newImage.getNumChannels()
* @see #setImage(IntegerImage)
*/
public void setImage(IntegerImage newImage, int imageChannelIndex)
{
if (newImage == null)
{
throw new IllegalArgumentException("Image argument must be non-null.");
}
if (imageChannelIndex < 0 || imageChannelIndex >= newImage.getNumChannels())
{
throw new IllegalArgumentException("Invalid channel for given image.");
}
image = newImage;
channelIndex = imageChannelIndex;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/YCbCrIndex.java 0000664 0000000 0000000 00000001546 07741250131 023747 0 ustar /*
* YCbCrIndex
*
* Copyright (c) 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.color;
/**
* This interface simply provides three integer constants as index
* values for the three channels of an YCbCr image: gray,
* blue chrominance and red chrominance.
* The three values are guaranteed to lie in the interval 0 to 2.
* Furthermore, all three values are different from each other, so
* that the complete interval from 0 to 2 is used.
* @see net.sourceforge.jiu.data.RGBIndex
* @author Marco Schmidt
*/
public interface YCbCrIndex
{
/**
* Index value for the luminance (gray) component.
*/
int INDEX_Y = 0;
/**
* Index value for the blue chrominance component.
*/
int INDEX_CB = 1;
/**
* Index value for the red chrominance component.
*/
int INDEX_CR = 2;
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/package.html 0000664 0000000 0000000 00000000370 07741250131 023425 0 ustar
Contains color-related operations that did not fit into one of the subpackages. java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/data/ 0000775 0000000 0000000 00000000000 10546757500 022066 5 ustar java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/data/OnDemandHistogram3D.java 0000664 0000000 0000000 00000010601 10546764333 026463 0 ustar /* * OnDemandHistogram3D * * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Marco Schmidt * All rights reserved. */ package net.sourceforge.jiu.color.data; import java.util.Hashtable; import net.sourceforge.jiu.color.data.Histogram3D; /** * Internal data class for the on demand histogram. Stores * one triplet of int values plus an int counter. * Implements {@link java.lang.Object#hashCode()} and * {@link java.lang.Object#equals(java.lang.Object)} to * be used with a hash table. * * @author Marco Schmidt */ final class Histogram3DNode { private final int sample1; private final int sample2; private final int sample3; private int counter; public Histogram3DNode(int s1, int s2, int s3) { sample1 = s1; sample2 = s2; sample3 = s3; } public boolean equals(Object obj) { Histogram3DNode node = (Histogram3DNode)obj; return sample1 == node.sample1 && sample2 == node.sample2 && sample3 == node.sample3; } public int getCounter() { return counter; } public int getSample1() { return sample1; } public int getSample2() { return sample2; } public int getSample3() { return sample3; } public int hashCode() { return sample1 + sample2 + sample3; } public void increase() { setCounter(getCounter() + 1); } public void setCounter(int newValue) { counter = newValue; } } /** * A data class for a three-dimensional histogram, creating counters on demand only, * not allocating counters for all possible entries at the beginning. * The creation on demand happens to save space. *
* Note:
* Rewrote from scratch for version 0.15.0 to use hash tables
* instead of int arrays. New version creates and
* throws away a lot of objects, which had been a problem
* with early JVMs but should be OK these days.
*
* @author Marco Schmidt
*/
public class OnDemandHistogram3D implements Histogram3D
{
private Hashtable hash;
private int numUniqueValues;
private final int maxValue1;
private final int maxValue2;
private final int maxValue3;
/**
* Creates a new histogram, internally creates the hash table
* for triplet values.
*/
public OnDemandHistogram3D(int max1, int max2, int max3)
{
if (max1 < 1 || max2 < 1 || max3 < 1)
{
throw new IllegalArgumentException("All max arguments must be 1 or larger.");
}
maxValue1 = max1;
maxValue2 = max2;
maxValue3 = max3;
clear();
}
public void clear()
{
if (hash == null)
{
hash = new Hashtable();
}
else
{
hash.clear();
}
numUniqueValues = 0;
}
private Histogram3DNode createNode(int v1, int v2, int v3)
{
if (v1 >= 0 && v2 >= 0 && v3 >= 0 &&
v1 <= maxValue1 && v2 <= maxValue2 && v3 <= maxValue3)
{
return new Histogram3DNode(v1, v2, v3);
}
else
{
throw new IllegalArgumentException("At least one of the arguments was not in its valid 0..max range.");
}
}
public int getEntry(int index1, int index2, int index3)
{
Histogram3DNode searchNode = createNode(index1, index2, index3);
Histogram3DNode counter = (Histogram3DNode)hash.get(searchNode);
if (counter == null)
{
return 0;
}
else
{
return counter.getCounter();
}
}
public int getMaxValue(int index) throws IllegalArgumentException
{
switch(index)
{
case(0): return maxValue1;
case(1): return maxValue2;
case(2): return maxValue3;
default: throw new IllegalArgumentException("Not a valid index, must be from 0 to 2: " + index);
}
}
public int getNumUsedEntries()
{
return numUniqueValues;
}
public void increaseEntry(int index1, int index2, int index3)
{
Histogram3DNode searchNode = createNode(index1, index2, index3);
Histogram3DNode counter = (Histogram3DNode)hash.get(searchNode);
if (counter == null)
{
searchNode.setCounter(1);
hash.put(searchNode, searchNode);
numUniqueValues++;
}
else
{
counter.increase();
}
}
public void setEntry(int index1, int index2, int index3, int newValue)
{
Histogram3DNode searchNode = createNode(index1, index2, index3);
Histogram3DNode counter = (Histogram3DNode)hash.get(searchNode);
if (counter == null)
{
searchNode.setCounter(newValue);
hash.put(searchNode, searchNode);
numUniqueValues++;
}
else
{
counter.setCounter(newValue);
}
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/data/NaiveHistogram3D.java 0000664 0000000 0000000 00000013272 10541050241 026024 0 ustar /*
* NaiveHistogram3D
*
* Copyright (c) 2001, 2002, 2003, 2004, 2005 Marco Schmidt
* All rights reserved.
*/
package net.sourceforge.jiu.color.data;
import net.sourceforge.jiu.color.data.Histogram3D;
/**
* A class for a three-dimensional histogram that allocates one int
value
* per counter at construction time.
* This means that a histogram with 8 bits for each channel will have
* 28 + 8 + 8 = 224 = 16,777,216 int values,
* making it 64 MB large.
*
* @author Marco Schmidt
*/
public class NaiveHistogram3D implements
Histogram3D
{
private int[][][] data;
private int[] values;
/**
* Creates a histogram
*/
public NaiveHistogram3D(int numValuesLevel1, int numValuesLevel2, int numValuesLevel3) throws
IllegalArgumentException,
OutOfMemoryError
{
if (numValuesLevel1 < 1)
{
throw new IllegalArgumentException("The number of values for " +
"level 1 must be at least 1; got " + numValuesLevel1);
}
if (numValuesLevel2 < 1)
{
throw new IllegalArgumentException("The number of values for " +
"level 2 must be at least 1; got " + numValuesLevel2);
}
if (numValuesLevel3 < 1)
{
throw new IllegalArgumentException("The number of values for " +
"level 3 must be at least 1; got " + numValuesLevel3);
}
values = new int[3];
values[0] = numValuesLevel1;
values[1] = numValuesLevel2;
values[2] = numValuesLevel3;
data = new int[values[0]][][];
for (int i1 = 0; i1 < values[0]; i1++)
{
data[i1] = new int[values[1]][];
for (int i2 = 0; i2 < values[1]; i1++)
{
data[i1][i2] = new int[values[2]];
}
}
clear();
}
/**
* Creates a histogram with the same number of values for all three dimensions.
* Calls {@link NaiveHistogram3D (int, int, int)}, repeating numValues
* three times.
* @param numValues the number of levels for all three dimensions
*/
public NaiveHistogram3D(int numValues) throws IllegalArgumentException, OutOfMemoryError
{
this(numValues, numValues, numValues);
}
/**
* Sets all counters to zero.
*/
public void clear()
{
for (int i1 = 0; i1 < values[0]; i1++)
for (int i2 = 0; i2 < values[1]; i2++)
for (int i3 = 0; i3 < values[2]; i3++)
data[i1][i2][i3] = 0;
}
/**
* Returns the counter value of (index1, index2, index3).
* @param index1 first of the three values forming the threedimensional index
* @param index2 second of the three values forming the threedimensional index
* @param index3 three of the three values forming the threedimensional index
* @return the counter value of the desired index
* @throws IllegalArgumentException could be (read: need not necessarily) be
* thrown if the index formed by the arguments is invalid
*/
public int getEntry(int index1, int index2, int index3) throws
IllegalArgumentException
{
try
{
return data[index1][index2][index3];
}
catch (ArrayIndexOutOfBoundsException aioobe)
{
throw new IllegalArgumentException("Not a valid index (" + index1 +
", " + index2 + ", " + index3 + ")");
}
}
public int getMaxValue(int index) throws
IllegalArgumentException
{
if (index >= 0 && index <= 2)
{
return values[index] - 1;
}
else
{
throw new IllegalArgumentException("The index argument must be " +
"from 0 to 2; got " + index);
}
}
/**
* Returns the number of used entries (those entries with
* a counter value larger than zero).
* @return number of non-zero counter values
*/
public int getNumUsedEntries()
{
int result = 0;
for (int i1 = 0; i1 < values[0]; i1++)
for (int i2 = 0; i2 < values[1]; i2++)
for (int i3 = 0; i3 < values[2]; i3++)
if (data[i1][i2][i3] > 0)
result++;
return result;
}
/**
* Increases the counter value of (index1, index2, index3) by one.
* This method can easily be implemented by the one-liner
* setEntry(index1, index2, index3, getEntry(index1, index2, index3) + 1);
* However, this method is expected to be faster in some contexts.
*
* @param index1 first of the three values forming the threedimensional index
* @param index2 second of the three values forming the threedimensional index
* @param index3 three of the three values forming the threedimensional index
* @throws IllegalArgumentException could be (read: need not necessarily) be
* thrown if the index formed by the arguments is invalid
*/
public void increaseEntry(int index1, int index2, int index3) throws IllegalArgumentException
{
try
{
data[index1][index2][index3]++;
}
catch (ArrayIndexOutOfBoundsException aioobe)
{
throw new IllegalArgumentException("Not a valid index (" + index1 +
", " + index2 + ", " + index3 + ")");
}
}
/**
* Sets the counter value of (index1, index2, index3) to newValue.
*
* @param index1 first of the three values forming the threedimensional index
* @param index2 second of the three values forming the threedimensional index
* @param index3 three of the three values forming the threedimensional index
* @param newValue the counter value that is assigned to the argument index
* @throws IllegalArgumentException could be (read: need not necessarily) be
* thrown if the index formed by the first three arguments is invalid
*/
public void setEntry(int index1, int index2, int index3, int newValue) throws IllegalArgumentException
{
try
{
data[index1][index2][index3] = newValue;
}
catch (ArrayIndexOutOfBoundsException aioobe)
{
throw new IllegalArgumentException("Not a valid index (" + index1 +
", " + index2 + ", " + index3 + ")");
}
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/data/CoOccurrenceMatrix.java 0000664 0000000 0000000 00000003232 07741250132 026460 0 ustar /*
* CoOccurrenceMatrix
*
* Copyright (c) 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.color.data;
/**
* An interface for co-occurrence matrices.
* An implementing class stores int
counter values for pairs of pixels.
* These counters represent the number of times two pixels are direct
* neighbors in an image.
* @author Marco Schmidt
*/
public interface CoOccurrenceMatrix
{
/**
* Sets all counters to zero.
*/
void clear();
/**
* Returns the dimension of this matrix.
* This is the number of rows and columns.
* @return matrix dimension (larger than zero)
*/
int getDimension();
/**
* Returns the matrix value at a given position.
* @param i column index, from 0 to {@link #getDimension} - 1
* @param j row index, from 0 to {@link #getDimension} - 1
* @throws IllegalArgumentException for invalid index pairs (i, j)
*/
int getValue(int i, int j);
/**
* Increases the counter for pair (i, j) by one.
* This method can be implemented by the call
* setValue(i, j, getValue(i, j) + 1);
.
* @param i column index, from 0 to {@link #getDimension} - 1
* @param j row index, from 0 to {@link #getDimension} - 1
* @throws IllegalArgumentException for invalid index pairs (i, j)
*/
void incValue(int i, int j);
/**
* Sets the counter for pair (i, j) to a new value.
* @param i column index, from 0 to {@link #getDimension} - 1
* @param j row index, from 0 to {@link #getDimension} - 1
* @throws IllegalArgumentException for invalid index pairs (i, j)
*/
void setValue(int i, int j, int newValue);
}
././@LongLink 0000000 0000000 0000000 00000000153 00000000000 011564 L ustar root root java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/data/MemoryCoOccurrenceFrequencyMatrix.java java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/data/MemoryCoOccurrenceFrequencyMatri0000664 0000000 0000000 00000005762 07741250132 030435 0 ustar /*
* MemoryCoOccurrenceFrequencyMatrix
*
* Copyright (c) 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.color.data;
import net.sourceforge.jiu.color.data.BaseCoOccurrenceFrequencyMatrix;
/**
* Implements the {@link CoOccurrenceFrequencyMatrix} interface by using a large array
* of values in memory.
* @author Marco Schmidt
*/
public class MemoryCoOccurrenceFrequencyMatrix extends BaseCoOccurrenceFrequencyMatrix
{
/** will be initialized in constructor and never changed */
private final int dimension;
/** total number of values, equals dimension * dimension and data.length */
private int numValues;
/** co occurrence frequency values */
private double[] data;
/**
* Creates a co-occurrence frequency matrix of given dimension;
* allocates dimension times dimension double values for
* internal array;
* does not call clear() to set everything to zero, must be
* done by user (or automatically in init).
* Dimension should be number of colors in palette.
* @throws IllegalArgumentException if dimension is smaller than 1
*/
public MemoryCoOccurrenceFrequencyMatrix(int dimension)
{
if (dimension < 1)
{
throw new IllegalArgumentException("Dimension of co-occurrence frequency matrix must be >= 1.");
}
this.dimension = dimension;
this.numValues = dimension * dimension;
data = new double[numValues];
}
/**
* Sets all values of this matrix to zero.
*/
public void clear()
{
if (data == null)
{
return;
}
for (int i = 0; i < numValues; i++)
{
data[i] = 0.0;
}
}
public int getDimension()
{
return dimension;
}
/**
* Returns the value of this matrix at row i, column i.
* Argument is zero-based, so make sure that
* 0 <= i < getDimension().
* Other values will raise an IllegalArgumentException.
* Simply calls getValue(i, i).
*/
public double getValue(int i) throws IllegalArgumentException
{
return getValue(i, i);
}
/**
* Returns the value of this matrix at row j, column i.
* Both arguments are zero-based, so make sure that
* 0 <= i, j < getDimension().
* Other values will raise an IllegalArgumentException.
*/
public double getValue(int i, int j) throws IllegalArgumentException
{
if (i < 0 || i >= dimension || j < 0 || j >= dimension)
{
throw new IllegalArgumentException(
"i/j arguments out of bounds: " + i + "/" + j);
}
return data[j * dimension + i];
}
/**
* Sets value at row j, column i to newValue.
* Both arguments are zero-based, so make sure that
* 0 <= i, j < getDimension().
* Other values will raise an IllegalArgumentException.
*/
public void setValue(int i, int j, double newValue)
throws IllegalArgumentException
{
if (i < 0 || i >= dimension || j < 0 || j >= dimension)
{
throw new IllegalArgumentException("i/j coordinate out of bounds: " + i + "/" + j);
}
data[j * dimension + i] = newValue;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/data/MemoryCoOccurrenceMatrix.java 0000664 0000000 0000000 00000005242 10611674432 027657 0 ustar /*
* MemoryCoOccurrenceMatrix
*
* Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.color.data;
import net.sourceforge.jiu.color.data.CoOccurrenceMatrix;
/**
* This class stores a co-occurrence matrix, a two-dimensional array of int counters.
* The dimension is given to the constructor which allocates a corresponding array.
*
Provides classes to store images and data directly related to them.
The base interface for image data in JIU is {@link net.sourceforge.jiu.data.PixelImage}. The concept of a pixel image includes the following properties:
The interface {@link net.sourceforge.jiu.data.IntegerImage} extends the
{@link net.sourceforge.jiu.data.PixelImage} interface.
All sample values belonging to an object of a class implementing IntegerImage
are supposed to be integer values that can be stored in an int
value (a signed 32 bit value).
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/data/ArrayHistogram1D.java 0000664 0000000 0000000 00000004262 10324333124 026040 0 ustar /* * ArrayHistogram1D * * Copyright (c) 2001, 2002, 2003, 2004, 2005 Marco Schmidt * All rights reserved. */ package net.sourceforge.jiu.color.data; import net.sourceforge.jiu.color.data.Histogram1D; /** * A one-dimensional histogram data class that stores its counters in memory. * Counters are stored in an
int
array of length
* {@link #getMaxValue()} + 1
so that k
* values will require k * 4
bytes.
* @author Marco Schmidt
*/
public class ArrayHistogram1D implements Histogram1D
{
private int[] data;
/**
* Creates a histogram with the argument's number of values, from
* 0
to numValues - 1
.
*
* @param numValues the number of counters in the histogram; must be one or larger
* @throws IllegalArgumentException if the argument is smaller than one
*/
public ArrayHistogram1D(int numValues)
{
if (numValues < 1)
{
throw new IllegalArgumentException("Must have at least one entry; numValues=" + numValues);
}
data = new int[numValues];
}
public void clear()
{
// OPTIMIZE
// we could use java.util.Arrays.fill, but that would require Java 1.2+:
// Arrays.fill(data, 0);
for (int i = 0; i < data.length; i++)
{
data[i] = 0;
}
}
public int getEntry(int index)
{
try
{
return data[index];
}
catch (ArrayIndexOutOfBoundsException aioobe)
{
throw new IllegalArgumentException("Not a valid index: " + index);
}
}
public int getMaxValue()
{
return data.length - 1;
}
public int getNumUsedEntries()
{
int result = 0;
for (int i = 0; i < data.length; i++)
{
if (data[i] > 0)
{
result++;
}
}
return result;
}
public void increaseEntry(int index)
{
try
{
data[index]++;
}
catch (ArrayIndexOutOfBoundsException aioobe)
{
throw new IllegalArgumentException("Not a valid index: " + index);
}
}
public void setEntry(int index, int newValue)
{
try
{
data[index] = newValue;
}
catch (ArrayIndexOutOfBoundsException aioobe)
{
throw new IllegalArgumentException("Not a valid index: " + index);
}
}
}
././@LongLink 0000000 0000000 0000000 00000000151 00000000000 011562 L ustar root root java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/data/BaseCoOccurrenceFrequencyMatrix.java java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/data/BaseCoOccurrenceFrequencyMatrix.0000664 0000000 0000000 00000011705 10377273422 030305 0 ustar /*
* BaseCoOccurrenceFrequencyMatrix
*
* Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.color.data;
/**
* This abstract class encapsulates all data of a co-occurrence
* frequency matrix except for the frequency values.
* The method computeStatistics is implemented.
* Any class extending this class only has to
* deal with storing the frequency values ({@link MemoryCoOccurrenceFrequencyMatrix}
* does this by using a one-dimensional array internally).
* @author Marco Schmidt
*/
public abstract class BaseCoOccurrenceFrequencyMatrix implements CoOccurrenceFrequencyMatrix
{
/** co-occurrence frequency mean $\mu_{C(j)}$ */
private double[] cofMean;
/** co-occurrence frequency standard deviation $\sigma_{C(j)}$ */
private double[] cofStddev;
/** self co-occurrence frequency mean $\mu_S$ */
private double scofMean;
/** self co-occurrence frequency standard deviation $\sigma_S$ */
private double scofStddev;
/** equals scofMean + scofStddev */
private double scofSum;
private void computeCoOccurrenceFrequencyMeanValues()
{
cofMean = new double[getDimension()];
for (int j = 0; j < getDimension(); j++)
{
double result = 0.0;
for (int i = 0; i < getDimension(); i++)
{
result += getValue(i, j);
}
cofMean[j] = result / ((double)getDimension());
}
//System.out.println("DEBUG: done computing cofm mean values");
}
private void computeCoOccurrenceFrequencyStandardDeviationValues()
{
cofStddev = new double[getDimension()];
for (int j = 0; j < getDimension(); j++)
{
double result = 0.0;
for (int i = 0; i < getDimension(); i++)
{
double value = getValue(i, j) - cofMean[j];
result += (value * value);
}
cofStddev[j] = Math.sqrt(result);
}
//System.out.println("DEBUG: done computing cofm stddev values");
}
private void computeSelfCoOccurrenceFrequencyMeanValue()
{
double sum = 0.0;
for (int i = 0; i < getDimension(); i++)
{
sum += getValue(i, i);
}
scofMean = sum / (getDimension());
//System.out.println("DEBUG: scof mean=" + scofMean);
}
private void computeSelfCoOccurrenceFrequencyStandardDeviationValue()
{
double result = 0.0;
for (int i = 0; i < getDimension(); i++)
{
double value = getValue(i, i) - getScofMean();
result += (value * value);
}
scofStddev = Math.sqrt(result);
//System.out.println("DEBUG: scof stddev=" + scofStddev);
}
/**
* Assumes that the co-occurrence frequency values have been initialized.
* Computes mean and standard deviation for co-occurrence and self co-occurrence
* frequency values.
*/
public void computeStatistics()
{
// we must keep this order because stddev needs mean!
computeSelfCoOccurrenceFrequencyMeanValue();
computeSelfCoOccurrenceFrequencyStandardDeviationValue();
scofSum = getScofMean() + getScofStddev();
//System.out.println("DEBUG: scof sum=" + scofSum);
computeCoOccurrenceFrequencyMeanValues();
computeCoOccurrenceFrequencyStandardDeviationValues();
}
/**
* Prints co-occurrence frequency values to standard output, one line
* per matrix row j.
* Calls getValue(i, j) with each column i for each row j.
*/
/*private void dump()
{
for (int j = 0; j < getDimension(); j++)
{
for (int i = 0; i < getDimension(); i++)
{
System.out.print(getValue(i, j) + " ");
}
System.out.println("");
}
}*/
/**
* Prints self co-occurrence frequency values to standard output, eight
* values per row.
* Calls getValue(i, i) with each value i from 0 to getDimension() - 1.
*/
/* private void dumpScofValues()
{
for (int j = 0; j < getDimension(); j++)
{
System.out.print(getValue(j) + " ");
if (j % 8 == 0 && j > 0)
{
System.out.println("");
}
}
System.out.println("");
}*/
/**
* Returns the mean of the co-occurrence frequency values.
*/
public double getMean(int index)
{
return cofMean[index];
}
public double getStddev(int index)
{
return cofStddev[index];
}
/**
* Returns the mean of all self co-occurrence frequency values.
* This value is called $\mu_S$ in Shufelt's paper.
* This value is determined once within computeStatistics().
*/
public double getScofMean()
{
return scofMean;
}
/**
* Returns the standard deviation of all self co-occurrence frequency
* values.
* This value is called $\sigma_S$ in Shufelt's paper.
* This value is determined once within a call to computeStatistics().
*/
public double getScofStddev()
{
return scofStddev;
}
/**
* Return the sum of mean and standard deviation of the self
* co-occurrence frequency values.
* Assumes that {@link #computeStatistics} has been called already.
* @return sum of mean and standard deviation of the self co-occurrence
* frequency values
*/
public double getScofSum()
{
return scofSum;
}
}
././@LongLink 0000000 0000000 0000000 00000000145 00000000000 011565 L ustar root root java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/data/CoOccurrenceFrequencyMatrix.java java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/data/CoOccurrenceFrequencyMatrix.java0000664 0000000 0000000 00000004242 07741250132 030344 0 ustar /*
* CoOccurrenceFrequencyMatrix
*
* Copyright (c) 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.color.data;
/**
* An interface for a co-occurrence frequency matrix.
* Also provides access to some statistical data.
* This class is not a pure data type for it also demands a method {@link #computeStatistics}
* which takes the matrix coefficients and computes mean, standard deviation and
* other properties from it.
* @author Marco Schmidt
*/
public interface CoOccurrenceFrequencyMatrix
{
/**
* Sets all frequency values in this matrix to 0.0
.
*/
void clear();
/**
* Computes mean, standard deviation and the sum of those two
* so that these values can be queried by the appropriate
* get methods.
*/
void computeStatistics();
/**
* Returns the sum of mean and standard deviation for all pairs (index, x), with x running from 0 to getDimension() - 1.
* The result is equal to {@link #getMean} + {@link #getStddev}
*/
double getScofMean();
/**
* Returns the mean for all pairs (index, i), with i running from 0 to {@link #getDimension()} - 1.
*/
double getMean(int index);
/**
* Returns the standard deviation of the values getValue(index, i)
* with i running from 0 to {@link #getDimension()} - 1.
* @param index first argument to all calls of getValue used to determine the standard deviation
*/
double getStddev(int index);
/**
* Returns the standard deviation for all pairs (i, i), with i running from 0 to getDimension() - 1.
* @return standard deviation for pairs
*/
double getScofStddev();
double getScofSum();
/**
* Returns the dimension of this matrix.
*/
int getDimension();
/**
* Returns the value for the self co-occurrence frequency of i (i being from
* 0 to {@link #getDimension()} - 1).
* The result is the same as a call to getValue(i, i)
.
* @param i index into the matrix, must be larger than or equal to 0 and smaller than {@link #getDimension()}
*/
double getValue(int i);
double getValue(int i, int j);
void setValue(int i, int j, double newValue);
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/data/Histogram1D.java 0000664 0000000 0000000 00000002770 10541050173 025044 0 ustar /*
* Histogram1D
*
* Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.color.data;
/**
* An interface for a one-dimensional histogram.
*
* @author Marco Schmidt
* @see Histogram3D
*/
public interface Histogram1D
{
/**
* Sets all counters to zero.
*/
void clear();
/**
* Returns the counter value for the given index.
* @param index the zero-based index of the desired counter value
* @return the counter value
* @throws IllegalArgumentException if the argument is not a valid index
*/
int getEntry(int index);
/**
* Returns the maximum allowed index.
* The minimum is always 0.
* @return the maximum index value
*/
int getMaxValue();
/**
* Returns the number of used entries (those entries with
* a counter value larger than zero).
* @return number of non-zero counter values
*/
int getNumUsedEntries();
/**
* Increases the counter value of the given index by one.
* Same semantics as
* setEntry(index, getEntry(index) + 1);
* @param index index into the histogram
* @throws IllegalArgumentException if the argument index is invalid
*/
void increaseEntry(int index);
/**
* Sets one counter to a new value.
* @param index index of the counter to be changed
* @param newValue new value for that counter
* @throws IllegalArgumentException if the index is invalid
*/
void setEntry(int index, int newValue);
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/data/Histogram3D.java 0000664 0000000 0000000 00000005427 10546764741 025072 0 ustar /*
* Histogram3D
*
* Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Marco Schmidt
* All rights reserved.
*/
package net.sourceforge.jiu.color.data;
/**
* An interface for classes that store three-dimensional histograms.
* Histograms count the occurrence of values, so a three-dimensional
* histogram has counters for three-dimensional values.
* The 3D histograms are used (as an example) to count the occurrence of
* each color in an RGB image.
*
* @author Marco Schmidt
* @see Histogram1D
*/
public interface Histogram3D
{
/**
* Sets all counters to zero.
*/
void clear();
/**
* Returns the counter value of (index1, index2, index3).
* @param index1 first of the three values forming the threedimensional index
* @param index2 second of the three values forming the threedimensional index
* @param index3 three of the three values forming the threedimensional index
* @return the counter value of the desired index
* @throws IllegalArgumentException if the index formed by the arguments is invalid
*/
int getEntry(int index1, int index2, int index3);
/**
* Returns the maximum index value for one of the three indexes.
* @throws IllegalArgumentException if the index formed by the arguments is invalid
*/
int getMaxValue(int index);
/**
* Returns the number of used entries (those entries with
* a counter value larger than zero).
* @return number of non-zero counter values
*/
int getNumUsedEntries();
/**
* Increases the counter value of (index1, index2, index3) by one.
* This method can be implemented by the one-liner
* setEntry(index1, index2, index3, getEntry(index1, index2, index3) + 1);
* However, implementations of this method may take advantage of
* implementation details to provide a more efficient approach.
* @param index1 first of the three values forming the threedimensional index
* @param index2 second of the three values forming the threedimensional index
* @param index3 three of the three values forming the threedimensional index
* @throws IllegalArgumentException if the index formed by the arguments is invalid
*/
void increaseEntry(int index1, int index2, int index3);
/**
* Sets the counter value of (index1, index2, index3) to newValue.
*
* @param index1 first of the three values forming the threedimensional index
* @param index2 second of the three values forming the threedimensional index
* @param index3 three of the three values forming the threedimensional index
* @param newValue the counter value that is assigned to the argument index
* @throws IllegalArgumentException if the index formed by the first three arguments is invalid
*/
void setEntry(int index1, int index2, int index3, int newValue);
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/color/WebsafePaletteCreator.java 0000664 0000000 0000000 00000003267 07741250131 026232 0 ustar /*
* WebsafePaletteCreator
*
* Copyright (c) 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.color;
import net.sourceforge.jiu.data.Palette;
import net.sourceforge.jiu.data.RGBIndex;
/**
* This class creates {@link net.sourceforge.jiu.data.Palette} objects that
* contain the so-called websafe palette.
* This palette has 216 entries which are uniformly spread over the RGB color
* cube.
* Each component (red / green / blue) takes each of the six values 0, 51, 101,
* 153, 204 and 255 (note that the difference is almost equal between two consecutive
* values, between 50 and 52).
* Therefore, the palette will have 63 = 6 * 6 * 6 = 216 entries.
* * This palette was designed with computer systems in mind that can only display * 256 colors at a time. * With the 216 colors that are uniformly spread over RGB color space, there is * at least a somewhat similar match for each possible input color. * * @author Marco Schmidt * @since 0.5.0 */ public class WebsafePaletteCreator implements RGBIndex { private static final int[] SAMPLES = {0x00, 0x33, 0x66, 0x99, 0xcc, 0xff}; private WebsafePaletteCreator() { // private so that this class cannot be instantiated } /** * Creates a new palette with the 216 websafe colors. * @return new palette object */ public static Palette create() { Palette result = new Palette(216, 255); int index = 0; for (int r = 0; r < 6; r++) { for (int g = 0; g < 6; g++) { for (int b = 0; b < 6; b++) { result.put(index++, SAMPLES[r], SAMPLES[g], SAMPLES[b]); } } } return result; } } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/util/ 0000775 0000000 0000000 00000000000 10546532075 021012 5 ustar java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/util/ArrayRotation.java 0000664 0000000 0000000 00000030507 10572433350 024453 0 ustar /* * ArrayRotation * * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Marco Schmidt * All rights reserved. */ package net.sourceforge.jiu.util; /** * Provides static methods to rotate (in steps of 90 degrees), flip and mirror array elements. * The image data is expected to be available as an array of integer values, being stored as rows top-to-bottom. * Within each row, the data is laid out from left to right. * This class may also been useful for transposing matrices. *
* The rotation by 90 and 270 degrees in-place (i.e., without using a * second array to copy to) is based on ideas and code developed * by others. * See Rotation of arrays * by Thomas W. Christopher. *
* I also got very useful advice from Hans-Bernhard Broeker and others in * comp.graphics.algorithms. * There is a thread titled In-place rotation of pixel images starting Oct 11, 2000. *
* Note: This class should be adjusted if Java ever supports genericity. * Then rotation functionality could be provided for all kinds of arrays. * @author Hans-Bernhard Broeker * @author Thomas W. Christopher * @author Marco Schmidt */ public class ArrayRotation { private ArrayRotation() { } /** * This method checks several properties of the arguments. * If any of the properties is not fulfilled, an explaining * {@link java.lang.IllegalArgumentException} is thrown. * Otherwise, nothing happens. * This method is supposed to be called at the beginning of several * other methods in this class. * Properties checked: *
pixels
is non-nullwidth
and height
are larger than zeropixels
is at least width
times height
true
all work is done on the pixels
array;
* otherwise, a second array is allocated and the pixels
array
* remains unmodified
* @param pixels the array of pixels that form the image to be flipped
* @param width the horizontal resolution of the image; must be larger than 0
* @param height the vertical resolution of the image; must be larger than 0
* @return the flipped image as int array; equals pixels
if
* inPlace
is true
* @exception IllegalArgumentException if the pixel resolution
* is invalid or the pixels array is not initialized or its length smaller
* than width
times height
*/
public static final int[] flip(boolean inPlace, int[] pixels, int width, int height)
{
if (inPlace)
{
flipInPlace(pixels, width, height);
return pixels;
}
else
{
return flip(pixels, width, height);
}
}
/**
* Mirrors the image given by the arguments.
* For each row, pixels are swapped, leftmost and rightmost,
* second-leftmost and second-rightmost, and so on.
* The inPlace argument determines if the pixels array is modified or not.
* If inPlace is true, no additional array is used.
* Otherwise, an array of width times height items is allocated and the
* mirrored image will be stored in this array.
* @param inPlace if true
all work is done on the pixels
array;
* otherwise, a second array is allocated and the pixels
array
* remains unmodified
* @param pixels the array of pixels that form the image to be flipped
* @param width the horizontal resolution of the image; must be larger than 0
* @param height the vertical resolution of the image; must be larger than 0
* @return the flipped image as int array; equals pixels
if
* inPlace
is true
* @exception IllegalArgumentException if the pixel resolution
* is invalid or the pixels array is not initialized or its length smaller
* than width
times height
*/
/*public static int[] mirror(boolean inPlace, int[] pixels, int width, int height)
{
if (inPlace)
{
//flipInPlace(pixels, width, height);
return pixels;
}
else
{
return pixels;//flip(pixels, width, height);
}
}*/
/**
* Rotates the argument image by 180 degrees.
* The resulting image will have exactly the same pixel resolution.
* Note that this operation is the same as two consecutive 90 degree
* rotations in the same direction.
* Another way of implementing a 180 degree rotation is first flipping
* and then mirroring the original image (or vice versa).
*
* If inPlace
is true, the rotation is done on the
* argument pixels
array.
* Otherwise a new array of sufficient length is allocated and the
* rotated image will be stored in this new array, not modifying the
* content of the pixels
array.
*
* @param inPlace determines whether the rotated image is written to the argument array
* @param pixels the array of pixels that form the image to be rotated
* @param width the horizontal resolution of the image; must be larger than 0
* @param height the vertical resolution of the image; must be larger than 0
* @return the flipped image as int array; equals pixels
if
* inPlace
is true
* @exception IllegalArgumentException if the pixel resolution
* is invalid or the pixels array is not initialized or its length smaller
* than width
times height
*/
public static int[] rotate180(boolean inPlace, int[] pixels, int width, int height)
{
if (inPlace)
{
rotateInPlace180(pixels, width, height);
return pixels;
}
else
{
return pixels;//rotateToCopy180(pixels, width, height);
}
}
/*private static int[] rotate180(int[] pixels, int width, int height)
{
checkPixelArray(pixels, width, height);
int numPixels = width * height;
int[] result = new int[numPixels];
int x1 = 0;
int x2 = numPixels - 1;
while (x1 < x2)
{
int temp = pixels[x1];
pixels[x1++] = pixels[x2];
pixels[x2--] = temp;
}
return result;
}*/
private static void rotateInPlace180(int[] pixels, int width, int height)
{
checkPixelArray(pixels, width, height);
int x1 = 0;
int x2 = width * height - 1;
while (x1 < x2)
{
int temp = pixels[x1];
pixels[x1++] = pixels[x2];
pixels[x2--] = temp;
}
}
/*private static void rotateToArray90Left(int[] src, int[] dest, int width, int height)
{
checkPixelArray(src, width, height);
checkPixelArray(dest, width, height);
if (src == dest)
{
throw new IllegalArgumentException("rotate90Left assumes that the argument arrays are not the same.");
}
int x_ = -1;
int y_ = -1;
try
{
int offset = 0;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
x_ = x;
y_ = y;
dest[(width - x - 1) * height + y] = src[offset++];
}
}
}
catch (ArrayIndexOutOfBoundsException ae)
{
System.out.println("bounds; x=" + x_ + " y=" + y_);
}
}*/
/*private static int pred(int k, int width, int height)
{
return (k % height) * width + k / height;
}
private static void rotateInPlace90Left(int[] pixels, int width, int height)
{
int LxM = height * width;
int i, j, k, stillToMove;
for (i = 0, stillToMove = LxM; stillToMove > 0; i++)
{
for (j = pred(i, width, height); j > i; j = pred(j, width, height))
;
if (j < i)
{
continue;
}
for (k = i, j = pred(i, width, height); j != i; k = j,
j = pred(j, width, height))
{
//exchange(k,j);
int temp = pixels[k];
pixels[k] = pixels[j];
pixels[j] = temp;
--stillToMove;
}
--stillToMove;
}
}*/
public static void rotate90Left(int width, int height, byte[] src, int srcOffset, byte[] dest, int destOffset)
{
int offset = srcOffset;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
dest[destOffset + (width - x - 1) * height + y] = src[offset++];
}
}
}
public static void rotate90Right(int width, int height, byte[] src, int srcOffset, byte[] dest, int destOffset)
{
int offset = srcOffset;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
dest[destOffset + x * height + (height - 1 - y)] = src[offset++];
}
}
}
public static void rotate180(int width, int height, byte[] src, int srcOffset, byte[] dest, int destOffset)
{
int n = width * height;
destOffset = destOffset + n - 1;
while (n-- > 0)
{
dest[destOffset--] = src[srcOffset++];
}
}
/* public static int[] rotate90Left(boolean inPlace, int[] pixels, int width,
int height) throws IllegalArgumentException
{
if (inPlace)
{
rotateInPlace90Left(pixels, width, height);
return pixels;
}
else
{
int[] dest = new int[width * height];
rotateToArray90Left(pixels, dest, width, height);
return dest;
}
}*/
private static void rotateInPlace90Right(int[] pixels, int width, int height)
{
throw new IllegalArgumentException("This method not implemented yet.");
}
private static int[] rotate90Right(int[] pixels, int width, int height)
{
int[] result = new int[width * height];
int offset = 0;
for (int y = 0; y < height; y++)
{
int srcOffset = height - 1 - y;
for (int x = 0; x < width; x++)
{
result[srcOffset] = pixels[offset++];
srcOffset += height;
}
}
return result;
}
public static int[] rotate90Right(boolean inPlace, int[] pixels, int width, int height)
{
if (inPlace)
{
rotateInPlace90Right(pixels, width, height);
return pixels;
}
else
{
return rotate90Right(pixels, width, height);
}
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/util/Sort.java 0000664 0000000 0000000 00000012227 07741250135 022605 0 ustar /*
* Sort
*
* Copyright (c) 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.util;
import net.sourceforge.jiu.util.ComparatorInterface;
/**
* Provides sorting of an Object array.
* @author Marco Schmidt
*/
public class Sort
{
/**
* This class is supposed to have static methods only.
* To hide any constructor, we define an empty private one.
*/
private Sort()
{
}
/**
* Sorts some (or all) elements of an Object array according to a specified comparator.
* This method does exactly the same as java.util.Arrays.sort(Object[], int, int, Comparator).
* Unfortunately, this method is not available in Java 1.1, so it must be provided here.
*
* As for the implementation of this method, it is taken from Arrays.java as found in
* Classpath 0.0.2 (2001-01-06).
* Go to www.classpath.org to learn more
* about the project, which implements the Java core libraries under the GPL.
*
* @param a the array which is to be sorted
* @param from the index value of the first element of the interval to be sorted
* @param to the index value of the last element of the interval to be sorted
* @param c the comparator used to query the relation between two objects
*/
public static void sort(Object[] a, int from, int to, ComparatorInterface c)
{
if (a == null)
{
throw new IllegalArgumentException("The object array to be sorted must be non-null.");
}
if (from > to)
{
throw new IllegalArgumentException("The from parameter (" + from + ") must be smaller than or equal to the to parameter (" + to + ").");
}
if (to >= a.length)
{
throw new IllegalArgumentException("The to parameter (" + to + ") must be smaller than the array length (" + a.length + ").");
}
if (c == null)
{
throw new IllegalArgumentException("The comparator parameter must be non-null.");
}
// First presort the array in chunks of length 6 with insertion sort.
// mergesort would give too much overhead for this length.
for (int chunk = from; chunk < to; chunk += 6)
{
int end = Math.min(chunk + 6, to);
for (int i = chunk + 1; i < end; i++)
{
if (c.compare(a[i - 1], a[i]) > 0)
{
// not already sorted
int j = i;
Object elem = a[j];
do
{
a[j] = a[j - 1];
j--;
}
while (j > chunk && c.compare(a[j - 1], elem) > 0);
a[j] = elem;
}
}
}
int len = to - from;
// If length is smaller or equal 6 we are done.
if (len <= 6)
return;
Object[]src = a;
Object[]dest = new Object[len];
Object[]t = null; // t is used for swapping src and dest
// The difference of the fromIndex of the src and dest array.
int srcDestDiff = -from;
// The merges are done in this loop
for (int size = 6; size < len; size <<= 1)
{
for (int start = from; start < to; start += size << 1)
{
// mid ist the start of the second sublist;
// end the start of the next sublist (or end of array).
int mid = start + size;
int end = Math.min(to, mid + size);
// The second list is empty or the elements are already in
// order - no need to merge
if (mid >= end || c.compare(src[mid - 1], src[mid]) <= 0)
{
System.arraycopy(src, start,
dest, start + srcDestDiff, end - start);
// The two halves just need swapping - no need to merge
}
else if (c.compare(src[start], src[end - 1]) > 0)
{
System.arraycopy(src, start,
dest, end - size + srcDestDiff, size);
System.arraycopy(src, mid,
dest, start + srcDestDiff, end - mid);
}
else
{
// Declare a lot of variables to save repeating
// calculations. Hopefully a decent JIT will put these
// in registers and make this fast
int p1 = start;
int p2 = mid;
int i = start + srcDestDiff;
// The main merge loop; terminates as soon as either
// half is ended
while (p1 < mid && p2 < end)
{
dest[i++] =
src[c.compare(src[p1], src[p2]) <= 0 ? p1++ : p2++];
}
// Finish up by copying the remainder of whichever half
// wasn't finished.
if (p1 < mid)
System.arraycopy(src, p1, dest, i, mid - p1);
else
System.arraycopy(src, p2, dest, i, end - p2);
}
}
// swap src and dest ready for the next merge
t = src;
src = dest;
dest = t;
from += srcDestDiff;
to += srcDestDiff;
srcDestDiff = -srcDestDiff;
}
// make sure the result ends up back in the right place. Note
// that src and dest may have been swapped above, so src
// contains the sorted array.
if (src != a)
{
// Note that from == 0.
System.arraycopy(src, 0, a, srcDestDiff, to);
}
}
/**
* Sort the complete argument array according to the argument comparator.
* Simply calls sort(a, 0, a.length - 1, comparator);
* @param a array to be sorted
* @param comparator the comparator used to compare to array entries
*/
public static void sort(Object[] a, ComparatorInterface comparator)
{
sort(a, 0, a.length - 1, comparator);
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/util/Statistics.java 0000664 0000000 0000000 00000015223 07741250135 024007 0 ustar /*
* Statistics
*
* Copyright (c) 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.util;
/**
* A number of static methods to compute statistical properties of an
* array of double values.
* Implements the computation of mean, variance and standard deviation
* for double
values.
* @author Marco Schmidt
* @since 0.11.0
*/
public class Statistics
{
private Statistics()
{
}
/**
* Computes the mean value for the argument array.
* Adds all values and divides them by the number of array elements.
* @param values double array on which the mean is to be determined
* @return computed mean value
* @throws IllegalArgumentException if the array has not at least one element
*/
public static double computeMean(double[] values)
{
return computeMean(values, 0, values.length);
}
/**
* Computes the mean value for some elements of the argument array.
* Adds all values and divides them by the number of array elements.
* @param values array from which elements are read
* @param offset index of the first element to be used
* @param number number of elements to be used
* @return computed mean value
* @throws IllegalArgumentException if the array has not at least one element
*/
public static double computeMean(double[] values, int offset, int number)
{
if (number < 1)
{
throw new IllegalArgumentException("The number of values to process must be one or larger.");
}
double sum = 0;
final int UNTIL = offset + number;
do
{
sum += values[offset++];
}
while (offset != UNTIL);
return sum / number;
}
/**
* Computes the standard deviation for the argument array of values.
* @param values array from which elements are read
* @return computed standard deviation
* @throws IllegalArgumentException if the array has not at least two elements
*/
public static double computeStandardDeviation(double[] values)
{
return computeStandardDeviation(values, 0, values.length);
}
/**
* Computes the standard deviation for the argument array of values.
* Reuses the mean value for that argument which must have been computed before.
* @param values array from which elements are read
* @param mean the mean value for the array, possibly computed with a
* call to {@link #computeMean(double[])}.
* @return computed standard deviation
* @throws IllegalArgumentException if the array has not at least two elements
*/
public static double computeStandardDeviation(double[] values, double mean)
{
return computeStandardDeviation(values, 0, values.length, mean);
}
/**
* Computes the standard deviation for some of the argument array's values.
* If you already have computed a mean value using {@link #computeMean(double[], int, int)},
* better call {@link #computeStandardDeviation(double[], int, int, double)}.
* Otherwise, this method has to compute mean again.
* @param values array from which elements are read
* @param offset first element to be used
* @param number number of elements used starting at values[offset]
* @return computed standard deviation
* @throws IllegalArgumentException if the array has not at least two elements
*/
public static double computeStandardDeviation(double[] values, int offset, int number)
{
double mean = computeMean(values, offset, number);
return computeStandardDeviation(values, 0, values.length, mean);
}
/**
* Computes the standard deviation for some of the argument array's values.
* Use this version of the method if you already have a mean value,
* otherwise this method must be computed again.
* @param values array from which elements are read
* @param offset first element to be used
* @param number number of elements used starting at values[offset]
* @param mean value of the elements
* @return computed standard deviation
* @throws IllegalArgumentException if the array has not at least two elements
*/
public static double computeStandardDeviation(double[] values, int offset, int number, double mean)
{
return Math.sqrt(computeVariance(values, offset, number, mean));
}
/**
* Computes the variance for the argument array.
* @param values array from which elements are read
* @return variance for the array elements
* @throws IllegalArgumentException if the array has not at least two elements
*/
public static double computeVariance(final double[] values)
{
return computeVariance(values, 0, values.length);
}
/**
* Computes the variance for some of the argument array's values.
* @param values array from which elements are read
* @param mean the mean for the array elements
* @return variance for the array elements
* @throws IllegalArgumentException if the array has not at least two elements
*/
public static double computeVariance(final double[] values, final double mean)
{
return computeVariance(values, 0, values.length, mean);
}
/**
* Computes the variance for some of the argument array's values.
* If you already have computed a mean value using {@link #computeMean(double[], int, int)},
* better call {@link #computeVariance(double[], int, int, double)}.
* Otherwise, this method has to compute mean again.
* @param values array from which elements are read
* @param offset first element to be used
* @param number number of elements used starting at values[offset]
* @return computed variance
* @throws IllegalArgumentException if the array has not at least two elements
*/
public static double computeVariance(final double[] values, int offset, final int number)
{
double mean = computeMean(values, offset, number);
return computeVariance(values, 0, values.length, mean);
}
/**
* Computes the variance for some of the argument array's values.
* Use this version of the method in case mean has already been
* computed.
* @param values array from which elements are read
* @param offset first element to be used
* @param number number of elements used starting at values[offset]
* @param mean the mean for the array elements
* @return computed variance
* @throws IllegalArgumentException if the array has not at least two elements
*/
public static double computeVariance(final double[] values, int offset, final int number, final double mean)
{
if (number < 2)
{
throw new IllegalArgumentException("The number of values to process must be two or larger.");
}
double sum = 0;
final int UNTIL = offset + number;
do
{
double diff = values[offset++] - mean;
sum += diff * diff;
}
while (offset != UNTIL);
return sum / (number - 1);
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/util/SeekableByteArrayOutputStream.java 0000664 0000000 0000000 00000014347 07741250135 027616 0 ustar /*
* SeekableByteArrayOutputStream
*
* Copyright (c) 2002 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.util;
import java.io.IOException;
import java.io.OutputStream;
/**
* An extension of {@link java.io.OutputStream} that writes data to an internal
* byte array, resizing it when necessary.
* Similar to {@link java.io.ByteArrayOutputStream}, but also enables seeking and truncating.
*
* @author Marco Schmidt
* @since 0.10.0
*/
public class SeekableByteArrayOutputStream extends OutputStream
{
private byte[] buffer;
private boolean closed;
private int incrementStep;
private int offset;
private int size;
/**
* Creates a new object of this class, setting initial capacity and increment size
* to default values.
*/
public SeekableByteArrayOutputStream()
{
this(1024, 1024);
}
/**
* Creates a new object of this class, setting initial capacity to the argument
* value.
* The increment size is set to the initial capacity as well if that value is larger
* than 0.
* Otherwise it is set to a default value.
* @param initialCapacity the number of bytes that are allocated in this constructor (0 or larger)
*/
public SeekableByteArrayOutputStream(int initialCapacity)
{
this(initialCapacity, initialCapacity == 0 ? 1024 : initialCapacity);
}
/**
* Creates a new object of this class, setting initial capacity and increment
* to the argument values.
* @param initialCapacity the number of bytes that are allocated in this constructor (0 or larger)
* @param increment the number of bytes by which the internal byte array is increased if it is full (1 or larger)
*/
public SeekableByteArrayOutputStream(int initialCapacity, int increment)
{
if (initialCapacity < 0)
{
throw new IllegalArgumentException("Value for initial capacity must not be negative.");
}
if (increment < 1)
{
throw new IllegalArgumentException("Value for increment must be 1 or larger.");
}
buffer = new byte[initialCapacity];
incrementStep = increment;
offset = 0;
}
/**
* Closes this output stream.
* After a call to this method, all write attempts will result in an exception.
*/
public void close() throws IOException
{
closed = true;
}
private void ensureSpace(int numBytes) throws IOException
{
if (closed)
{
throw new IOException("Stream was closed already. Cannot write to closed stream.");
}
if (numBytes < 0)
{
throw new IllegalArgumentException("Cannot write negative number of bytes (" + numBytes + ").");
}
if (buffer.length - offset < numBytes)
{
increaseBuffer(Math.max(buffer.length + incrementStep, offset + numBytes));
}
}
/**
* Returns the current offset in the output stream.
* Larger than or equal to 0 and smaller than or equal to {@link #getSize}.
* @return current position in the output stream, 0-based
*/
public int getPosition()
{
return offset;
}
/**
* Returns the current size of the output stream.
* @return size of the output stream in bytes (0 or larger)
*/
public int getSize()
{
return size;
}
private void increaseBuffer(int newLength)
{
if (newLength <= buffer.length)
{
return;
}
byte[] temp = new byte[newLength];
System.arraycopy(buffer, 0, temp, 0, offset);
buffer = temp;
}
/**
* Sets the current position in the output stream to the argument.
* @param newOffset new offset into the file, must be >= 0 and <= {@link #getSize}
* @throws IOException if the argument is invalid
*/
public void seek(int newOffset) throws IOException
{
if (newOffset < 0)
{
throw new IOException("Cannot seek to negative offset (" + newOffset + ").");
}
if (newOffset > size)
{
throw new IOException("Cannot seek to offset " + newOffset + ", stream has only " + size + " byte(s).");
}
offset = newOffset;
}
/**
* Allocates a new byte[]
object, copies {@link #getSize} bytes
* from the internal byte array to that new array and returns the array.
* @return a copy of the byte[] data stored internally
*/
public byte[] toByteArray()
{
byte[] result = new byte[size];
System.arraycopy(buffer, 0, result, 0, size);
return result;
}
/**
* Removes all bytes after the current position.
* After a call to this method, {@link #getSize} is equal to {@link #getPosition}.
*/
public void truncate()
{
size = offset;
}
/**
* Writes the least significant eight bits of the argument int
to the internal array.
* @param b int variable that stores the byte value to be written
*/
public void write(int b) throws IOException
{
ensureSpace(1);
buffer[offset++] = (byte)b;
if (offset > size)
{
size = offset;
}
}
/**
* Write the complete argument array to this stream.
* Copies the data to the internal byte array.
* Simply calls write(data, 0, data.length);
.
* @param data array to be copied to this stream
*/
public void write(byte[] data) throws IOException
{
write(data, 0, data.length);
}
/**
* Write some bytes from the argument array to this stream.
* Copies num bytes starting at src[srcOffset] to this stream.
* @param src the array from which data is copied
* @param srcOffset int index into that array pointing to the first byte to be copied
* @param num number of bytes to be copied
*/
public void write(byte[] src, int srcOffset, int num) throws IOException
{
ensureSpace(num);
System.arraycopy(src, srcOffset, buffer, offset, num);
offset += num;
if (offset > size)
{
size = offset;
}
}
/**
* Writes the bytes in the internal byte array to the argument output stream.
* A call to this method has the same effect as
*
* byte[] copy = toByteArray(); * out.write(copy, 0, copy.length); ** However, you with this method you save the allocation of an additional byte array * and the copying to that new array. * @param out the output stream to which this stream's content is copied * @throws IOException if out has a problem writing the bytes */ public void writeTo(OutputStream out) throws IOException { out.write(buffer, 0, size); } } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/util/ArrayScaling.java 0000664 0000000 0000000 00000006701 10572433337 024240 0 ustar /* * ArrayScaling * * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Marco Schmidt * All rights reserved. */ package net.sourceforge.jiu.util; import java.lang.IllegalArgumentException; /** * This class currently only scales up an image given as a one-dimensional array * of values. *
* Note: This class should be adjusted if Java ever supports genericity.
* It could then work on all kinds of arrays.
*
* @author Marco Schmidt
*/
public class ArrayScaling
{
private ArrayScaling()
{
}
/**
* Scales up the argument image by factor 2 in both directions.
* It is assumed that the first width
times
* height
values of data
contain an image
* (or image channel).
* The pixels (or samples) are assumed to be laid out rows top-to-bottom,
* within each row left-to-right.
* It is further assumed that the length of the data
array is
* at least 4 times width
times height
.
* This method scales up the image in data
so that after the call to this
* method data
can be treated as an image (a channel) that has a horizontal
* resolution of width * 2
and a vertical resolution of
* height * 2
.
*
* @param data the array of pixels that form the image to be flipped
* @param width the horizontal resolution of the image; must be larger than 0
* @param height the vertical resolution of the image; must be larger than 0
* @exception IllegalArgumentException if the arguments are invalid
*/
public static final void scaleUp200Percent(byte[] data, int width, int height)
throws IllegalArgumentException
{
if (data == null)
{
throw new IllegalArgumentException("Error -- data must be non-null.");
}
if (width < 1 || height < 1)
{
throw new IllegalArgumentException("Error -- both width and " +
"height must be larger than zero (width=" + width +
", height=" + height + ").");
}
if (width * height * 4 > data.length)
{
throw new IllegalArgumentException("Error -- data array must hold " +
"at least width times height times 4 values.");
}
int newWidth = width * 2;
int newHeight = height * 2;
// (1) scale up each row in horizontal direction and copy it to its destination
// at the same time
int y1 = height - 1;
int y2 = newHeight - 1;
while (y1 >= 0)
{
int x = width - 1;
int offset1 = (y1 + 1) * width - 1;
int offset2 = (y2 + 1) * newWidth - 1;
while (x > 0)
{
int v1 = data[offset1--] & 0xff;
int v2 = data[offset1] & 0xff;
data[offset2--] = (byte)v1;
data[offset2--] = (byte)((v1 + v2) >> 1);
x--;
}
byte v = data[offset1];
data[offset2--] = v;
data[offset2] = v;
y1--;
y2 -= 2;
}
// (2) take two already-copied rows from scaled image and
// interpolate the row between them
int y = newHeight - 1;
while (y > 1)
{
int offset1 = (y - 2) * newWidth;
int offset2 = offset1 + newWidth;
int offset3 = offset2 + newWidth;
for (int x = 0; x < newWidth; x++)
{
int v1 = data[offset1++] & 0xff;
int v2 = data[offset3++] & 0xff;
data[offset2++] = (byte)((v1 + v2) >> 1);
}
y -= 2;
}
// (3) copy second row of scaled image to first row
int x1 = 0;
int x2 = newWidth;
while (x1 < newWidth)
{
data[x1++] = data[x2++];
}
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/util/ArrayConverter.java 0000664 0000000 0000000 00000037546 10104716177 024637 0 ustar /*
* ArrayConverter
*
* Copyright (c) 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.util;
/**
* Helper class with static methods to convert between byte arrays and primitive types.
* Useful for serialization.
* @author Marco Schmidt
* @since 0.9.0
*/
public class ArrayConverter
{
private static final int SHORT_SIZE = 2;
private static final int INT_SIZE = 4;
private ArrayConverter()
{
}
/**
* Makes sure that the arguments define a valid (existing) array interval.
* This includes:
*
* A little discussion on how to implement this method
* was held in the German Java newsgroup
* de.comp.lang.java.
* The message I wrote to start the thread has the ID
* 1ef7du4vfqsd2pskb6jukut6pnhn87htt2@4ax.com
.
* Read the
* thread
* at Google Groups.
* @param src byte array, each byte stores four two-bit intensity values
* @param srcOffset index into src
* @param dest byte array, each byte stores an eight-bit intensity values
* @param destOffset index into dest
* @param numPackedBytes number of bytes in src to be decoded
*/
public static void convertPacked2BitIntensityTo8Bit(byte[] src, int srcOffset, byte[] dest, int destOffset, int numPackedBytes)
{
while (numPackedBytes-- > 0)
{
int srcValue = src[srcOffset++] & 0xff;
dest[destOffset++] = (byte)(((srcValue >> 6) & 3) * 85);
dest[destOffset++] = (byte)(((srcValue >> 4) & 3) * 85);
dest[destOffset++] = (byte)(((srcValue >> 2) & 3) * 85);
dest[destOffset++] = (byte)((srcValue & 3) * 85);
}
}
/**
* Converts bytes with four two-bit-intensity samples to byte-sized intensity values.
* Four-bit values can be from 0 to 15.
* These values will be scaled to the full [0;255] range so that 0 remains 0,
* 1 becomes 17, 2 becomes 34, ..., and 15 becomes 255.
* The most significant four bits in a byte become the left, the least significant
* four bits the right pixel.
* @param src byte array, each byte stores two four-bit intensity values
* @param srcOffset index into src
* @param dest byte array, each byte stores an eight-bit intensity values
* @param destOffset index into dest
* @param numPackedBytes number of bytes in src to be decoded
* @since 0.12.0
*/
public static void convertPacked4BitIntensityTo8Bit(byte[] src, int srcOffset, byte[] dest, int destOffset, int numPackedBytes)
{
while (numPackedBytes-- > 0)
{
int srcValue = src[srcOffset++] & 0xff;
dest[destOffset++] = (byte)((srcValue & 0xf0) | ((srcValue & 0xf0) >> 4));
dest[destOffset++] = (byte)((srcValue & 0x0f) | ((srcValue & 0x0f) << 4));
}
}
/**
* Copies a number of bit values from one byte array to another.
* @param src array from which is copied
* @param srcOffset index into the src array of the first byte from which is copied
* @param srcBitOffset first bit within src[srcOffset] from which is copied (0 is left-most, 1 is second left-most, 7 is right-most)
* @param dest array to which is copied
* @param destOffset index into the dest array of the first byte to which is copied
* @param destBitOffset first bit within dest[destOffset] to which is copied (0 is left-most, 1 is second left-most, 7 is right-most)
* @param numSamples number of bits to be copied
*/
public static void copyPackedBytes(byte[] src, int srcOffset, int srcBitOffset, byte[] dest, int destOffset, int destBitOffset, int numSamples)
{
if (numSamples < 0)
{
throw new IllegalArgumentException("Number of samples to be copied must be 0 or larger.");
}
if (srcBitOffset == 0 && destBitOffset == 0 && numSamples > 7)
{
int bytes = numSamples >> 3;
System.arraycopy(src, srcOffset, dest, destOffset, bytes);
srcOffset += bytes;
destOffset += bytes;
numSamples &= 7;
}
int srcMask = 1 << (7 - srcBitOffset);
int destMask = 1 << (7 - destBitOffset);
while (numSamples-- != 0)
{
if ((src[srcOffset] & srcMask) == 0)
{
dest[destOffset] &= (byte)(255 - destMask);
}
else
{
dest[destOffset] |= (byte)destMask;
}
if (srcMask == 1)
{
srcMask = 128;
srcOffset++;
}
else
{
srcMask >>= 1;
}
if (destMask == 1)
{
destMask = 128;
destOffset++;
}
else
{
destMask >>= 1;
}
}
}
public static void decodePacked1Bit(byte[] src, int srcOffset, byte[] dest, int destOffset, int numPackedBytes)
{
while (numPackedBytes-- != 0)
{
int srcValue = src[srcOffset++] & 0xff;
dest[destOffset++] = (byte)((srcValue >> 7) & 0x01);
dest[destOffset++] = (byte)((srcValue >> 6) & 0x01);
dest[destOffset++] = (byte)((srcValue >> 5) & 0x01);
dest[destOffset++] = (byte)((srcValue >> 4) & 0x01);
dest[destOffset++] = (byte)((srcValue >> 3) & 0x01);
dest[destOffset++] = (byte)((srcValue >> 2) & 0x01);
dest[destOffset++] = (byte)((srcValue >> 1) & 0x01);
dest[destOffset++] = (byte)(srcValue & 0x01);
}
}
/**
* Decodes bytes with four two-bit samples to single bytes.
* The two most significant bits of a source byte become the first value,
* the two least significant bits the fourth value.
* The method expects numPackedBytes
bytes at src[srcOffset]
* (these will be read and interpreted) and
* numPackedBytes * 4
at dest[destOffset]
(where the decoded
* byte values will be stored.
*
* @param src byte array, each byte stores four two-bit values
* @param srcOffset index into src
* @param dest byte array, each byte stores a single decoded value (from 0 to 3)
* @param destOffset index into dest
* @param numPackedBytes number of bytes in src to be decoded
* @since 0.10.0
*/
public static void decodePacked2Bit(byte[] src, int srcOffset, byte[] dest, int destOffset, int numPackedBytes)
{
while (numPackedBytes-- != 0)
{
int srcValue = src[srcOffset++] & 0xff;
dest[destOffset++] = (byte)(srcValue >> 6);
dest[destOffset++] = (byte)((srcValue >> 4) & 0x03);
dest[destOffset++] = (byte)((srcValue >> 2) & 0x03);
dest[destOffset++] = (byte)(srcValue & 0x03);
}
}
/**
* Decodes bytes with two four-bit samples to single bytes.
* The four most significant bits of a source byte become the first value,
* the least significant four bits the second value.
* The method expects numPackedBytes
bytes at src[srcOffset]
* (these will be read and interpreted) and
* numPackedBytes * 2
at dest[destOffset]
(where the decoded
* byte values will be stored.
*
* @param src byte array, each byte stores two four-bit values
* @param srcOffset index into src
* @param dest byte array, each byte stores a single decoded value
* @param destOffset index into dest
* @param numPackedBytes number of bytes in src to be decoded
*/
public static void decodePacked4Bit(byte[] src, int srcOffset, byte[] dest, int destOffset, int numPackedBytes)
{
while (numPackedBytes-- > 0)
{
int srcValue = src[srcOffset++] & 0xff;
dest[destOffset++] = (byte)(srcValue >> 4);
dest[destOffset++] = (byte)(srcValue & 0x0f);
}
}
/**
* Convert 16 bit RGB samples stored in big endian (BE) byte order
* with 5 bits for red and blue and 6 bits for green to 24
* bit RGB byte samples.
* @since 0.10.0
*/
public static void decodePackedRGB565BigEndianToRGB24(byte[] src, int srcOffset,
byte[] red, int redOffset,
byte[] green, int greenOffset,
byte[] blue, int blueOffset,
int numPixels)
{
while (numPixels-- != 0)
{
int pixel = ((src[srcOffset] & 0xff) << 8) | (src[srcOffset + 1] & 0xff);
srcOffset += 2;
int r = (pixel >> 11) & 0x1f;
int g = (pixel >> 5) & 0x3f;
int b = pixel & 0x1f;
red[redOffset++] = (byte)((r << 3) | ((r >> 2) & 0x07));
green[greenOffset++] = (byte)((g << 2) | ((g >> 4) & 0x03));
blue[blueOffset++] = (byte)((b << 3) | ((b >>2) & 0x07));
}
}
public static void encodePacked2Bit(byte[] src, int srcOffset, byte[] dest, int destOffset, int numSamples)
{
int numBytes = numSamples / 4;
while (numBytes-- != 0)
{
int b1 = src[srcOffset++] & 3;
int b2 = src[srcOffset++] & 3;
int b3 = src[srcOffset++] & 3;
int b4 = src[srcOffset++] & 3;
dest[destOffset++] = (byte)(b1 << 6 | b2 << 4 | b3 << 2 | b4);
}
numSamples = numSamples % 4;
if (numSamples > 0)
{
int value = 0;
int mask = 6;
while (numSamples-- != 0)
{
value |= ((src[srcOffset++] & 3) << mask);
mask -= 2;
}
dest[destOffset] = (byte)value;
}
}
public static void encodePacked4Bit(byte[] src, int srcOffset, byte[] dest, int destOffset, int numSamples)
{
int numBytes = numSamples / 2;
while (numBytes-- != 0)
{
int b1 = src[srcOffset++] & 15;
int b2 = src[srcOffset++] & 15;
dest[destOffset++] = (byte)(b1 << 4 | b2);
}
if ((numSamples % 2) == 1)
{
dest[destOffset] = (byte)((src[srcOffset] & 15) << 4);
}
}
/**
* Convert 24 bit RGB pixels to 16 bit pixels stored in big endian (BE) byte order
* with 5 bits for red and blue and 6 bits for green.
* @since 0.10.0
*/
public static void encodeRGB24ToPackedRGB565BigEndian(
byte[] red, int redOffset,
byte[] green, int greenOffset,
byte[] blue, int blueOffset,
byte[] dest, int destOffset,
int numPixels)
{
while (numPixels-- != 0)
{
int r = (red[redOffset++] & 0xff) >> 3;
int g = (green[greenOffset++] & 0xff) >> 2;
int b = (blue[blueOffset++] & 0xff) >> 3;
int pixel = r << 11 | g << 5 | b;
dest[destOffset++] = (byte)(pixel >> 8);
dest[destOffset++] = (byte)(pixel & 0xff);
}
}
/**
* Reads four consecutive bytes from the given array at the
* given position in big endian order and returns them as
* an int
.
* @param src the array from which bytes are read
* @param srcOffset the index into the array from which the bytes are read
* @return int value taken from the array
*/
public static int getIntBE(byte[] src, int srcOffset)
{
checkArray(src, srcOffset, INT_SIZE);
return
(src[srcOffset + 3] & 0xff) |
((src[srcOffset + 2] & 0xff) << 8) |
((src[srcOffset + 1] & 0xff) << 16) |
((src[srcOffset] & 0xff) << 24);
}
/**
* Reads four consecutive bytes from the given array at the
* given position in little endian order and returns them as
* an int
.
* @param src the array from which bytes are read
* @param srcOffset the index into the array from which the bytes are read
* @return short value taken from the array
*/
public static int getIntLE(byte[] src, int srcOffset)
{
checkArray(src, srcOffset, INT_SIZE);
return
(src[srcOffset] & 0xff) |
((src[srcOffset + 1] & 0xff) << 8) |
((src[srcOffset + 2] & 0xff) << 16) |
((src[srcOffset + 3] & 0xff) << 24);
}
/**
* Reads two consecutive bytes from the given array at the
* given position in big endian order and returns them as
* a short
.
* @param src the array from which two bytes are read
* @param srcOffset the index into the array from which the two bytes are read
* @return short value taken from the array
*/
public static short getShortBE(byte[] src, int srcOffset)
{
checkArray(src, srcOffset, SHORT_SIZE);
return (short)
(((src[srcOffset++] & 0xff) << 8) |
(src[srcOffset++] & 0xff));
}
public static int getShortBEAsInt(byte[] src, int srcOffset)
{
checkArray(src, srcOffset, SHORT_SIZE);
return ((src[srcOffset++] & 0xff) << 8) |
(src[srcOffset++] & 0xff);
}
/**
* Reads two consecutive bytes from the given array at the
* given position in little endian order and returns them as
* a short
.
* @param src the array from which two bytes are read
* @param srcOffset the index into the array from which the two bytes are read
* @return short value taken from the array
*/
public static short getShortLE(byte[] src, int srcOffset)
{
checkArray(src, srcOffset, SHORT_SIZE);
return (short)
((src[srcOffset++] & 0xff) |
((src[srcOffset++] & 0xff) << 8));
}
/**
* Writes an int value into four consecutive bytes of a byte array,
* in big endian (network) byte order.
* @param dest the array to which bytes are written
* @param destOffset index of the array to which the first byte is written
* @param newValue the int value to be written to the array
*/
public static void setIntBE(byte[] dest, int destOffset, int newValue)
{
checkArray(dest, destOffset, INT_SIZE);
dest[destOffset] = (byte)((newValue >> 24)& 0xff);
dest[destOffset + 1] = (byte)((newValue >> 16)& 0xff);
dest[destOffset + 2] = (byte)((newValue >> 8)& 0xff);
dest[destOffset + 3] = (byte)(newValue & 0xff);
}
/**
* Writes an int value into four consecutive bytes of a byte array,
* in little endian (Intel) byte order.
* @param dest the array to which bytes are written
* @param destOffset index of the array to which the first byte is written
* @param newValue the int value to be written to the array
*/
public static void setIntLE(byte[] dest, int destOffset, int newValue)
{
checkArray(dest, destOffset, INT_SIZE);
dest[destOffset] = (byte)(newValue & 0xff);
dest[destOffset + 1] = (byte)((newValue >> 8)& 0xff);
dest[destOffset + 2] = (byte)((newValue >> 16)& 0xff);
dest[destOffset + 3] = (byte)((newValue >> 24)& 0xff);
}
public static void setShortBE(byte[] dest, int destOffset, short newValue)
{
checkArray(dest, destOffset, SHORT_SIZE);
dest[destOffset] = (byte)((newValue >> 8) & 0xff);
dest[destOffset + 1] = (byte)(newValue & 0xff);
}
public static void setShortLE(byte[] dest, int destOffset, short newValue)
{
checkArray(dest, destOffset, SHORT_SIZE);
dest[destOffset + 1] = (byte)((newValue >> 8) & 0xff);
dest[destOffset] = (byte)(newValue & 0xff);
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/util/package.html 0000664 0000000 0000000 00000000363 07741250135 023272 0 ustar
Various helper classes with functionality not directly related to imaging. java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/util/ComparatorInterface.java 0000664 0000000 0000000 00000001563 10324334215 025600 0 ustar /* * ComparatorInterface * * Copyright (c) 2001, 2002, 2003, 2004, 2005 Marco Schmidt * All rights reserved. */ package net.sourceforge.jiu.util; /** * To be able to do sorting in Java 1.1 as defined in java.util.Arrays (which * is only available in Java 1.2 and higher), we offer a java.util.Comparator * clone under a different name: ComparatorInterface. * Sorting will be provided by the {@link Sort} class of this package. */ public interface ComparatorInterface { /** * Compares the two argument objects and returns their relation. * Returns *
o1
is smaller than o2
,o1
is equal to o2
ando1
is greater than o2
.from
and goes to
* to
; the values at these positions are included.
* Note that the array will be modified while searching, so you might want
* to backup your data.
*
* This implementation is a port of the C function from
* quickselect.c
, provided at http://ndevilla.free.fr/median/.
* The page is a good resource for various median value algorithms, including
* implementations and benchmarks.
*
* The original code on which this class is based was written in C++ * by Martin Leese. * It was ported to C and optimized by Nicolas Devillard (author of the * above mentioned page). * The algorithm is from Numerical recipes in C, Second Edition, * Cambridge University Press, 1992, Section 8.5, ISBN 0-521-43108-5. *
*
* @param a the array
* @param from the index of the start of the interval in which the median value will be searched
* @param to the index of the end of the interval in which the median value will be searched
* @return the median value
*/
public static int find(int[] a, int from, int to)
{
int low = from;
int high = to;
int median = (low + high) / 2;
do
{
if (high <= low)
{
return a[median];
}
if (high == low + 1)
{
if (a[low] > a[high])
{
swap(a, low, high);
}
return a[median];
}
int middle = (low + high) / 2;
if (a[middle] > a[high])
{
swap(a, middle, high);
}
if (a[low] > a[high])
{
swap(a, low, high);
}
if (a[middle] > a[low])
{
swap(a, middle, low);
}
swap(a, middle, low + 1);
int ll = low + 1;
int hh = high;
do
{
do
{
ll++;
}
while(a[low] > a[ll]);
do
{
hh--;
}
while(a[hh] > a[low]);
if (hh < ll)
{
break;
}
swap(a, ll, hh);
}
while(true);
swap(a, low, hh);
if (hh <= median)
{
low = ll;
}
if (hh >= median)
{
high = hh - 1;
}
}
while(true);
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/apps/ 0000775 0000000 0000000 00000000000 10612172112 020762 5 ustar java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/apps/MenuWrapper.java 0000664 0000000 0000000 00000023542 10404065334 024106 0 ustar /*
* MenuWrapper
*
* Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.apps;
/**
* Abstract menu wrapper.
* A menu consists of a number of menu elements, each of which have a text,
* an enabled status and an int constant from MenuIndexConstants associated with it.
* @author Marco Schmidt
*/
public abstract class MenuWrapper
{
/**
* Attempts to find the index of a given object that represents a menu element.
* @param o some object representing part of the menu
* @return corresponding index value from {@link MenuIndexConstants} on success
* or -1 on failure
*/
public abstract int findIndex(Object o);
/**
* For one of the values in {@link MenuIndexConstants}, returns the corresponding
* constant in {@link StringIndexConstants}.
* @param menuIndex int value from the MenuIndexConstants interface
* @return int value from the StringIndexConstants interface
*/
public int getStringIndex(int menuIndex)
{
switch(menuIndex)
{
case(MenuIndexConstants.FILE): return StringIndexConstants.FILE;
case(MenuIndexConstants.FILE_OPEN): return StringIndexConstants.OPEN;
case(MenuIndexConstants.FILE_SAVEAS): return StringIndexConstants.SAVE_AS;
case(MenuIndexConstants.FILE_SAVEAS_GIF): return StringIndexConstants.GIF;
case(MenuIndexConstants.FILE_SAVEAS_PALM): return StringIndexConstants.PALM;
case(MenuIndexConstants.FILE_SAVEAS_PBM): return StringIndexConstants.PORTABLE_BITMAP;
case(MenuIndexConstants.FILE_SAVEAS_PGM): return StringIndexConstants.PORTABLE_GRAYMAP;
case(MenuIndexConstants.FILE_SAVEAS_PNG): return StringIndexConstants.PORTABLE_NETWORK_GRAPHICS;
case(MenuIndexConstants.FILE_SAVEAS_PPM): return StringIndexConstants.PORTABLE_PIXMAP;
case(MenuIndexConstants.FILE_SAVEAS_SUNRASTER): return StringIndexConstants.SUN_RASTER;
case(MenuIndexConstants.FILE_SAVEAS_WINDOWSBMP): return StringIndexConstants.WINDOWS_BITMAP;
case(MenuIndexConstants.FILE_IMAGE_1): return StringIndexConstants.IMAGE_1;
case(MenuIndexConstants.FILE_CLOSE): return StringIndexConstants.CLOSE;
case(MenuIndexConstants.FILE_EXIT): return StringIndexConstants.EXIT;
case(MenuIndexConstants.EDIT): return StringIndexConstants.EDIT;
case(MenuIndexConstants.EDIT_UNDO): return StringIndexConstants.EDIT_UNDO;
case(MenuIndexConstants.EDIT_REDO): return StringIndexConstants.EDIT_REDO;
case(MenuIndexConstants.COLOR): return StringIndexConstants.COLOR;
case(MenuIndexConstants.COLOR_ADJUST): return StringIndexConstants.ADJUST;
case(MenuIndexConstants.COLOR_ADJUST_BRIGHTNESS): return StringIndexConstants.BRIGHTNESS_MENU_ITEM;
case(MenuIndexConstants.COLOR_ADJUST_CONTRAST): return StringIndexConstants.CONTRAST_MENU_ITEM;
case(MenuIndexConstants.COLOR_ADJUST_GAMMA): return StringIndexConstants.GAMMA_MENU_ITEM;
case(MenuIndexConstants.COLOR_ADJUST_HUESATURATIONVALUE): return StringIndexConstants.HUE_SATURATION_VALUE_MENU_ITEM;
case(MenuIndexConstants.COLOR_HISTOGRAM): return StringIndexConstants.HISTOGRAM;
case(MenuIndexConstants.COLOR_HISTOGRAM_COUNTCOLORSUSED): return StringIndexConstants.COUNT_COLORS_USED;
case(MenuIndexConstants.COLOR_HISTOGRAM_EQUALIZE): return StringIndexConstants.EQUALIZE_HISTOGRAM_MENU_ITEM;
case(MenuIndexConstants.COLOR_HISTOGRAM_NORMALIZE): return StringIndexConstants.NORMALIZE_HISTOGRAM_MENU_ITEM;
case(MenuIndexConstants.COLOR_HISTOGRAM_TEXTUREPROPERTIES): return StringIndexConstants.TEXTURE_PROPERTIES_MENU_ITEM;
case(MenuIndexConstants.COLOR_HISTOGRAM_SAVEHISTOGRAMAS): return StringIndexConstants.SAVE_HISTOGRAM_AS_MENU_ITEM;
case(MenuIndexConstants.COLOR_HISTOGRAM_SAVECOOCCURRENCEMATRIXAS): return StringIndexConstants.SAVE_COOCCURRENCE_MATRIX_MENU_ITEM;
case(MenuIndexConstants.COLOR_HISTOGRAM_SAVECOOCCURRENCEFREQUENCYMATRIXAS): return StringIndexConstants.SAVE_COOCCURRENCE_FREQUENCY_MATRIX_MENU_ITEM;
case(MenuIndexConstants.COLOR_PALETTE): return StringIndexConstants.PALETTE_MENU_ITEM;
case(MenuIndexConstants.COLOR_PALETTE_SAVEAS): return StringIndexConstants.PALETTE_SAVE_AS_MENU_ITEM;
case(MenuIndexConstants.COLOR_PROMOTE): return StringIndexConstants.PROMOTE;
case(MenuIndexConstants.COLOR_PROMOTE_PROMOTETOPALETTED): return StringIndexConstants.PROMOTE_TO_PALETTED;
case(MenuIndexConstants.COLOR_PROMOTE_PROMOTETOGRAY8): return StringIndexConstants.PROMOTE_TO_GRAY8;
case(MenuIndexConstants.COLOR_PROMOTE_PROMOTETOGRAY16): return StringIndexConstants.PROMOTE_TO_GRAY16;
case(MenuIndexConstants.COLOR_PROMOTE_PROMOTETORGB24): return StringIndexConstants.PROMOTE_TO_RGB24;
case(MenuIndexConstants.COLOR_PROMOTE_PROMOTETORGB48): return StringIndexConstants.PROMOTE_TO_RGB48;
case(MenuIndexConstants.COLOR_REDUCE): return StringIndexConstants.REDUCE;
case(MenuIndexConstants.COLOR_REDUCE_REDUCETOBILEVELTHRESHOLD): return StringIndexConstants.REDUCE_TO_BILEVEL_THRESHOLD_MENU_ITEM;
case(MenuIndexConstants.COLOR_REDUCE_REDUCENUMBEROFSHADESOFGRAY): return StringIndexConstants.REDUCE_NUMBER_OF_SHADES_OF_GRAY_MENU_ITEM;
case(MenuIndexConstants.COLOR_REDUCE_CONVERTTOGRAYSCALE): return StringIndexConstants.CONVERT_TO_GRAYSCALE;
case(MenuIndexConstants.COLOR_REDUCE_MEDIANCUT): return StringIndexConstants.MEDIAN_CUT;
case(MenuIndexConstants.COLOR_REDUCE_OCTREE): return StringIndexConstants.OCTREE_COLOR_QUANTIZATION_MENU_ITEM;
case(MenuIndexConstants.COLOR_REDUCE_UNIFORMPALETTE): return StringIndexConstants.UNIFORM_PALETTE_COLOR_QUANTIZATION_MENU_ITEM;
case(MenuIndexConstants.COLOR_REDUCE_MAPTOARBITRARYPALETTE): return StringIndexConstants.MAP_TO_ARBITRARY_PALETTE_MENU_ITEM;
case(MenuIndexConstants.COLOR_INVERT): return StringIndexConstants.INVERT;
case(MenuIndexConstants.COLOR_CONVERTTOMINIMUMCOLORTYPE): return StringIndexConstants.CONVERT_TO_MINIMUM_COLOR_TYPE_MENU_ITEM;
case(MenuIndexConstants.TRANSFORMATIONS): return StringIndexConstants.TRANSFORMATIONS;
case(MenuIndexConstants.TRANSFORMATIONS_FLIP): return StringIndexConstants.FLIP;
case(MenuIndexConstants.TRANSFORMATIONS_MIRROR): return StringIndexConstants.MIRROR;
case(MenuIndexConstants.TRANSFORMATIONS_ROTATELEFT90): return StringIndexConstants.ROTATE_90_LEFT;
case(MenuIndexConstants.TRANSFORMATIONS_ROTATERIGHT90): return StringIndexConstants.ROTATE_90_RIGHT;
case(MenuIndexConstants.TRANSFORMATIONS_ROTATE180): return StringIndexConstants.ROTATE_180;
case(MenuIndexConstants.TRANSFORMATIONS_CROP): return StringIndexConstants.CROP_MENU_ITEM;
case(MenuIndexConstants.TRANSFORMATIONS_SHEAR): return StringIndexConstants.SHEAR_MENU_ITEM;
case(MenuIndexConstants.TRANSFORMATIONS_SCALE): return StringIndexConstants.SCALE;
case(MenuIndexConstants.FILTERS): return StringIndexConstants.FILTERS;
case(MenuIndexConstants.FILTERS_BLUR): return StringIndexConstants.BLUR;
case(MenuIndexConstants.FILTERS_SHARPEN): return StringIndexConstants.SHARPEN;
case(MenuIndexConstants.FILTERS_EDGEDETECTION): return StringIndexConstants.EDGE_DETECTION;
case(MenuIndexConstants.FILTERS_EMBOSS): return StringIndexConstants.EMBOSS;
case(MenuIndexConstants.FILTERS_PSYCHEDELICDISTILLATION): return StringIndexConstants.PSYCHEDELIC_DISTILLATION;
case(MenuIndexConstants.FILTERS_LITHOGRAPH): return StringIndexConstants.LITHOGRAPH;
case(MenuIndexConstants.FILTERS_HORIZONTALSOBEL): return StringIndexConstants.HORIZONTAL_SOBEL;
case(MenuIndexConstants.FILTERS_VERTICALSOBEL): return StringIndexConstants.VERTICAL_SOBEL;
case(MenuIndexConstants.FILTERS_HORIZONTALPREWITT): return StringIndexConstants.HORIZONTAL_PREWITT;
case(MenuIndexConstants.FILTERS_VERTICALPREWITT): return StringIndexConstants.VERTICAL_PREWITT;
case(MenuIndexConstants.FILTERS_MINIMUM): return StringIndexConstants.MINIMUM_FILTER_MENU_ITEM;
case(MenuIndexConstants.FILTERS_MAXIMUM): return StringIndexConstants.MAXIMUM_FILTER_MENU_ITEM;
case(MenuIndexConstants.FILTERS_MEDIAN): return StringIndexConstants.MEDIAN_FILTER_MENU_ITEM;
case(MenuIndexConstants.FILTERS_MEAN): return StringIndexConstants.MEAN_FILTER_MENU_ITEM;
case(MenuIndexConstants.FILTERS_OIL): return StringIndexConstants.OIL_FILTER_MENU_ITEM;
case(MenuIndexConstants.VIEW): return StringIndexConstants.VIEW;
case(MenuIndexConstants.VIEW_ZOOMIN): return StringIndexConstants.VIEW_ZOOMIN;
case(MenuIndexConstants.VIEW_ZOOMOUT): return StringIndexConstants.VIEW_ZOOMOUT;
case(MenuIndexConstants.VIEW_SETORIGINALSIZE): return StringIndexConstants.VIEW_SETORIGINALSIZE;
case(MenuIndexConstants.VIEW_INTERPOLATIONTYPE): return StringIndexConstants.VIEW_INTERPOLATIONTYPE;
case(MenuIndexConstants.VIEW_INTERPOLATIONTYPE_NEARESTNEIGHBOR): return StringIndexConstants.VIEW_INTERPOLATIONTYPE_NEARESTNEIGHBOR;
case(MenuIndexConstants.VIEW_INTERPOLATIONTYPE_BILINEAR): return StringIndexConstants.VIEW_INTERPOLATIONTYPE_BILINEAR;
case(MenuIndexConstants.VIEW_INTERPOLATIONTYPE_BICUBIC): return StringIndexConstants.VIEW_INTERPOLATIONTYPE_BICUBIC;
case(MenuIndexConstants.HELP): return StringIndexConstants.HELP;
case(MenuIndexConstants.HELP_ABOUT): return StringIndexConstants.ABOUT;
case(MenuIndexConstants.HELP_SYSTEMINFORMATION): return StringIndexConstants.SYSTEM_INFORMATION;
default: return -1;
}
}
/**
* Sets the enabled status of one of the menu items to either
* true
or false
.
* @param index menu index of the component whose status is to be reset
* @param enabled boolean with the new value
*/
public abstract void setEnabled(int index, boolean enabled);
/**
* Sets the text of one of the menu elements to a new value.
* This method is usually called when the language settings have changed and
* new words have to be assigned.
* @param index integer index of the menu element
* @param text new text value to be used for this element
*/
public abstract void setLabel(int index, String text);
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/apps/Strings.java 0000664 0000000 0000000 00000011771 10121567174 023300 0 ustar /*
* Strings
*
* Copyright (c) 2001, 2002, 2003, 2004 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.apps;
import java.util.Hashtable;
import java.util.Locale;
/**
* String resource for the various apps.
* Each index value from {@link StringIndexConstants} has a corresponding String value
* for all supported natural languages.
* @author Marco Schmidt
*/
public class Strings implements StringIndexConstants
{
/**
* Constant int value for the natural language English.
* */
public static final Integer LANG_ENGLISH = new Integer(0);
/**
* Constant int value for the natural language German.
*/
public static final Integer LANG_GERMAN = new Integer(1);
/**
* Constant int value for the natural language Spanish.
*/
public static final Integer LANG_SPANISH = new Integer(2);
/**
* Constant int value for the natural language French.
*/
public static final Integer LANG_FRENCH = new Integer(3);
/**
* Constant of the default language, {@link #LANG_ENGLISH}.
*/
public static final Integer DEFAULT_LANGUAGE = LANG_ENGLISH;
/**
* ISO 639 two-letter country codes for the supported languages, lower case.
*/
private static final String[] ISO_639_LANGUAGE_CODES =
{
"en",
"de",
"es",
"fr",
};
private static final Integer[] LANGUAGE_CONSTANTS =
{
LANG_ENGLISH,
LANG_GERMAN,
LANG_SPANISH,
LANG_FRENCH,
};
/**
* The ISO 639 code for the default language {@link #DEFAULT_LANGUAGE}.
*/
public static final String DEFAULT_LANGUAGE_ISO_639_CODE = ISO_639_LANGUAGE_CODES[DEFAULT_LANGUAGE.intValue()];
/**
* A hashtable that maps from ISO 639 country codes to Integer
* objects with the corresponding LANG_xyz constant for that language.
*/
private static Hashtable isoToConstant;
static
{
isoToConstant = new Hashtable(ISO_639_LANGUAGE_CODES.length);
for (int i = 0; i < ISO_639_LANGUAGE_CODES.length; i++)
{
isoToConstant.put(ISO_639_LANGUAGE_CODES[i], LANGUAGE_CONSTANTS[i]);
}
}
private String[] data;
private Integer language;
/**
* Create a new String object for the given language and fill it
* with the String array.
*/
public Strings(Integer languageConstant, String[] stringValues)
{
set(languageConstant, stringValues);
}
/**
* Determines an ISO 639 code of a language suitable for the environment
* in which the JVM is currently running.
* First calls {@link #determineIsoCodeFromDefaultLocale()}.
* If that yields null, the ISO code for {@link #DEFAULT_LANGUAGE} is returned.
* So different from {@link #determineIsoCodeFromDefaultLocale()}
* this method always returns a non-null value.
* @return String with ISO 639 code of a language that fits the JVM environment,
* or the default language as fallback solution
*/
public static String determineSuitableIsoCode()
{
String code = determineIsoCodeFromDefaultLocale();
if (code != null && findLanguageCode(code) != null)
{
return code;
}
else
{
return ISO_639_LANGUAGE_CODES[DEFAULT_LANGUAGE.intValue()];
}
}
public static String determineIsoCodeFromDefaultLocale()
{
Locale locale = Locale.getDefault();
if (locale == null)
{
return null;
}
return locale.getLanguage();
}
public static Integer findLanguageCode(String iso639LanguageCode)
{
if (iso639LanguageCode == null)
{
return null;
}
String code = iso639LanguageCode.toLowerCase();
return (Integer)isoToConstant.get(code);
}
/**
* Gets the String denoted by the argument index.
* This index must be one of the int constants defined in {@link StringIndexConstants}.
* @return String with given index in the current language
* @throws IllegalArgumentException is not a valid index from {@link StringIndexConstants}
*/
public String get(int index)
{
try
{
return data[index];
}
catch (ArrayIndexOutOfBoundsException aioobe)
{
throw new IllegalArgumentException("Not a valid String index: " + index);
}
}
/**
* Returns the language of this object as one of the LANG_xyz
* constants of this class.
*/
public Integer getLanguage()
{
return language;
}
public static String getFileName(int languageCode)
{
if (languageCode >= 0 && languageCode < ISO_639_LANGUAGE_CODES.length)
{
return ISO_639_LANGUAGE_CODES[languageCode] + ".txt";
}
else
{
return null;
}
}
public void set(Integer languageConstant, String[] values)
{
if (languageConstant == null ||
languageConstant.intValue() < 0 ||
languageConstant.intValue() >= ISO_639_LANGUAGE_CODES.length)
{
throw new IllegalArgumentException("Not a valid language constant: " + languageConstant);
}
if (values == null || values.length < 1)
{
throw new IllegalArgumentException("The values array argument must be non-null and have at least one element.");
}
language = languageConstant;
data = values;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/apps/OperationProcessor.java 0000664 0000000 0000000 00000045536 10404072156 025510 0 ustar /*
* OperationProcessor
*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.apps;
import net.sourceforge.jiu.data.BilevelImage;
import net.sourceforge.jiu.data.Gray16Image;
import net.sourceforge.jiu.data.Gray8Image;
import net.sourceforge.jiu.data.Paletted8Image;
import net.sourceforge.jiu.data.PixelImage;
import net.sourceforge.jiu.data.RGB24Image;
import net.sourceforge.jiu.data.RGB48Image;
/**
* Abstract base class for performing JIU operations in combination
* with an {@link EditorState}.
* @author Marco Schmidt
*/
public abstract class OperationProcessor implements MenuIndexConstants
{
private EditorState state;
/**
* Create an object of this class, storing the state argument for later use.
* @param editorState EditorState object to be used for processing
*/
public OperationProcessor(EditorState editorState)
{
state = editorState;
}
/**
* Adjust the brightness of the current image.
*/
public abstract void colorAdjustBrightness();
/**
* Adjust the contrast of the current image.
*/
public abstract void colorAdjustContrast();
/**
* Adjust the gamma value of the current image.
*/
public abstract void colorAdjustGamma();
/**
* Adjust hue, saturation and value of the current image.
*/
public abstract void colorAdjustHueSaturationValue();
/**
* Count the number of colors used in the current image.
*/
public abstract void colorHistogramCountColorsUsed();
public abstract void colorHistogramEqualize();
public abstract void colorHistogramNormalize();
public abstract void colorHistogramTextureProperties();
public abstract void colorHistogramSaveHistogramAs();
public abstract void colorHistogramSaveCoOccurrenceMatrixAs();
public abstract void colorHistogramSaveCoOccurrenceFrequencyMatrixAs();
public abstract void colorPaletteSaveAs();
public abstract void colorPromotePromoteToPaletted();
public abstract void colorPromotePromoteToGray8();
public abstract void colorPromotePromoteToGray16();
public abstract void colorPromotePromoteToRgb24();
public abstract void colorPromotePromoteToRgb48();
public abstract void colorReduceReduceNumberOfShadesOfGray();
public abstract void colorReduceConvertToGrayscale();
public abstract void colorReduceMedianCut();
public abstract void colorReduceOctree();
public abstract void colorReduceReduceToBilevelThreshold();
public abstract void colorReduceUniformPalette();
public abstract void colorReduceMapToArbitraryPalette();
public abstract void colorConvertToMinimumColorType();
public abstract void colorInvert();
public abstract void editRedo();
public abstract void editUndo();
public abstract void filtersBlur();
public abstract void filtersSharpen();
public abstract void filtersEdgeDetection();
public abstract void filtersEmboss();
public abstract void filtersPsychedelicDistillation();
public abstract void filtersLithograph();
public abstract void filtersHorizontalSobel();
public abstract void filtersVerticalSobel();
public abstract void filtersHorizontalPrewitt();
public abstract void filtersVerticalPrewitt();
public abstract void filtersMaximum();
public abstract void filtersMedian();
public abstract void filtersMean();
public abstract void filtersMinimum();
public abstract void filtersOil();
public abstract void transformationsFlip();
public abstract void transformationsMirror();
public abstract void transformationsRotate90Left();
public abstract void transformationsRotate90Right();
public abstract void transformationsRotate180();
public abstract void transformationsCrop();
public abstract void transformationsShear();
public abstract void transformationsScale();
public abstract void viewInterpolationTypeBicubic();
public abstract void viewInterpolationTypeBilinear();
public abstract void viewInterpolationTypeNearestNeighbor();
public abstract void viewZoomIn();
public abstract void viewZoomOut();
public abstract void viewSetOriginalSize();
/**
* If there is an image loaded in the application, remove the image.
*/
public abstract void fileClose();
/**
* Terminate the application.
* If changes were not saved, the user should be asked whether these changes
* should be discarded.
*/
public abstract void fileExit();
/**
* Load an image in the application.
*/
public abstract void fileOpen(String uri);
/**
* Save the current image as a Windows BMP file.
*/
public abstract void fileSaveAsBmp();
/**
* Save the current image as a GIF file.
*/
public abstract void fileSaveAsGif();
/**
* Save the current image as a Palm image file.
*/
public abstract void fileSaveAsPalm();
/**
* Save the current image as a Portable Bitmap file.
*/
public abstract void fileSaveAsPbm();
/**
* Save the current image as a Portable Graymap file.
*/
public abstract void fileSaveAsPgm();
/**
* Save the current image as a Portable Network Graphics file.
*/
public abstract void fileSaveAsPng();
/**
* Save the current image as a Portable Pixmap file.
*/
public abstract void fileSaveAsPpm();
/**
* Save the current image as a Sun Raster file.
*/
public abstract void fileSaveAsRas();
/**
* Returns the EditorState object given to this object's constructor.
* @return EditorState object used by this processor
*/
public EditorState getEditorState()
{
return state;
}
/**
* Display information about the application:
* name, version, feedback email address, website.
*/
public abstract void helpAbout();
/**
* Display information on the system this application
* is currently running on.
*/
public abstract void helpSystemInformation();
/**
* Returns if the operation given by the menu index (from {@link MenuIndexConstants}
* is available regarding the current editor state.
* This method is used to update the enabled status of menu items so that
* they reflect what can be done in the current state of an application.
* Thus, things that cannot be done cannot be chosen in the menu
* because they are disabled.
* Example: the File | Save as... items are disabled as long as there is no image loaded,
* simply because there is nothing to save.
* @param menuIndex index of menu item to be checked
* @return whether the operation is available (if true, menu item
* should be enabled)
*/
public boolean isAvailable(int menuIndex)
{
boolean hasImage = state.hasImage();
PixelImage image = state.getImage();
boolean bilevel = hasImage && image instanceof BilevelImage;
boolean gray8 = hasImage && image instanceof Gray8Image;
boolean gray16 = hasImage && image instanceof Gray16Image;
//boolean gray = gray8 || gray16;
boolean pal8 = hasImage && image instanceof Paletted8Image;
boolean rgb24 = hasImage && image instanceof RGB24Image;
boolean rgb48 = hasImage && image instanceof RGB48Image;
boolean rgb = rgb24 || rgb48;
switch(menuIndex)
{
case(FILE):
{
return true;
}
case(FILE_OPEN):
{
return true;
}
case(FILE_CLOSE):
{
return hasImage;
}
case(FILE_SAVEAS):
{
return hasImage;
}
case(FILE_SAVEAS_GIF):
{
return bilevel || gray8 || pal8;
}
case(FILE_SAVEAS_PALM):
{
return bilevel || gray8 || pal8 || rgb24;
}
case(FILE_SAVEAS_PBM):
{
return bilevel;
}
case(FILE_SAVEAS_PGM):
{
return gray8 || gray16;
}
case(FILE_SAVEAS_PNG):
{
return hasImage;
}
case(FILE_SAVEAS_PPM):
{
return rgb24 || rgb48;
}
case(FILE_SAVEAS_SUNRASTER):
{
return pal8;
}
case(FILE_SAVEAS_WINDOWSBMP):
{
return bilevel || gray8 || pal8 || rgb24;
}
case(FILE_IMAGE_1):
{
return true;
}
case(FILE_EXIT):
{
return true;
}
case(EDIT):
{
return state.canUndo() || state.canRedo();
}
case(EDIT_UNDO):
{
return state.canUndo();
}
case(EDIT_REDO):
{
return state.canRedo();
}
case(COLOR):
{
return hasImage;
}
case(COLOR_ADJUST):
{
return !bilevel;
}
case(COLOR_ADJUST_BRIGHTNESS):
{
return gray8 || gray16 || pal8 || rgb24 || rgb48;
}
case(COLOR_ADJUST_CONTRAST):
{
return gray8 || gray16 || pal8 || rgb24 || rgb48;
}
case(COLOR_ADJUST_GAMMA):
{
return gray8 || gray16 || pal8 || rgb24 || rgb48;
}
case(COLOR_HISTOGRAM):
{
return hasImage;
}
case(COLOR_HISTOGRAM_COUNTCOLORSUSED):
{
return hasImage;
}
case(COLOR_HISTOGRAM_EQUALIZE):
{
return gray8 || pal8 || rgb24 || rgb48;
}
case(COLOR_HISTOGRAM_NORMALIZE):
{
return gray8 || pal8 || rgb24 || rgb48;
}
case(COLOR_HISTOGRAM_TEXTUREPROPERTIES):
{
return gray8;
}
case(COLOR_HISTOGRAM_SAVEHISTOGRAMAS):
{
return hasImage;
}
case(COLOR_HISTOGRAM_SAVECOOCCURRENCEMATRIXAS):
{
return pal8 || gray8 || bilevel;
}
case(COLOR_HISTOGRAM_SAVECOOCCURRENCEFREQUENCYMATRIXAS):
{
return pal8 || gray8 || bilevel;
}
case(COLOR_PALETTE):
{
return pal8;
}
case(COLOR_PALETTE_SAVEAS):
{
return pal8;
}
case(COLOR_PROMOTE):
{
return !rgb48;
}
case(COLOR_PROMOTE_PROMOTETOGRAY8):
{
return bilevel;
}
case(COLOR_PROMOTE_PROMOTETOGRAY16):
{
return bilevel || gray8;
}
case(COLOR_PROMOTE_PROMOTETORGB24):
{
return bilevel || gray8 || pal8;
}
case(COLOR_PROMOTE_PROMOTETORGB48):
{
return bilevel || gray8 || gray16 || pal8 || rgb24;
}
case(COLOR_PROMOTE_PROMOTETOPALETTED):
{
return bilevel || gray8;
}
case(COLOR_ADJUST_HUESATURATIONVALUE):
{
return pal8 || rgb24;
}
case(COLOR_REDUCE):
{
return !bilevel;
}
case(COLOR_REDUCE_CONVERTTOGRAYSCALE):
{
return pal8 || rgb;
}
case(COLOR_REDUCE_REDUCENUMBEROFSHADESOFGRAY):
{
return gray8 || gray16;
}
case(COLOR_REDUCE_REDUCETOBILEVELTHRESHOLD):
{
return gray8 || gray16;
}
case(COLOR_REDUCE_MEDIANCUT):
{
return rgb24;
}
case(COLOR_REDUCE_OCTREE):
{
return rgb24;
}
case(COLOR_REDUCE_UNIFORMPALETTE):
{
return rgb24;
}
case(COLOR_REDUCE_MAPTOARBITRARYPALETTE):
{
return rgb24;
}
case(COLOR_INVERT):
{
return hasImage;
}
case(COLOR_CONVERTTOMINIMUMCOLORTYPE):
{
return !bilevel;
}
case(TRANSFORMATIONS):
{
return hasImage;
}
case(TRANSFORMATIONS_FLIP):
{
return hasImage;
}
case(TRANSFORMATIONS_MIRROR):
{
return hasImage;
}
case(TRANSFORMATIONS_ROTATELEFT90):
{
return hasImage;
}
case(TRANSFORMATIONS_ROTATERIGHT90):
{
return hasImage;
}
case(TRANSFORMATIONS_ROTATE180):
{
return hasImage;
}
case(TRANSFORMATIONS_SHEAR):
{
return hasImage;
}
case(TRANSFORMATIONS_SCALE):
{
return hasImage;
}
case(TRANSFORMATIONS_CROP):
{
return hasImage;
}
case(FILTERS):
{
return hasImage && !pal8;
}
case(FILTERS_BLUR):
case(FILTERS_SHARPEN):
case(FILTERS_EDGEDETECTION):
case(FILTERS_EMBOSS):
case(FILTERS_PSYCHEDELICDISTILLATION):
case(FILTERS_LITHOGRAPH):
case(FILTERS_HORIZONTALSOBEL):
case(FILTERS_VERTICALSOBEL):
case(FILTERS_HORIZONTALPREWITT):
case(FILTERS_VERTICALPREWITT):
case(FILTERS_MEAN):
case(FILTERS_OIL):
{
return gray16 || gray8 || rgb24 || rgb48;
}
case(FILTERS_MAXIMUM):
case(FILTERS_MINIMUM):
case(FILTERS_MEDIAN):
{
return gray16 || gray8 || rgb24 || bilevel || rgb48;
}
case(VIEW):
case(VIEW_INTERPOLATIONTYPE):
case(VIEW_INTERPOLATIONTYPE_NEARESTNEIGHBOR):
case(VIEW_INTERPOLATIONTYPE_BILINEAR):
case(VIEW_INTERPOLATIONTYPE_BICUBIC):
{
return hasImage;
}
case(VIEW_SETORIGINALSIZE):
{
return hasImage && !state.isZoomOriginalSize();
}
case(VIEW_ZOOMIN):
{
return hasImage && !state.isMaximumZoom();
}
case(VIEW_ZOOMOUT):
{
return hasImage && !state.isMinimumZoom();
}
case(HELP):
{
return true;
}
case(HELP_ABOUT):
{
return true;
}
case(HELP_SYSTEMINFORMATION):
{
return true;
}
default:
{
throw new IllegalArgumentException("Not a valid menu index: " + menuIndex);
}
}
}
public void process(int menuIndex)
{
switch (menuIndex)
{
case(FILE_OPEN):
{
fileOpen(null);
break;
}
case(FILE_SAVEAS_GIF):
{
fileSaveAsGif();
break;
}
case(FILE_SAVEAS_PALM):
{
fileSaveAsPalm();
break;
}
case(FILE_SAVEAS_PBM):
{
fileSaveAsPbm();
break;
}
case(FILE_SAVEAS_PGM):
{
fileSaveAsPgm();
break;
}
case(FILE_SAVEAS_PNG):
{
fileSaveAsPng();
break;
}
case(FILE_SAVEAS_PPM):
{
fileSaveAsPpm();
break;
}
case(FILE_SAVEAS_SUNRASTER):
{
fileSaveAsRas();
break;
}
case(FILE_SAVEAS_WINDOWSBMP):
{
fileSaveAsBmp();
break;
}
case(FILE_IMAGE_1):
{
fileOpen("/resources/images/image1.jpg");
break;
}
case(FILE_CLOSE):
{
fileClose();
break;
}
case(FILE_EXIT):
{
fileExit();
break;
}
case(EDIT_UNDO):
{
editUndo();
break;
}
case(EDIT_REDO):
{
editRedo();
break;
}
case(COLOR_ADJUST_BRIGHTNESS):
{
colorAdjustBrightness();
break;
}
case(COLOR_ADJUST_CONTRAST):
{
colorAdjustContrast();
break;
}
case(COLOR_ADJUST_GAMMA):
{
colorAdjustGamma();
break;
}
case(COLOR_ADJUST_HUESATURATIONVALUE):
{
colorAdjustHueSaturationValue();
break;
}
case(COLOR_HISTOGRAM_COUNTCOLORSUSED):
{
colorHistogramCountColorsUsed();
break;
}
case(COLOR_HISTOGRAM_EQUALIZE):
{
colorHistogramEqualize();
break;
}
case(COLOR_HISTOGRAM_NORMALIZE):
{
colorHistogramNormalize();
break;
}
case(COLOR_HISTOGRAM_TEXTUREPROPERTIES):
{
colorHistogramTextureProperties();
break;
}
case(COLOR_HISTOGRAM_SAVEHISTOGRAMAS):
{
colorHistogramSaveHistogramAs();
break;
}
case(COLOR_HISTOGRAM_SAVECOOCCURRENCEMATRIXAS):
{
colorHistogramSaveCoOccurrenceMatrixAs();
break;
}
case(COLOR_HISTOGRAM_SAVECOOCCURRENCEFREQUENCYMATRIXAS):
{
colorHistogramSaveCoOccurrenceFrequencyMatrixAs();
break;
}
case(COLOR_PALETTE_SAVEAS):
{
colorPaletteSaveAs();
break;
}
case(COLOR_PROMOTE_PROMOTETOPALETTED):
{
colorPromotePromoteToPaletted();
break;
}
case(COLOR_PROMOTE_PROMOTETOGRAY8):
{
colorPromotePromoteToGray8();
break;
}
case(COLOR_PROMOTE_PROMOTETOGRAY16):
{
colorPromotePromoteToGray16();
break;
}
case(COLOR_PROMOTE_PROMOTETORGB24):
{
colorPromotePromoteToRgb24();
break;
}
case(COLOR_PROMOTE_PROMOTETORGB48):
{
colorPromotePromoteToRgb48();
break;
}
case(COLOR_REDUCE_REDUCETOBILEVELTHRESHOLD):
{
colorReduceReduceToBilevelThreshold();
break;
}
case(COLOR_REDUCE_REDUCENUMBEROFSHADESOFGRAY):
{
colorReduceReduceNumberOfShadesOfGray();
break;
}
case(COLOR_REDUCE_CONVERTTOGRAYSCALE):
{
colorReduceConvertToGrayscale();
break;
}
case(COLOR_REDUCE_MEDIANCUT):
{
colorReduceMedianCut();
break;
}
case(COLOR_REDUCE_OCTREE):
{
colorReduceOctree();
break;
}
case(COLOR_REDUCE_UNIFORMPALETTE):
{
colorReduceUniformPalette();
break;
}
case(COLOR_REDUCE_MAPTOARBITRARYPALETTE):
{
colorReduceMapToArbitraryPalette();
break;
}
case(COLOR_INVERT):
{
colorInvert();
break;
}
case(COLOR_CONVERTTOMINIMUMCOLORTYPE):
{
colorConvertToMinimumColorType();
break;
}
case(TRANSFORMATIONS_FLIP):
{
transformationsFlip();
break;
}
case(TRANSFORMATIONS_MIRROR):
{
transformationsMirror();
break;
}
case(TRANSFORMATIONS_ROTATELEFT90):
{
transformationsRotate90Left();
break;
}
case(TRANSFORMATIONS_ROTATERIGHT90):
{
transformationsRotate90Right();
break;
}
case(TRANSFORMATIONS_ROTATE180):
{
transformationsRotate180();
break;
}
case(TRANSFORMATIONS_CROP):
{
transformationsCrop();
break;
}
case(TRANSFORMATIONS_SCALE):
{
transformationsScale();
break;
}
case(TRANSFORMATIONS_SHEAR):
{
transformationsShear();
break;
}
case(FILTERS_BLUR):
{
filtersBlur();
break;
}
case(FILTERS_SHARPEN):
{
filtersSharpen();
break;
}
case(FILTERS_EDGEDETECTION):
{
filtersEdgeDetection();
break;
}
case(FILTERS_EMBOSS):
{
filtersEmboss();
break;
}
case(FILTERS_PSYCHEDELICDISTILLATION):
{
filtersPsychedelicDistillation();
break;
}
case(FILTERS_LITHOGRAPH):
{
filtersLithograph();
break;
}
case(FILTERS_HORIZONTALSOBEL):
{
filtersHorizontalSobel();
break;
}
case(FILTERS_VERTICALSOBEL):
{
filtersVerticalSobel();
break;
}
case(FILTERS_HORIZONTALPREWITT):
{
filtersHorizontalPrewitt();
break;
}
case(FILTERS_VERTICALPREWITT):
{
filtersVerticalPrewitt();
break;
}
case(FILTERS_MINIMUM):
{
filtersMinimum();
break;
}
case(FILTERS_MAXIMUM):
{
filtersMaximum();
break;
}
case(FILTERS_MEDIAN):
{
filtersMedian();
break;
}
case(FILTERS_MEAN):
{
filtersMean();
break;
}
case(FILTERS_OIL):
{
filtersOil();
break;
}
case(VIEW_ZOOMIN):
{
viewZoomIn();
break;
}
case(VIEW_ZOOMOUT):
{
viewZoomOut();
break;
}
case(VIEW_SETORIGINALSIZE):
{
viewSetOriginalSize();
break;
}
case(VIEW_INTERPOLATIONTYPE_NEARESTNEIGHBOR):
{
viewInterpolationTypeNearestNeighbor();
break;
}
case(VIEW_INTERPOLATIONTYPE_BILINEAR):
{
viewInterpolationTypeBilinear();
break;
}
case(VIEW_INTERPOLATIONTYPE_BICUBIC):
{
viewInterpolationTypeBicubic();
break;
}
case(HELP_ABOUT):
{
helpAbout();
break;
}
case(HELP_SYSTEMINFORMATION):
{
helpSystemInformation();
break;
}
default:
{
// error?
break;
}
}
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/apps/MenuIndexConstants.java 0000664 0000000 0000000 00000006244 10404065314 025430 0 ustar /*
* MenuIndexConstants
*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.apps;
/**
* Constant int values for all menu items.
* Some of these menu items denote operations which can be performed by
* {@link OperationProcessor}.
*
* @author Marco Schmidt
*/
public interface MenuIndexConstants
{
int FILE = 0;
int FILE_OPEN = 1;
int FILE_SAVEAS = 2;
int FILE_SAVEAS_GIF = 83;
int FILE_SAVEAS_PALM = 81;
int FILE_SAVEAS_PBM = 3;
int FILE_SAVEAS_PGM = 4;
int FILE_SAVEAS_PNG = 82;
int FILE_SAVEAS_PPM = 5;
int FILE_SAVEAS_SUNRASTER = 6;
int FILE_SAVEAS_WINDOWSBMP = 7;
int FILE_IMAGE_1 = 84;
int FILE_CLOSE = 8;
int FILE_EXIT = 9;
int EDIT = 67;
int EDIT_UNDO = 68;
int EDIT_REDO = 69;
int COLOR = 10;
int COLOR_ADJUST = 11;
int COLOR_ADJUST_BRIGHTNESS = 12;
int COLOR_ADJUST_CONTRAST = 13;
int COLOR_ADJUST_GAMMA = 14;
int COLOR_ADJUST_HUESATURATIONVALUE = 15;
int COLOR_HISTOGRAM = 16;
int COLOR_HISTOGRAM_COUNTCOLORSUSED = 17;
int COLOR_HISTOGRAM_EQUALIZE = 18;
int COLOR_HISTOGRAM_NORMALIZE = 19;
int COLOR_HISTOGRAM_TEXTUREPROPERTIES = 70;
int COLOR_HISTOGRAM_SAVEHISTOGRAMAS = 66;
int COLOR_HISTOGRAM_SAVECOOCCURRENCEMATRIXAS = 20;
int COLOR_HISTOGRAM_SAVECOOCCURRENCEFREQUENCYMATRIXAS = 21;
int COLOR_PALETTE = 22;
int COLOR_PALETTE_SAVEAS = 23;
int COLOR_PROMOTE = 24;
int COLOR_PROMOTE_PROMOTETOPALETTED = 25;
int COLOR_PROMOTE_PROMOTETOGRAY8 = 26;
int COLOR_PROMOTE_PROMOTETOGRAY16 = 27;
int COLOR_PROMOTE_PROMOTETORGB24 = 28;
int COLOR_PROMOTE_PROMOTETORGB48 = 29;
int COLOR_REDUCE = 30;
int COLOR_REDUCE_REDUCETOBILEVELTHRESHOLD = 31;
int COLOR_REDUCE_REDUCENUMBEROFSHADESOFGRAY = 32;
int COLOR_REDUCE_CONVERTTOGRAYSCALE = 33;
int COLOR_REDUCE_MEDIANCUT = 34;
int COLOR_REDUCE_OCTREE = 35;
int COLOR_REDUCE_UNIFORMPALETTE = 36;
int COLOR_REDUCE_MAPTOARBITRARYPALETTE = 37;
int COLOR_INVERT = 38;
int COLOR_CONVERTTOMINIMUMCOLORTYPE = 39;
int TRANSFORMATIONS = 40;
int TRANSFORMATIONS_FLIP = 41;
int TRANSFORMATIONS_MIRROR = 42;
int TRANSFORMATIONS_ROTATELEFT90 = 43;
int TRANSFORMATIONS_ROTATERIGHT90 = 44;
int TRANSFORMATIONS_ROTATE180 = 45;
int TRANSFORMATIONS_CROP = 46;
int TRANSFORMATIONS_SCALE = 47;
int TRANSFORMATIONS_SHEAR = 48;
int FILTERS = 49;
int FILTERS_BLUR = 50;
int FILTERS_SHARPEN = 51;
int FILTERS_EDGEDETECTION = 52;
int FILTERS_EMBOSS = 53;
int FILTERS_PSYCHEDELICDISTILLATION = 54;
int FILTERS_LITHOGRAPH = 55;
int FILTERS_HORIZONTALSOBEL = 56;
int FILTERS_VERTICALSOBEL = 57;
int FILTERS_HORIZONTALPREWITT = 58;
int FILTERS_VERTICALPREWITT = 59;
int FILTERS_MINIMUM = 71;
int FILTERS_MAXIMUM = 72;
int FILTERS_MEDIAN = 60;
int FILTERS_MEAN = 61;
int FILTERS_OIL = 62;
int VIEW = 73;
int VIEW_ZOOMIN = 74;
int VIEW_ZOOMOUT = 75;
int VIEW_SETORIGINALSIZE = 76;
int VIEW_INTERPOLATIONTYPE = 77;
int VIEW_INTERPOLATIONTYPE_NEARESTNEIGHBOR = 78;
int VIEW_INTERPOLATIONTYPE_BILINEAR = 79;
int VIEW_INTERPOLATIONTYPE_BICUBIC = 80;
int HELP = 63;
int HELP_ABOUT = 64;
int HELP_SYSTEMINFORMATION = 65;
int NUM_CONSTANTS = 85;
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/apps/EditorState.java 0000664 0000000 0000000 00000032346 07741250130 024072 0 ustar /*
* EditorState
*
* Copyright (c) 2000, 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.apps;
import java.io.IOException;
import java.util.Locale;
import java.util.Vector;
import net.sourceforge.jiu.data.PixelImage;
import net.sourceforge.jiu.ops.Operation;
import net.sourceforge.jiu.ops.ProgressListener;
/**
* Represents the state of the editor, including image(s), modified flag,
* current file name and directories and more.
* This class must not know GUI-specific information like Frame or JFrame objects.
* These GUI classes (more precisely, the JIU classes that extend them) will have to
* know EditorState and update according to the information they retrieve from an
* EditorState object associated with them.
* EditorState is a pure data container.
* @author Marco Schmidt
*/
public class EditorState implements MenuIndexConstants
{
/**
* The default number of undo steps possible.
*/
public static final int DEFAULT_MAX_UNDO_IMAGES = 2;
/**
* The default number of redo steps possible.
*/
public static final int DEFAULT_MAX_REDO_IMAGES = DEFAULT_MAX_UNDO_IMAGES;
/**
* All allowed zoom levels, as percentage values in ascending order.
*/
public static final int[] ZOOM_LEVELS = {5, 7, 10, 15, 20, 30, 50, 70, 100, 150, 200, 300, 500, 700, 1000, 2000, 3000, 5000};
/**
* The index into the {@link #ZOOM_LEVELS} array that holds the original size zoom level (100 percent).
* So, ZOOM_LEVELS[ORIGINAL_SIZE_ZOOM_INDEX] must be equal to 100.
*/
public static final int ORIGINAL_SIZE_ZOOM_INDEX = 8;
/**
* Integer constant for nearest neighbor interpolation.
* A fast but ugly method.
*/
public static final int INTERPOLATION_NEAREST_NEIGHBOR = 0;
/**
* Integer constant for bilinear neighbor interpolation.
* A slow but nice method.
*/
public static final int INTERPOLATION_BILINEAR = 1;
/**
* Integer constant for bicubic interpolation.
* A very slow method, but with the nicest output of the three supported interpolation types.
*/
public static final int INTERPOLATION_BICUBIC = 2;
/**
* The default interpolation type, one of the three INTERPOLATION_xyz constants.
*/
public static final int DEFAULT_INTERPOLATION = INTERPOLATION_NEAREST_NEIGHBOR;
private String currentDirectory;
private String fileName;
private PixelImage currentImage;
private int interpolation;
private Locale locale;
private int maxRedoImages;
private int maxUndoImages;
private boolean modified;
private Vector progressListeners;
private Vector redoImages;
private Vector redoModified;
private String startupImageName;
private Strings strings;
private Vector undoImages;
private Vector undoModified;
private int zoomIndex = ORIGINAL_SIZE_ZOOM_INDEX;
private double zoomFactorX;
private double zoomFactorY;
private boolean zoomToFit;
/**
* Create new EditorState object and initialize its private fields
* to default values.
*/
public EditorState()
{
locale = Locale.getDefault();
setStrings(null);
progressListeners = new Vector();
maxRedoImages = DEFAULT_MAX_REDO_IMAGES;
maxUndoImages = DEFAULT_MAX_UNDO_IMAGES;
redoImages = new Vector(maxRedoImages);
redoModified = new Vector(maxRedoImages);
undoImages = new Vector(maxUndoImages);
undoModified = new Vector(maxUndoImages);
zoomFactorX = 1.0;
zoomFactorY = 1.0;
zoomToFit = false;
}
private void addImageToRedo(PixelImage image, boolean modifiedState)
{
if (maxRedoImages < 1)
{
return;
}
if (redoImages.size() == maxRedoImages)
{
redoImages.setElementAt(null, 0);
redoImages.removeElementAt(0);
redoModified.removeElementAt(0);
}
redoImages.addElement(image);
redoModified.addElement(new Boolean(modifiedState));
}
private void addImageToUndo(PixelImage image, boolean modifiedState)
{
if (maxUndoImages < 1)
{
return;
}
if (undoImages.size() == maxUndoImages)
{
undoImages.setElementAt(null, 0);
undoImages.removeElementAt(0);
undoModified.removeElementAt(0);
}
undoImages.addElement(image);
undoModified.addElement(new Boolean(modifiedState));
}
/**
* Adds the argument progress listener to the internal list of progress
* listeners to be notified by progress updates.
* @param pl object implementing ProgressListener to be added
*/
public void addProgressListener(ProgressListener pl)
{
progressListeners.addElement(pl);
}
/**
* Returns if a redo operation is possible right now.
*/
public boolean canRedo()
{
return (redoImages.size() > 0);
}
/**
* Returns if an undo operation is possible right now.
*/
public boolean canUndo()
{
return (undoImages.size() > 0);
}
public void clearRedo()
{
int index = 0;
while (index < redoImages.size())
{
redoImages.setElementAt(null, index++);
}
redoImages.setSize(0);
redoModified.setSize(0);
}
public void clearUndo()
{
int index = 0;
while (index < undoImages.size())
{
undoImages.setElementAt(null, index++);
}
undoImages.setSize(0);
undoModified.setSize(0);
}
public void ensureStringsAvailable()
{
if (getStrings() == null)
{
setStrings(Strings.DEFAULT_LANGUAGE_ISO_639_CODE);
}
}
/**
* Returns the current directory.
* This directory will be used when file dialogs are opened.
*/
public String getCurrentDirectory()
{
return currentDirectory;
}
/**
* Returns the name of the file from which the current image was loaded.
*/
public String getFileName()
{
return fileName;
}
/**
* Returns the image object currently loaded.
*/
public PixelImage getImage()
{
return currentImage;
}
/**
* Returns the current interpolation type, one of the INTERPOLATION_xyz constants.
*/
public int getInterpolation()
{
return interpolation;
}
/**
* Returns the Locale object currently used.
*/
public Locale getLocale()
{
return locale;
}
/**
* Returns the current modified state (true if image was modified and not saved
* after modification, false otherwise).
*/
public boolean getModified()
{
return modified;
}
/**
* Returns the internal list of progress listeners.
*/
public Vector getProgressListeners()
{
return progressListeners;
}
public String getStartupImageName()
{
return startupImageName;
}
/**
* Returns the Strings object currently in use.
*/
public Strings getStrings()
{
return strings;
}
/**
* Returns the current zoom factor in horizontal direction.
* The value 1.0 means that the image is displayed at its
* original size.
* Anything smaller means that the image is scaled down,
* anything larger means that the image is scaled up.
* The value must not be smaller than or equal to 0.0.
* @return zoom factor in horizontal direction
* @see #getZoomFactorY
*/
public double getZoomFactorX()
{
return zoomFactorX;
}
/**
* Returns the current zoom factor in vertical direction.
* The value 1.0 means that the image is displayed at its
* original size.
* Anything smaller means that the image is scaled down,
* anything larger means that the image is scaled up.
* The value must not be smaller than or equal to 0.0.
* @return zoom factor in vertical direction
* @see #getZoomFactorX
*/
public double getZoomFactorY()
{
return zoomFactorY;
}
/**
* Returns if image display is currently set to "zoom to fit"
* Zoom to fit means that the image is always zoomed to fit exactly into the window.
*/
public boolean getZoomToFit()
{
return zoomToFit;
}
/**
* Returns if this state encapsulates an image object.
*/
public boolean hasImage()
{
return (currentImage != null);
}
/**
* Adds all ProgressListener objects from the internal list of listeners to
* the argument operation.
*/
public void installProgressListeners(Operation op)
{
if (op == null)
{
return;
}
// cannot use Iterator because it's 1.2+
int index = 0;
while (index < progressListeners.size())
{
ProgressListener pl = (ProgressListener)progressListeners.elementAt(index++);
op.addProgressListener(pl);
}
}
/**
* Returns if the image is displayed at maximum zoom level.
*/
public boolean isMaximumZoom()
{
return zoomIndex == ZOOM_LEVELS.length - 1;
}
/**
* Returns if the image is displayed at minimum zoom level.
*/
public boolean isMinimumZoom()
{
return zoomIndex == 0;
}
/**
* Returns if the current zoom level is set to original size
* (each image pixel is displayed as one pixel).
*/
public boolean isZoomOriginalSize()
{
return zoomIndex == ORIGINAL_SIZE_ZOOM_INDEX;
}
/**
* Perform a redo operation, restore the state before the last undo operation.
* Before that is done, save the current state for an undo.
*/
public void redo()
{
if (redoImages.size() < 1)
{
return;
}
addImageToUndo(currentImage, modified);
int redoIndex = redoImages.size() - 1;
currentImage = (PixelImage)redoImages.elementAt(redoIndex);
redoImages.setElementAt(null, redoIndex);
redoImages.setSize(redoIndex);
modified = ((Boolean)redoModified.elementAt(redoIndex)).booleanValue();
redoModified.setSize(redoIndex);
}
public void resetZoomFactors()
{
setZoomFactors(1.0, 1.0);
}
/**
* Sets a new current directory.
* @param newCurrentDirectory the directory to be used as current directory from now on
*/
public void setCurrentDirectory(String newCurrentDirectory)
{
currentDirectory = newCurrentDirectory;
}
/**
* Sets a new file name.
* This is used mostly after a new image was loaded from a file or
* if the current image is closed (then a null value would be given to this method).
* @param newFileName new name of the current file
*/
public void setFileName(String newFileName)
{
fileName = newFileName;
}
/**
* Sets image and modified state to argument values.
* @param image new current image
* @param newModifiedState new state of modified flag
*/
public void setImage(PixelImage image, boolean newModifiedState)
{
if (hasImage())
{
addImageToUndo(currentImage, modified);
}
currentImage = image;
modified = newModifiedState;
clearRedo();
}
public void setStartupImageName(String name)
{
startupImageName = name;
}
/**
* Sets a new interpolation type to be used for display.
* @param newInterpolation an int for the interpolation type, must be one of the INTERPOLATION_xyz constants
*/
public void setInterpolation(int newInterpolation)
{
if (newInterpolation == INTERPOLATION_NEAREST_NEIGHBOR ||
newInterpolation == INTERPOLATION_BILINEAR ||
newInterpolation == INTERPOLATION_BICUBIC)
{
interpolation = newInterpolation;
}
}
/**
* Defines a new Locale to be used.
* @param newLocale Locale object used from now on
* @see #setStrings
*/
public void setLocale(Locale newLocale)
{
locale = newLocale;
}
/*public void setModified(boolean modifiedState)
{
modified = modifiedState;
}*/
/**
* Set new Strings resource.
* @param iso639Code language of the new Strings resource
*/
public void setStrings(String iso639Code)
{
Strings newStrings = null;
try
{
StringLoader loader;
if (iso639Code == null)
{
loader = new StringLoader();
}
else
{
loader = new StringLoader(iso639Code);
}
newStrings = loader.load();
}
catch (IOException ioe)
{
}
if (newStrings != null)
{
strings = newStrings;
}
}
/**
* Sets the zoom factors to the argument values.
*/
public void setZoomFactors(double zoomX, double zoomY)
{
zoomFactorX = zoomX;
zoomFactorY = zoomY;
}
/**
* Perform an undo step - the previous state will be set, the
* current state will be saved for a redo operation
* @see #redo
*/
public void undo()
{
if (undoImages.size() < 1)
{
return;
}
addImageToRedo(currentImage, modified);
int undoIndex = undoImages.size() - 1;
currentImage = (PixelImage)undoImages.elementAt(undoIndex);
undoImages.setElementAt(null, undoIndex);
undoImages.setSize(undoIndex);
modified = ((Boolean)undoModified.elementAt(undoIndex)).booleanValue();
undoModified.setSize(undoIndex);
}
/**
* Increase the zoom level by one.
* @see #zoomOut
* @see #zoomSetOriginalSize
*/
public void zoomIn()
{
if (zoomIndex + 1 == ZOOM_LEVELS.length)
{
return;
}
zoomIndex++;
zoomFactorX = 1.0 * ZOOM_LEVELS[zoomIndex] / 100;
zoomFactorY = zoomFactorX;
}
/**
* Decrease the zoom level by one.
* @see #zoomIn
* @see #zoomSetOriginalSize
*/
public void zoomOut()
{
if (zoomIndex == 0)
{
return;
}
zoomIndex--;
zoomFactorX = 1.0 * ZOOM_LEVELS[zoomIndex] / 100;
zoomFactorY = zoomFactorX;
}
/**
* Set the zoom level to 100 percent (1:1).
* Each image pixel will be displayed as one pixel
* @see #zoomIn
* @see #zoomOut
*/
public void zoomSetOriginalSize()
{
zoomIndex = ORIGINAL_SIZE_ZOOM_INDEX;
zoomFactorX = 1.0;
zoomFactorY = 1.0;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/apps/JiuBlur.java 0000664 0000000 0000000 00000002156 10612170500 023204 0 ustar /*
* JiuBlur
*
* Copyright (c) 2007 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.apps;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import net.sourceforge.jiu.color.adjustment.Contrast;
import net.sourceforge.jiu.data.PixelImage;
import net.sourceforge.jiu.filters.ConvolutionKernelFilter;
import net.sourceforge.jiu.gui.awt.ImageCreator;
import net.sourceforge.jiu.gui.awt.ToolkitLoader;
/**
* Small example command line program which loads a JPEG file,
* applies a blur filter, increases its contrast and saves it
* back to another JPEG file.
* @author Marco Schmidt
* @since 0.14.2
*/
public class JiuBlur
{
public static void main(String[] args) throws Exception
{
PixelImage image = ToolkitLoader.loadAsRgb24Image("resources/images/image1.jpg");
image = Contrast.adjust(image, 20);
image = ConvolutionKernelFilter.filter(image, ConvolutionKernelFilter.TYPE_BLUR);
BufferedImage awtImage = ImageCreator.convertToAwtBufferedImage(image);
ImageIO.write(awtImage, "jpg", new File("out-image1.jpg"));
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/apps/JiuHelloWorld.java 0000664 0000000 0000000 00000002751 10611710711 024357 0 ustar /*
* JiuHelloWorld
*
* Copyright (c) 2007 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.apps;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import net.sourceforge.jiu.codecs.CodecMode;
import net.sourceforge.jiu.codecs.PNGCodec;
import net.sourceforge.jiu.data.RGB24Image;
import net.sourceforge.jiu.gui.awt.ImageCreator;
/**
* Small example command line program which creates a new image,
* prints the text Hello World! into it and saves it as
* a PNG file.
* @author Marco Schmidt
* @since 0.14.2
*/
public class JiuHelloWorld
{
public static void main(String[] args) throws Exception
{
// AWT image creation
BufferedImage awtImage = new BufferedImage(100, 30, BufferedImage.TYPE_INT_RGB);
Graphics graphics = awtImage.getGraphics();
// fill image with red
graphics.setColor(Color.RED);
graphics.fillRect(0, 0, awtImage.getWidth(), awtImage.getHeight());
// draw on it in white
graphics.setColor(Color.WHITE);
graphics.drawString("Hello World!", 5, 15);
// conversion AWT image to JIU image
RGB24Image jiuImage = ImageCreator.convertImageToRGB24Image(awtImage);
// saving JIU image to file
PNGCodec codec = new PNGCodec();
codec.setImage(jiuImage);
codec.appendComment("Hello World! as a text comment; " +
"see http://schmidt.devlib.org/jiu/introduction.html");
codec.setFile("jiu-hello-world.png", CodecMode.SAVE);
codec.process();
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/apps/StringLoader.java 0000664 0000000 0000000 00000003220 10212515720 024221 0 ustar /*
* StringLoader
*
* Copyright (c) 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.apps;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Vector;
/**
* This class loads a {@link Strings} resource from a text file.
* The text file must contain one
* @author Marco Schmidt
* @since 0.12.0
*/
public class StringLoader
{
private BufferedReader in;
private Integer langCode;
/**
* The directory of language resource files, default:
* /resources/lang/
.
*/
public static String resourceDirectory = "/resources/lang/";
public StringLoader()
{
this(Strings.determineSuitableIsoCode());
}
public StringLoader(String iso639Code)
{
InputStream input = getClass().getResourceAsStream(resourceDirectory + iso639Code + ".txt");
if (input == null && !"en".equals(iso639Code))
{
input = getClass().getResourceAsStream(resourceDirectory + "en.txt");
}
if (input == null)
{
return;
}
in = new BufferedReader(new InputStreamReader(input));
langCode = Strings.findLanguageCode(iso639Code);
}
public Strings load() throws IOException
{
if (in == null)
{
return null;
}
Vector list = new Vector();
String line;
while ((line = in.readLine()) != null)
{
list.addElement(line);
}
if (list.size() < 1)
{
return null;
}
String[] data = new String[list.size()];
for (int i = 0; i < list.size(); i++)
{
data[i] = (String)list.elementAt(i);
}
in.close();
return new Strings(langCode, data);
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/apps/jiuawtapplet.java 0000664 0000000 0000000 00000001615 10421163206 024343 0 ustar /*
* jiuawtapplet
*
* Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.apps;
import java.applet.Applet;
import net.sourceforge.jiu.gui.awt.JiuAwtFrame;
/**
* Applet version of jiuawt.
* Not really useful because no images can be loaded.
* @author Marco Schmidt
*/
public class jiuawtapplet extends Applet implements JiuInfo
{
private static final long serialVersionUID = 93423883004L;
public String getAppletInfo()
{
return "jiuawtapplet" +
"; demo applet for the Java Imaging Utilities" +
"; feedback address: " + JIU_FEEDBACK_ADDRESS +
"; homepage: " + JIU_HOMEPAGE;
}
public void init()
{
EditorState state = new EditorState();
state.setStrings(null);
new JiuAwtFrame(state);
}
public void start()
{
}
public void stop()
{
System.exit(0);
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/apps/package.html 0000664 0000000 0000000 00000000353 07741250130 023252 0 ustar
Smaller and larger applications demonstrating how to use JIU.
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/apps/ImageDescriptionCreator.java 0000664 0000000 0000000 00000006473 10523755041 026416 0 ustar /* * ImageDescriptionCreator * * Copyright (c) 2002, 2003, 2004, 2005, 2006 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.apps; import java.text.NumberFormat; import java.util.Locale; import net.sourceforge.jiu.data.PixelImage; import net.sourceforge.jiu.data.BilevelImage; import net.sourceforge.jiu.data.GrayImage; import net.sourceforge.jiu.data.PalettedImage; import net.sourceforge.jiu.data.RGBImage; /** * Returns textual descriptions of the properties of JIU image objects. * @author Marco Schmidt * @since 0.9.0 */ public class ImageDescriptionCreator { /*private static final int TYPE = 0; private static final int PIXELS = 1; private static final int IMAGE_TYPE_BILEVEL = 2; private static final int IMAGE_TYPE_GRAYSCALE = 3; private static final int IMAGE_TYPE_PALETTED = 4; private static final int IMAGE_TYPE_RGB_TRUECOLOR = 5; private static final int IMAGE_TYPE_UNKNOWN = 6; private static final int BITS_PER_PIXEL = 7; private static final int MEMORY = 8; private static final int DISK_SPACE = 9;*/ private ImageDescriptionCreator() { } private static String formatNumber(long value, Locale locale) { if (locale == null) { return Long.toString(value); } else { return NumberFormat.getInstance(locale).format(value); } } /** * Returns a description of the argument image using the default locale. */ /*public static String getDescription(PixelImage image) { return getDescription(image, Locale.getDefault()); }*/ /** * Returns a description of the argument image using the language * as specified by the argument locale's two-letter language code. * @param image the image for which a textual description is to be returned * @param locale the Locale storing the natural language to be used for formatting * @return a textual description of the image */ public static String getDescription(PixelImage image, Locale locale, Strings strings) { StringBuffer result = new StringBuffer(); result.append(strings.get(StringIndexConstants.IMAGE_TYPE)); result.append(": "); result.append(strings.get(getImageType(image))); result.append(", "); result.append(strings.get(StringIndexConstants.PIXELS)); result.append(": "); int width = image.getWidth(); int height = image.getHeight(); result.append(formatNumber(width, locale)); result.append(" x "); result.append(formatNumber(height, locale)); result.append(" ("); result.append(formatNumber(width * height, locale)); result.append("), "); result.append(strings.get(StringIndexConstants.BITS_PER_PIXEL)); result.append(": "); result.append(formatNumber(image.getBitsPerPixel(), locale)); return result.toString(); } private static int getImageType(PixelImage image) { int stringIndex = StringIndexConstants.IMAGE_TYPE_UNKNOWN; if (image instanceof BilevelImage) { return stringIndex = StringIndexConstants.BILEVEL; } else if (image instanceof GrayImage) { return stringIndex = StringIndexConstants.GRAYSCALE; } else if (image instanceof PalettedImage) { return stringIndex = StringIndexConstants.PALETTED; } else if (image instanceof RGBImage) { return stringIndex = StringIndexConstants.RGB_TRUECOLOR; } return stringIndex; } } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/apps/ImageLoadTester.java 0000664 0000000 0000000 00000007402 07741250130 024647 0 ustar /* * ImageLoadTester * * Copyright (c) 2003 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.apps; import java.io.File; import net.sourceforge.jiu.codecs.ImageLoader; import net.sourceforge.jiu.data.PixelImage; import net.sourceforge.jiu.gui.awt.ToolkitLoader; import net.sourceforge.jiu.ops.BatchProcessorOperation; /** * Command line program that tries to load images from files, * thus testing the built-in and / or Toolkit's codecs. * Start the program with file names or directory names as arguments. * Directory names will lead to the inclusion of that complete directory tree * in the list of files to test. * Add the argument--notoolkit
in order to keep this
* program from trying to load images via java.awt.Toolkit.
* The program will process all files and print one line per file
* that tells the result of the loading process.
* At the end, three lines with statistics (failed / successful / total
* loading attempts) are printed.
* Note that you may want to give the JVM more memory if large images
* are stored in those files you want to test.
* Example:
* java -mx300m net.sourceforge.jiu.apps.ImageLoadTester *.jpg* This gives 300 MB to the JVM. * @author Marco Schmidt * @since 0.11.0 */ public class ImageLoadTester extends BatchProcessorOperation { private boolean useToolkit; private int numFailed; private int numSuccess; /** * Main method of this command line program. * @param args program arguments, provided by the Java Virtual Machine, must be file or directory names */ public static void main(String[] args) throws Exception { ImageLoadTester tester = new ImageLoadTester(); boolean useToolkit = true; for (int i = 0; i < args.length; i++) { String name = args[i]; if ("--notoolkit".equals(name)) { useToolkit = false; } else { File file = new File(name); if (file.isFile()) { tester.addInputFileName(name); } else if (file.isDirectory()) { tester.addDirectoryTree(name); } } } tester.setUseToolkit(useToolkit); tester.process(); int total = (tester.numFailed + tester.numSuccess); System.out.println("OK: " + tester.numSuccess + " (" + tester.numSuccess * 100.0 / total + " %)"); System.out.println("Failed: " + tester.numFailed + " (" + tester.numFailed * 100.0 / total + " %)"); System.out.println("Total: " + total + " (100.0 %)"); } /** * Tries to load an image from a file. * Prints a message to standard output and increases certain internal counters * for statistics. * @param inputDirectory directory where the file resides * @param inputFileName name of file * @param outputDirectory not used, this argument is demanded by the parent class+ */ public void processFile(String inputDirectory, String inputFileName, String outputDirectory) { File file = new File(inputDirectory, inputFileName); String name = file.getAbsolutePath(); System.out.print(name); PixelImage image; try { if (useToolkit) { image = ToolkitLoader.loadViaToolkitOrCodecs(name, true, null); } else { image = ImageLoader.load(name); } } catch (Exception e) { image = null; } if (image == null) { numFailed++; System.out.println(" Failed."); } else { numSuccess++; System.out.println(" OK. Width=" + image.getWidth() + ", height=" + image.getHeight() + " pixels."); } } /** * Specifies whether java.awt.Toolkit is supposed to be used when * trying to load an image. * @param newValue boolean, true if Toolkit is to be used, false otherwise */ public void setUseToolkit(boolean newValue) { useToolkit = newValue; } } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/apps/JiuCountColors.java 0000664 0000000 0000000 00000001523 10612171071 024553 0 ustar /* * JiuCountColors * * Copyright (c) 2007 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.apps; import net.sourceforge.jiu.color.analysis.Histogram3DCreator; import net.sourceforge.jiu.data.RGB24Image; import net.sourceforge.jiu.gui.awt.ToolkitLoader; /** * Small example command line program to count the number of * unique colors in image files. * @author Marco Schmidt * @since 0.14.2 */ public class JiuCountColors { public static void main(String[] args) throws Exception { String[] FILE_NAMES = {"jiu-hello-world.png", "resources/images/image1.jpg", "out-image1.jpg"}; for (int i = 0; i < FILE_NAMES.length; i++) { RGB24Image image = ToolkitLoader.loadAsRgb24Image(FILE_NAMES[i]); System.out.println(FILE_NAMES[i] + "\t" + Histogram3DCreator.count(image)); } } } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/apps/ColorIndexer.java 0000664 0000000 0000000 00000013172 10523754542 024244 0 ustar /* * ColorIndexer * * Copyright (c) 2003 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.apps; import java.io.File; import java.text.DecimalFormat; import java.text.NumberFormat; import net.sourceforge.jiu.color.adjustment.Contrast; import net.sourceforge.jiu.color.promotion.PromotionRGB24; import net.sourceforge.jiu.data.PixelImage; import net.sourceforge.jiu.data.RGB24Image; import net.sourceforge.jiu.data.RGBIndex; import net.sourceforge.jiu.geometry.Resample; import net.sourceforge.jiu.gui.awt.ToolkitLoader; import net.sourceforge.jiu.ops.BatchProcessorOperation; import net.sourceforge.jiu.ops.OperationFailedException; /** * Loads image files and generates color index information for them. * @author Marco Schmidt * @since 0.12.0 */ public class ColorIndexer extends BatchProcessorOperation { private int maxLength = 256; private int contrastChange = 100; private NumberFormat formatter = new DecimalFormat("#.##"); public static final int BLACK = 0; public static final int RED = 4; public static final int GREEN = 2; public static final int BLUE = 1; public static final int YELLOW = 6; public static final int MAGENTA = 5; public static final int CYAN = 3; public static final int WHITE = 7; public static final String[] COLOR_NAMES = {"black", "blue", "green", "cyan", "red", "magenta", "yellow", "white"}; public static void main(String[] args) { ColorIndexer indexer = new ColorIndexer(); for (int i = 0; i < args.length; i++) { String name = args[i]; File file = new File(name); if (file.isFile()) { indexer.addInputFileName(name); } else if (file.isDirectory()) { indexer.addDirectoryTree(name); } } indexer.process(); System.out.println("Done."); } private PixelImage convertToRgb24(PixelImage in) { if (in == null) { return null; } if (in instanceof RGB24Image) { return in; } try { PromotionRGB24 pr = new PromotionRGB24(); pr.setInputImage(in); pr.process(); return pr.getOutputImage(); } catch (OperationFailedException ofe) { return null; } } private PixelImage adjustColor(PixelImage img) { if (img == null || contrastChange == 0) { return img; } try { Contrast con = new Contrast(); con.setInputImage(img); con.setContrast(contrastChange); con.process(); return con.getOutputImage(); /* HueSaturationValue hsv = new HueSaturationValue(); hsv.setInputImage(img); hsv.setSaturationValue(30, 0); hsv.process(); return hsv.getOutputImage();*/ } catch (OperationFailedException ofe) { return null; } } private PixelImage scale(PixelImage in) { if (in == null) { return null; } if (in.getWidth() <= maxLength && in.getHeight() <= maxLength) { return in; } try { Resample res = new Resample(); res.setFilter(Resample.FILTER_TYPE_LANCZOS3); res.setInputImage(in); float thumbRatio = 1.0f; float imageRatio = (float)in.getWidth() / (float)in.getHeight(); int width = maxLength; int height = maxLength; if (thumbRatio < imageRatio) { height = (int)(maxLength / imageRatio); } else { width = (int)(maxLength * imageRatio); } //float x = (float)in.getWidth() / maxLength; //float y = (float)in.getHeight() / maxLength; res.setSize(width, height); res.process(); return res.getOutputImage(); } catch (OperationFailedException ofe) { return null; } } private int[] count(PixelImage image) { if (image == null) { return null; } RGB24Image in = (RGB24Image)image; int[] result = new int[8]; for (int y = 0; y < image.getHeight(); y++) { for (int x = 0; x < image.getWidth(); x++) { int red = in.getSample(RGBIndex.INDEX_RED, x, y) >> 7; int green = in.getSample(RGBIndex.INDEX_GREEN, x, y) >> 7; int blue = in.getSample(RGBIndex.INDEX_BLUE, x, y) >> 7; int index = (red << 2) | (green << 1) | blue; result[index]++; } } return result; } /*private void save(PixelImage img, String fileName) { PNGCodec codec = new PNGCodec(); try { codec.setImage(img); codec.setFile(fileName, CodecMode.SAVE); codec.process(); codec.close(); } catch (OperationFailedException ofe) { } catch (IOException ioe) { } }*/ private void store(String name, int[] occ) { if (name == null || occ == null) { return; } int sum = 0; for (int i = 0; i < occ.length; i++) { sum += occ[i]; } System.out.print(name); System.out.print(';'); for (int i = 0; i < occ.length; i++) { float rel = (float)occ[i] / sum; if (rel < 0.01f) { continue; } System.out.print(COLOR_NAMES[i] + " = " + formatter.format(rel) + ";"); } System.out.println(); } public void processFile(String inputDirectory, String inputFileName, String outputDirectory) { File dir = new File(inputDirectory); File file = new File(dir, inputFileName); String name = file.getAbsolutePath(); // load image PixelImage image = ToolkitLoader.loadViaToolkitOrCodecs(name); // convert to RGB24 if necessary image = convertToRgb24(image); // scale down if necessary image = scale(image); // increase contrast image = adjustColor(image); // save the modified image, for testing purposes /*File outFile = new File("f:\\", "th_" + inputFileName + ".png"); save(image, outFile.getAbsolutePath());*/ // determine occurrence of colors int[] occur = count(image); // store store(name, occur); } } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/apps/jiuawt.java 0000664 0000000 0000000 00000007435 07741250130 023147 0 ustar /* * jiuawt * * Copyright (c) 2000, 2001, 2002, 2003 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.apps; import net.sourceforge.jiu.apps.EditorState; import net.sourceforge.jiu.gui.awt.JiuAwtFrame; import net.sourceforge.jiu.util.SystemInfo; /** * Graphical user interface application based on the AWT (Abstract * Windowing Toolkit, part of Java's standard runtime library since 1.0) * that demonstrates features of JIU. *
*
java -mx300m jiu.jar* starts jiuawt and provides it with 300 MB of memory. * *
--dir DIRECTORY
* DIRECTORY
* --help
* --lang LANGUAGE
* LANGUAGE
, where en
is English, de
is German and es
is Spanish
* --system
* --version
* --help
as single argument to get a help screen
*/
public static void main(String[] args)
{
EditorState state = new EditorState();
int index = 0;
while (index < args.length)
{
String s = args[index++];
if ("--dir".equals(s))
{
if (index == args.length)
{
throw new IllegalArgumentException("Directory switch must be followed by a directory name.");
}
state.setCurrentDirectory(args[index++]);
}
else
if ("--help".equals(s))
{
printVersion();
System.out.println();
System.out.println("Usage: jiuawt [OPTIONS] [FILE]");
System.out.println("\tFILE is the name of an image file to be loaded after start-up");
System.out.println("\t--dir DIRECTORY set working directory to DIRECTORY");
System.out.println("\t--help print this help screen and exit");
System.out.println("\t--lang LANGCODE set language to LANGCODE (de=German, en=English, es=Spanish)");
System.out.println("\t--system print system info and exit");
System.out.println("\t--version print version information and exit");
System.exit(0);
}
else
if ("--lang".equals(s))
{
if (index == args.length)
{
throw new IllegalArgumentException("Language switch must be followed by language code.");
}
state.setStrings(args[index++]);
}
else
if ("--system".equals(s))
{
String info = SystemInfo.getSystemInfo(state.getStrings());
System.out.println(info);
System.exit(0);
}
else
if ("--version".equals(s))
{
printVersion();
System.exit(0);
}
else
{
if (s.startsWith("-"))
{
throw new IllegalArgumentException("Unknown switch: " + s);
}
else
{
state.setStartupImageName(s);
}
}
}
state.ensureStringsAvailable();
new JiuAwtFrame(state);
}
private static void printVersion()
{
System.out.println("jiuawt " + JiuInfo.JIU_VERSION);
System.out.println("An image editing program as a demo for the JIU image processing library.");
System.out.println("Written by Marco Schmidt.");
System.out.println("Visit the JIU website at <" + JiuInfo.JIU_HOMEPAGE + ">.");
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/apps/JiuInfo.java 0000664 0000000 0000000 00000001543 10541044123 023174 0 ustar /*
* JiuInfo
*
* Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.apps;
/**
* Contains several constants with information on JIU.
* @author Marco Schmidt
*/
public interface JiuInfo
{
/**
* Three int values for the JIU version, in order (major, minor, patch).
*/
int[] JIU_NUMERICAL_VERSION = {0, 15, 0};
/**
* Version as String, created from {@link #JIU_NUMERICAL_VERSION}.
*/
String JIU_VERSION =
JIU_NUMERICAL_VERSION[0] + "." +
JIU_NUMERICAL_VERSION[1] + "." +
JIU_NUMERICAL_VERSION[2];
/**
* URL of the homepage of the JIU project.
*/
String JIU_HOMEPAGE = "http://schmidt.devlib.org/jiu/";
/**
* Address for feedback on JIU.
*/
String JIU_FEEDBACK_ADDRESS = "http://schmidt.devlib.org/jiu/feedback.html";
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/apps/StringIndexConstants.java 0000664 0000000 0000000 00000016613 10404064612 025773 0 ustar /*
* StringIndexConstants
*
* Copyright (c) 2001, 2002, 2003, 2004 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.apps;
/**
* Interface of integer index values to be used with {@link Strings}.
* @author Marco Schmidt
*/
public interface StringIndexConstants
{
int ERROR_LOADING_IMAGE = 0;
int FILE_FORMAT_UNKNOWN = 1;
int LOAD_IMAGE_FILE = 2;
int SCREEN_RESOLUTION = 3;
int COULD_NOT_CREATE_HISTOGRAM = 4;
int NUMBER_OF_USED_COLORS = 5;
int COUNT_COLORS_USED = 6;
int CLOSE = 7;
int HELP = 8;
int ABOUT = 9;
int SYSTEM = 10;
int SYSTEM_INFORMATION = 11;
int COLOR = 12;
int INVERT = 13;
int CONVERT_TO_GRAYSCALE = 14;
int FILE = 15;
int OPEN = 16;
int SAVEAS = 17;
int EXIT = 18;
int PROPERTY_JAVA_VERSION = 19;
int PROPERTY_JAVA_VENDOR = 20;
int PROPERTY_JAVA_VENDOR_URL = 21;
int PROPERTY_JAVA_HOME = 22;
int PROPERTY_JAVA_VM_SPECIFICATION_VERSION = 23;
int PROPERTY_JAVA_VM_SPECIFICATION_VENDOR = 24;
int PROPERTY_JAVA_VM_SPECIFICATION_NAME = 25;
int PROPERTY_JAVA_VM_VERSION = 26;
int PROPERTY_JAVA_VM_VENDOR = 27;
int PROPERTY_JAVA_VM_NAME = 28;
int PROPERTY_JAVA_SPECIFICATION_VERSION = 29;
int PROPERTY_JAVA_SPECIFICATION_VENDOR = 30;
int PROPERTY_JAVA_SPECIFICATION_NAME = 31;
int PROPERTY_JAVA_CLASS_VERSION = 32;
int PROPERTY_JAVA_CLASS_PATH = 33;
int PROPERTY_OS_NAME = 34;
int PROPERTY_OS_ARCH = 35;
int PROPERTY_OS_VERSION = 36;
int HOMEPAGE = 37;
int FEEDBACK = 38;
int MEDIAN_CUT = 39;
int ERROR_MESSAGE = 40;
int NUMBER_OF_COLORS_SMALL_ENOUGH = 41;
int CPU_ENDIANNESS = 42;
int CPU_ISALIST = 43;
int FREE_MEMORY = 44;
int USED_MEMORY = 45;
int TOTAL_MEMORY = 46;
int SAVE_AS = 47;
int TRANSFORMATIONS = 48;
int FLIP = 49;
int MIRROR = 50;
int MEDIAN_CUT_CONTOUR_REMOVAL = 51;
int PROMOTE_TO_RGB = 52;
int REDUCE_TO_BILEVEL_THRESHOLD_MENU_ITEM = 53;
int REDUCE_TO_BILEVEL_ORDERED_DITHERING = 54;
int ROTATE_90_LEFT = 55;
int ROTATE_90_RIGHT = 56;
int ROTATE_180 = 57;
int ROTATE_OTHER = 58;
int SCALE = 59;
int SCALE_IMAGE = 60;
int NEW_WIDTH = 61;
int NEW_HEIGHT = 62;
int MAINTAIN_ASPECT_RATIO = 63;
int OK = 64;
int CANCEL = 65;
int NUM_COLORS = 66;
int MEDIAN_CUT_COLOR_QUANTIZATION = 67;
int OUTPUT_COLOR_TYPE = 68;
int METHOD_REPR_COLOR_AVERAGE = 69;
int METHOD_REPR_COLOR_WEIGHTED_AVERAGE = 70;
int METHOD_REPR_COLOR_MEDIAN = 71;
int OUTPUT_COLOR_TYPE_PALETTED = 72;
int OUTPUT_COLOR_TYPE_RGB = 73;
int METHOD_REPR_COLOR = 74;
int CONTOUR_REMOVAL = 75;
int METHOD = 76;
int FILTERS = 77;
int SHARPEN = 78;
int BLUR = 79;
int EMBOSS = 80;
int PSYCHEDELIC_DISTILLATION = 81;
int LITHOGRAPH = 82;
int MAXIMUM_COLOR_DISTANCE = 83;
int PORTABLE_BITMAP = 84;
int PORTABLE_GRAYMAP = 85;
int PORTABLE_PIXMAP = 86;
int UNIFORM_PALETTE_COLOR_QUANTIZATION_MENU_ITEM = 87;
int NUMBER_OF_BITS_RED = 88;
int NUMBER_OF_BITS_GREEN = 89;
int NUMBER_OF_BITS_BLUE = 90;
int ORDERED_DITHERING = 91;
int DITHERING_NONE = 92;
int DITHERING_METHOD = 93;
int UNIFORM_PALETTE_COLOR_QUANTIZATION = 94;
int SAVE_IMAGE_AS = 95;
int ERROR_NO_MORE_THAN_8_BITS = 96;
int TOTAL_NUMBER_OF_BITS_AND_COLORS = 97;
int EDGE_DETECTION = 98;
int REDUCE_NUMBER_OF_SHADES_OF_GRAY = 99;
int REDUCE_NUMBER_OF_SHADES_OF_GRAY_MENU_ITEM = 100;
int NUMBER_OF_BITS = 101;
int NUMBER_OF_SHADES_OF_GRAY = 102;
int SUN_RASTER = 103;
int ADJUST = 104;
int CONTRAST_MENU_ITEM = 105;
int BRIGHTNESS_MENU_ITEM = 106;
int GAMMA_MENU_ITEM = 107;
int ADJUST_CONTRAST = 108;
int ENTER_CONTRAST_VALUE = 109;
int ADJUST_BRIGHTNESS = 110;
int ENTER_BRIGHTNESS_VALUE = 111;
int ADJUST_GAMMA = 112;
int ENTER_GAMMA_VALUE = 113;
int CROP_IMAGE = 114;
int LEFT_COLUMN = 115;
int TOP_ROW = 116;
int RIGHT_COLUMN = 117;
int BOTTOM_ROW = 118;
int CROP_MENU_ITEM = 119;
int CONVERT_TO_MINIMUM_COLOR_TYPE_MENU_ITEM = 120;
int HISTOGRAM = 121;
int REDUCE_TO_BILEVEL_THRESHOLD = 122;
int ENTER_THRESHOLD_VALUE = 123;
int FLOYD_STEINBERG_ERROR_DIFFUSION = 124;
int STUCKI_ERROR_DIFFUSION = 125;
int BURKES_ERROR_DIFFUSION = 126;
int SIERRA_ERROR_DIFFUSION = 127;
int JARVIS_JUDICE_NINKE_ERROR_DIFFUSION = 128;
int STEVENSON_ARCE_ERROR_DIFFUSION = 129;
int OUTPUT_QUALITY_IMPROVEMENT_ALGORITHM = 130;
int ALGORITHMS_NONE = 131;
int ERROR_DIFFUSION = 132;
int COLOR_IMAGE_QUANTIZATION = 133;
int HORIZONTAL_SOBEL = 134;
int VERTICAL_SOBEL = 135;
int HORIZONTAL_PREWITT = 136;
int VERTICAL_PREWITT = 137;
int SHEAR_MENU_ITEM = 138;
int SHEAR_IMAGE = 139;
int SHEAR_ENTER_ANGLE = 140;
int HUE_SATURATION_VALUE_MENU_ITEM = 141;
int ADJUST_HUE_SATURATION_AND_VALUE = 142;
int SET_HUE = 143;
int HUE = 144;
int SATURATION = 145;
int VALUE = 146;
int MEAN_FILTER_MENU_ITEM = 147;
int MEDIAN_FILTER_MENU_ITEM = 148;
int OIL_FILTER_MENU_ITEM = 149;
int APPLY_MEAN_FILTER = 150;
int APPLY_MEDIAN_FILTER = 151;
int APPLY_OIL_FILTER = 152;
int WINDOW_WIDTH = 153;
int WINDOW_HEIGHT = 154;
int ENTER_WINDOW_SIZE = 155;
int CONTOUR_REMOVAL_NUM_PASSES = 156;
int CONTOUR_REMOVAL_TAU = 157;
int PALETTE_MENU_ITEM = 158;
int PALETTE_SAVE_AS_MENU_ITEM = 159;
int MAP_TO_ARBITRARY_PALETTE_MENU_ITEM = 160;
int SAVE_PALETTE = 161;
int LOAD_PALETTE = 162;
int CHOOSE_DITHERING_METHOD = 163;
int WEBSAFE_PALETTE = 164;
int PALETTE_FROM_FILE = 165;
int CHOOSE_PALETTE_TYPE = 166;
int MAP_TO_ARBITRARY_PALETTE = 167;
int EQUALIZE_HISTOGRAM_MENU_ITEM = 168;
int NORMALIZE_HISTOGRAM_MENU_ITEM = 169;
int OCTREE_COLOR_QUANTIZATION_MENU_ITEM = 170;
int OCTREE_COLOR_QUANTIZATION = 171;
int SAVE_COOCCURRENCE_MATRIX = 172;
int SAVE_COOCCURRENCE_MATRIX_MENU_ITEM = 173;
int SAVE_COOCCURRENCE_FREQUENCY_MATRIX = 174;
int SAVE_COOCCURRENCE_FREQUENCY_MATRIX_MENU_ITEM = 175;
int WINDOWS_BITMAP = 176;
int PROMOTE = 177;
int PROMOTE_TO_PALETTED = 178;
int PROMOTE_TO_GRAY8 = 179;
int PROMOTE_TO_GRAY16 = 180;
int PROMOTE_TO_RGB24 = 181;
int PROMOTE_TO_RGB48 = 182;
int REDUCE = 183;
int SAVE_HISTOGRAM_AS_MENU_ITEM = 184;
int SAVE_HISTOGRAM_AS = 185;
int EDIT = 186;
int EDIT_UNDO = 187;
int EDIT_REDO = 188;
int TEXTURE_PROPERTIES_MENU_ITEM = 189;
int CONTRAST = 190;
int ENERGY = 191;
int ENTROPY = 192;
int HOMOGENEITY = 193;
int TEXTURE_PROPERTIES = 194;
int CORRELATION = 195;
int DISSIMILARITY = 196;
int MINIMUM_FILTER_MENU_ITEM = 197;
int MAXIMUM_FILTER_MENU_ITEM = 198;
int APPLY_MINIMUM_FILTER = 199;
int APPLY_MAXIMUM_FILTER = 200;
int VIEW = 201;
int VIEW_ZOOMIN = 202;
int VIEW_ZOOMOUT = 203;
int VIEW_SETORIGINALSIZE = 204;
int VIEW_INTERPOLATIONTYPE = 205;
int VIEW_INTERPOLATIONTYPE_NEARESTNEIGHBOR = 206;
int VIEW_INTERPOLATIONTYPE_BILINEAR = 207;
int VIEW_INTERPOLATIONTYPE_BICUBIC = 208;
int PALM = 209;
int PALETTE_PALM_256_COLORS = 210;
int PALETTE_PALM_16_COLORS = 211;
int PALETTE_PALM_16_GRAY = 212;
int PALETTE_PALM_4_GRAY = 213;
int DO_YOU_REALLY_WANT_TO_QUIT_WITHOUT_SAVING = 214;
int QUIT_PROGRAM = 215;
int YES = 216;
int NO = 217;
int DO_YOU_REALLY_WANT_TO_CLOSE_WITHOUT_SAVING = 218;
int CLOSE_FILE = 219;
int BITS_PER_PIXEL = 220;
int BILEVEL = 221;
int GRAYSCALE = 222;
int RGB_TRUECOLOR = 223;
int IMAGE_TYPE_UNKNOWN = 224;
int IMAGE_TYPE = 225;
int PALETTED = 226;
int PIXELS = 227;
int PORTABLE_NETWORK_GRAPHICS = 228;
int MEMORY = 229;
int DISK_SPACE = 230;
int GIF = 231;
int IMAGE_1 = 232;
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/apps/dumpcodecs.java 0000664 0000000 0000000 00000001507 07741250130 023764 0 ustar /*
* dumpcodecs
*
* Copyright (c) 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.apps;
import net.sourceforge.jiu.codecs.*;
/**
* Command line program that lists all codecs registered with ImageLoader.
* All program arguments are ignored.
* @author Marco Schmidt
* @since 0.10.0
*/
public class dumpcodecs
{
public static void main(String[] args) throws Exception
{
System.out.println("Codecs known to net.sourceforge.jiu.codecs.ImageLoader");
for (int i = 0; i < ImageLoader.getNumCodecs(); i++)
{
ImageCodec codec = ImageLoader.createCodec(i);
System.out.println("(" + (i + 1) + ") " +
codec.getClass().getName() + " / " +
codec.getFormatName() + " / " +
"Saving supported=" + (codec.isSavingSupported() ? "yes" : "no"));
}
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/apps/jiuconvert.java 0000664 0000000 0000000 00000034553 10377272210 024037 0 ustar /*
* jiuconvert
*
* Copyright (c) 2002, 2003, 2004, 2005, 2006 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.apps;
import java.io.File;
import java.io.IOException;
import java.util.Hashtable;
import java.util.Vector;
import net.sourceforge.jiu.codecs.BMPCodec;
import net.sourceforge.jiu.codecs.CodecMode;
import net.sourceforge.jiu.codecs.ImageCodec;
import net.sourceforge.jiu.codecs.ImageLoader;
import net.sourceforge.jiu.codecs.InvalidFileStructureException;
import net.sourceforge.jiu.codecs.InvalidImageIndexException;
import net.sourceforge.jiu.codecs.PalmCodec;
import net.sourceforge.jiu.codecs.PNMCodec;
import net.sourceforge.jiu.codecs.UnsupportedTypeException;
import net.sourceforge.jiu.data.PixelImage;
import net.sourceforge.jiu.ops.OperationFailedException;
class JiuConvertSettings
{
static final int VERBOSITY_QUIET = 0;
static final int VERBOSITY_NORMAL = 1;
static final int VERBOSITY_HIGH = 2;
static final int FORMAT_UNKNOWN = -1;
static final int FORMAT_BMP = 0;
static final int FORMAT_PNM = 1;
static final int FORMAT_PALM = 2;
Vector inputFileNames = new Vector();
File destinationDirectory;
int fileFormat;
boolean noAwtLoading;
boolean overwrite;
boolean testOnly;
long time1;
long time2;
int verbosity;
}
abstract class Switch
{
void check(JiuConvertSettings settings) { }
abstract String getDescription();
int getMinParameters() { return 0; }
String getParameters() { return ""; }
abstract String[] getValues();
abstract int init(String[] args, int index, JiuConvertSettings settings);
void setDefaults(JiuConvertSettings settings) { }
}
class BMPSwitch extends Switch
{
void check(JiuConvertSettings settings)
{
if (settings.fileFormat == JiuConvertSettings.FORMAT_UNKNOWN && !settings.testOnly)
{
System.err.println("ERROR: You must either use test mode or provide an output file format switch.");
System.exit(1);
}
}
String[] getValues() { return new String[] {"-b", "--bmp"}; }
String getDescription() { return "write Windows BMP output"; }
int init(String[] args, int index, JiuConvertSettings settings)
{
settings.fileFormat = JiuConvertSettings.FORMAT_BMP;
return index;
}
void setDefaults(JiuConvertSettings settings) { settings.fileFormat = JiuConvertSettings.FORMAT_UNKNOWN; }
}
class DestinationDirectorySwitch extends Switch
{
int getMinParameters() { return 1; }
String getDescription() { return "write output files to directory DIR"; }
String getParameters() { return "DIR"; }
String[] getValues() { return new String[] {"-d", "--destdir"}; }
int init(String[] args, int index, JiuConvertSettings settings)
{
String name = args[index++];
File dir = new File(name);
if (!dir.exists())
{
System.err.println("Directory " + name + " does not exist.");
System.exit(1);
}
if (!dir.isDirectory())
{
System.err.println(name + " does not seem to be a directory.");
System.exit(1);
}
settings.destinationDirectory = dir;
return index;
}
void setDefaults(JiuConvertSettings settings) { settings.destinationDirectory = new File("."); }
}
class NoAwtLoadingSwitch extends Switch
{
String[] getValues() { return new String[] {"--noawtloading"}; }
String getDescription() { return "never use AWT Toolkit to load images"; }
int init(String[] args, int index, JiuConvertSettings settings)
{
settings.noAwtLoading = true;
return index;
}
void setDefaults(JiuConvertSettings settings) { settings.noAwtLoading = false; }
}
class OverwriteSwitch extends Switch
{
String[] getValues() { return new String[] {"-o", "--overwrite"}; }
String getDescription() { return "overwrite existing files"; }
int init(String[] args, int index, JiuConvertSettings settings)
{
settings.overwrite = true;
return index;
}
void setDefaults(JiuConvertSettings settings) { settings.overwrite = false; }
}
class PalmSwitch extends Switch
{
String[] getValues() { return new String[] {"-P", "--palm"}; }
String getDescription() { return "write Palm native image output"; }
int init(String[] args, int index, JiuConvertSettings settings)
{
settings.fileFormat = JiuConvertSettings.FORMAT_PALM;
return index;
}
}
class PNMSwitch extends Switch
{
String[] getValues() { return new String[] {"-p", "--pnm"}; }
String getDescription() { return "write Portable Anymap (PNM/PBM/PGM/PPM) output"; }
int init(String[] args, int index, JiuConvertSettings settings)
{
settings.fileFormat = JiuConvertSettings.FORMAT_PNM;
return index;
}
}
class PrintHelpSwitch extends Switch
{
static Vector switches;
String[] getValues() { return new String[] {"-H", "--help"}; }
String getDescription() { return "print help text to stdout and terminate"; }
int init(String[] args, int index, JiuConvertSettings settings)
{
System.out.println("Usage: java jiuconvert [OPTIONS] [FILEs]");
System.out.println("");
for (int i = 0; i < switches.size(); i++)
{
Switch sw = (Switch)switches.elementAt(i);
System.out.print("\t");
String[] values = sw.getValues();
int chars = 0;
for (int j = 0; j < values.length; j++)
{
if (j > 0)
{
System.out.print(", ");
chars += 2;
}
System.out.print(values[j]);
chars += values[j].length();
}
String params = sw.getParameters();
System.out.print(" " + params);
chars += params.length() + 1;
while (chars++ < 24)
{
System.out.print(" ");
}
System.out.println(sw.getDescription());
}
System.exit(0);
return 0; // compiler doesn't know that System.exit(0) prevents execution ever getting here
}
}
class PrintVersionSwitch extends Switch
{
String[] getValues() { return new String[] {"-V", "--version"}; }
String getDescription() { return "print version to stdout and terminate"; }
int init(String[] args, int index, JiuConvertSettings settings)
{
System.out.println("jiuconvert " + JiuInfo.JIU_VERSION);
System.out.println("Written by Marco Schmidt.");
System.out.println("Copyright (C) 2002, 2003, 2004, 2005 Marco Schmidt.");
System.out.println("This is free software; see the source for copying conditions. There is NO");
System.out.println("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.");
System.exit(0);
return 0; // compiler doesn't know that System.exit(0) prevents execution ever getting here
}
}
class QuietSwitch extends Switch
{
String[] getValues() { return new String[] {"-q", "--quiet"}; }
String getDescription() { return "print only error messages"; }
int init(String[] args, int index, JiuConvertSettings settings)
{
settings.verbosity = JiuConvertSettings.VERBOSITY_QUIET;
return index;
}
void setDefaults(JiuConvertSettings settings) { settings.verbosity = JiuConvertSettings.VERBOSITY_NORMAL; }
}
class TestSwitch extends Switch
{
String[] getValues() { return new String[] {"-t", "--test"}; }
String getDescription() { return "test loading, do not write any output files"; }
int init(String[] args, int index, JiuConvertSettings settings)
{
settings.testOnly = true;
return index;
}
void setDefaults(JiuConvertSettings settings) { settings.testOnly = false; }
}
class VerbositySwitch extends Switch
{
String[] getValues() { return new String[] {"-v", "--verbose"}; }
String getDescription() { return "print extensive information to stdout"; }
int init(String[] args, int index, JiuConvertSettings settings)
{
settings.verbosity = JiuConvertSettings.VERBOSITY_HIGH;
return index;
}
}
/**
* A command line program to convert between file formats.
* @author Marco Schmidt
* @since 0.10.0
*/
public class jiuconvert
{
// to prevent instances of this class
private jiuconvert()
{
}
private static Vector createSwitches()
{
Vector switches = new Vector();
// note that the order in which the switches are added is the order in which they are displayed
switches.addElement(new BMPSwitch());
switches.addElement(new PalmSwitch());
switches.addElement(new PNMSwitch());
switches.addElement(new TestSwitch());
switches.addElement(new NoAwtLoadingSwitch());
switches.addElement(new OverwriteSwitch());
switches.addElement(new DestinationDirectorySwitch());
switches.addElement(new QuietSwitch());
switches.addElement(new VerbositySwitch());
switches.addElement(new PrintHelpSwitch());
switches.addElement(new PrintVersionSwitch());
return switches;
}
private static void exit(JiuConvertSettings settings, int exitCode)
{
settings.time2 = System.currentTimeMillis();
println(JiuConvertSettings.VERBOSITY_NORMAL, settings, "Time: " + ((settings.time2 - settings.time1) / 1000L) + " s.");
System.exit(exitCode);
}
private static JiuConvertSettings initFromArguments(String[] args)
{
// create switch objects
Vector switches = createSwitches();
PrintHelpSwitch.switches = switches;
// set defaults
JiuConvertSettings settings = new JiuConvertSettings();
settings.time1 = System.currentTimeMillis();
Hashtable switchHash = new Hashtable();
for (int i = 0; i < switches.size(); i++)
{
Switch sw = (Switch)switches.elementAt(i);
sw.setDefaults(settings);
String[] values = sw.getValues();
int j = 0;
while (j < values.length)
{
String value = values[j++];
if (switchHash.get(value) != null)
{
System.err.println("FATAL INTERNAL ERROR: Switch " + value + " is used more than once.");
System.exit(1);
}
switchHash.put(value, sw);
}
}
// process arguments
int index = 0;
while (index < args.length)
{
String arg = args[index++];
Switch sw = (Switch)switchHash.get(arg);
if (sw == null)
{
// maybe a switch that does not exist?
if (arg.charAt(0) == '-')
{
System.err.println("Error: Unknown switch " + arg);
System.exit(1);
}
// there is no switch of that name => must be a file
File file = new File(arg);
if (!file.exists() || !file.isFile())
{
System.err.println("Error: There is no file \"" + arg + "\".");
System.exit(1);
}
settings.inputFileNames.addElement(arg);
}
else
{
int minParams = sw.getMinParameters();
if (index + minParams > args.length)
{
System.err.println("Error: switch " + arg + " needs at least " + minParams + " parameter(s).");
System.exit(1);
}
index = sw.init(args, index, settings);
}
}
// now call check() on each switch
for (int i = 0; i < switches.size(); i++)
{
Switch sw = (Switch)switches.elementAt(i);
sw.check(settings);
}
// other checks
if (settings.inputFileNames.size() < 1)
{
System.err.println("Error: You must provide at least one input file name.");
System.exit(1);
}
return settings;
}
private static void print(int minVerbosityLevel, JiuConvertSettings settings, String message)
{
if (settings.verbosity >= minVerbosityLevel)
{
System.out.print(message);
}
}
private static void println(int minVerbosityLevel, JiuConvertSettings settings, String message)
{
if (settings.verbosity >= minVerbosityLevel)
{
System.out.println(message);
}
}
private static void run(JiuConvertSettings settings, String inputFileName)
{
String message = null;
PixelImage image = null;
try
{
image = ImageLoader.load(inputFileName, (Vector)null);
}
catch (InvalidImageIndexException iiie)
{
message = "Failed: " + iiie.toString();
}
catch (InvalidFileStructureException ifse)
{
message = "Failed: " + ifse.toString();
}
catch (UnsupportedTypeException ute)
{
message = "Failed: " + ute.toString();
}
catch (IOException ioe)
{
message = "Failed: " + ioe.toString();
}
if (message == null && image == null)
{
message = "Failed.";
}
if (message != null)
{
println(JiuConvertSettings.VERBOSITY_QUIET, settings, "\"" + inputFileName + "\" " + message);
return;
}
else
{
print(JiuConvertSettings.VERBOSITY_NORMAL, settings, "\"" + inputFileName + "\" ");
print(JiuConvertSettings.VERBOSITY_NORMAL, settings, "Loaded (" +
//ImageDescriptionCreator.getDescription(image, Locale.US, state) +
").");
}
if (settings.testOnly)
{
println(JiuConvertSettings.VERBOSITY_NORMAL, settings, "");
return;
}
String outputFileName = inputFileName;
String sep = System.getProperty("file.separator");
int index = outputFileName.lastIndexOf(sep);
if (index != -1)
{
outputFileName = outputFileName.substring(index + sep.length());
}
index = outputFileName.lastIndexOf(".");
if (index != -1)
{
outputFileName = outputFileName.substring(0, index);
}
ImageCodec codec = null;
switch(settings.fileFormat)
{
case(JiuConvertSettings.FORMAT_BMP):
{
codec = new BMPCodec();
break;
}
case(JiuConvertSettings.FORMAT_PALM):
{
codec = new PalmCodec();
break;
}
case(JiuConvertSettings.FORMAT_PNM):
{
codec = new PNMCodec();
break;
}
}
String ext = codec.suggestFileExtension(image);
if (ext != null)
{
outputFileName += ext;
}
File outputFile = new File(settings.destinationDirectory, outputFileName);
outputFileName = outputFile.getAbsolutePath();
if (outputFile.exists() && !settings.overwrite)
{
println(JiuConvertSettings.VERBOSITY_NORMAL, settings, " File \"" + outputFileName + "\" already exists, skipping.");
}
codec.setImage(image);
try
{
codec.setFile(outputFileName, CodecMode.SAVE);
codec.process();
codec.close();
println(JiuConvertSettings.VERBOSITY_NORMAL, settings, " Wrote \"" + outputFileName + "\".");
}
catch (IOException ioe)
{
println(JiuConvertSettings.VERBOSITY_HIGH, settings, " I/O error writing \"" + outputFileName + "\": " + ioe.toString());
}
catch (OperationFailedException ofe)
{
println(JiuConvertSettings.VERBOSITY_HIGH, settings, " Error writing \"" + outputFileName + "\": " + ofe.toString());
}
}
private static void run(JiuConvertSettings settings)
{
int index = 0;
while (index < settings.inputFileNames.size())
{
String fileName = (String)settings.inputFileNames.elementAt(index++);
run(settings, fileName);
}
exit(settings, 0);
}
public static void main(String[] args)
{
JiuConvertSettings settings = initFromArguments(args);
run(settings);
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/gui/ 0000775 0000000 0000000 00000000000 10546532075 020621 5 ustar java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/gui/awt/ 0000775 0000000 0000000 00000000000 10572433573 021416 5 ustar java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/gui/awt/dialogs/ 0000775 0000000 0000000 00000000000 10546532075 023036 5 ustar java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/gui/awt/dialogs/ReduceGrayscaleDialog.java 0000664 0000000 0000000 00000012142 07741250134 030057 0 ustar /*
* ReduceGrayscaleDialog
*
* Copyright (c) 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.gui.awt.dialogs;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Choice;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.Panel;
import java.awt.Rectangle;
import java.awt.Scrollbar;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import net.sourceforge.jiu.apps.Strings;
/**
* A dialog to enter the parameters for a grayscale reduction operation.
* @author Marco Schmidt
*/
public class ReduceGrayscaleDialog extends Dialog implements ActionListener, AdjustmentListener
{
public static final int TYPE_DITHERING_NONE = 0;
public static final int TYPE_ORDERED_DITHERING = 1;
public static final int TYPE_FLOYD_STEINBERG_ERROR_DIFFUSION = 2;
public static final int TYPE_STUCKI_ERROR_DIFFUSION = 3;
public static final int TYPE_BURKES_ERROR_DIFFUSION = 4;
public static final int TYPE_SIERRA_ERROR_DIFFUSION = 5;
public static final int TYPE_JARVIS_JUDICE_NINKE_ERROR_DIFFUSION = 6;
public static final int TYPE_STEVENSON_ARCE_ERROR_DIFFUSION = 7;
public final int[][] DITHERING_METHODS =
{
{
TYPE_DITHERING_NONE,
TYPE_ORDERED_DITHERING,
TYPE_FLOYD_STEINBERG_ERROR_DIFFUSION,
TYPE_STUCKI_ERROR_DIFFUSION,
TYPE_BURKES_ERROR_DIFFUSION,
TYPE_SIERRA_ERROR_DIFFUSION,
TYPE_JARVIS_JUDICE_NINKE_ERROR_DIFFUSION,
TYPE_STEVENSON_ARCE_ERROR_DIFFUSION
},
{
Strings.DITHERING_NONE,
Strings.ORDERED_DITHERING,
Strings.FLOYD_STEINBERG_ERROR_DIFFUSION,
Strings.STUCKI_ERROR_DIFFUSION,
Strings.BURKES_ERROR_DIFFUSION,
Strings.SIERRA_ERROR_DIFFUSION,
Strings.JARVIS_JUDICE_NINKE_ERROR_DIFFUSION,
Strings.STEVENSON_ARCE_ERROR_DIFFUSION
}
};
private Strings strings;
private Button ok;
private Button cancel;
private Scrollbar scrollbar;
private Choice ditheringMethod;
private Label bitLabel;
private Label shadesLabel;
private boolean pressedOk;
/**
* Creates a modal dialog to enter the parameters.
* @param owner the parent of this modal dialog
* @param strings an object to get String constants in the current language
* @param bits initial number of bits to be shown in the dialog
* @param maxBits maximum allowed number of bits
* @param ditheringMethodSelection initial selection of dithering method
*/
public ReduceGrayscaleDialog(Frame owner, Strings strings, int bits, int maxBits,
int ditheringMethodSelection)
{
super(owner, strings.get(Strings.REDUCE_NUMBER_OF_SHADES_OF_GRAY), true);
pressedOk = false;
this.strings = strings;
Panel panel = new Panel();
panel.setLayout(new GridLayout(0, 2));
bitLabel = new Label();
panel.add(bitLabel);
scrollbar = new Scrollbar(Scrollbar.HORIZONTAL, bits, 1, 1, maxBits + 1);
scrollbar.addAdjustmentListener(this);
panel.add(scrollbar);
panel.add(new Label(strings.get(Strings.NUMBER_OF_SHADES_OF_GRAY) + ": "));
shadesLabel = new Label();
panel.add(shadesLabel);
panel.add(new Label(strings.get(Strings.DITHERING_METHOD)));
ditheringMethod = new Choice();
for (int i = 0; i < DITHERING_METHODS[0].length; i++)
{
ditheringMethod.add(strings.get(DITHERING_METHODS[1][i]));
if (ditheringMethodSelection == i)
{
ditheringMethod.select(i);
}
}
panel.add(ditheringMethod);
add(panel, BorderLayout.CENTER);
ok = new Button(strings.get(Strings.OK));
ok.addActionListener(this);
cancel = new Button(strings.get(Strings.CANCEL));
cancel.addActionListener(this);
panel = new Panel();
panel.add(ok);
panel.add(cancel);
add(panel, BorderLayout.SOUTH);
updateLabels();
pack();
center();
}
/**
* Hides (closes) this dialog if the OK button was source of the action event
* (e.g. if the button was pressed).
*/
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == ok)
{
pressedOk = true;
setVisible(false);
}
else
if (e.getSource() == cancel)
{
setVisible(false);
}
}
public void adjustmentValueChanged(AdjustmentEvent e)
{
updateLabels();
}
/**
* Centers the dialog on screen.
*/
public void center()
{
Rectangle rect = getBounds();
int width = rect.width;
int height = rect.height;
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
setLocation((screenSize.width / 2) - (width / 2),
(screenSize.height / 2) - (height / 2));
}
public int getDitheringMethod()
{
return DITHERING_METHODS[0][ditheringMethod.getSelectedIndex()];
}
public int getNumBits()
{
return scrollbar.getValue();
}
public boolean hasPressedOk()
{
return pressedOk;
}
private void updateLabels()
{
int numBits = getNumBits();
bitLabel.setText(strings.get(Strings.NUMBER_OF_BITS) + ": " + numBits);
shadesLabel.setText(Integer.toString(1 << numBits));
}
}
././@LongLink 0000000 0000000 0000000 00000000154 00000000000 011565 L ustar root root java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/gui/awt/dialogs/UniformPaletteQuantizerDialog.java java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/gui/awt/dialogs/UniformPaletteQuantizerDial0000664 0000000 0000000 00000016425 07741250134 030420 0 ustar /*
* UniformPaletteQuantizerDialog
*
* Copyright (c) 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.gui.awt.dialogs;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Choice;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.Panel;
import java.awt.Rectangle;
import java.awt.Scrollbar;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import net.sourceforge.jiu.apps.Strings;
/**
* An AWT dialog to enter the parameters for a uniform palette color quantization operation.
* @author Marco Schmidt
*/
public class UniformPaletteQuantizerDialog extends Dialog implements ActionListener, AdjustmentListener, ItemListener
{
public static final int TYPE_DITHERING_NONE = 0;
public static final int TYPE_ORDERED_DITHERING = 1;
public static final int TYPE_FLOYD_STEINBERG_ERROR_DIFFUSION = 2;
public static final int TYPE_STUCKI_ERROR_DIFFUSION = 3;
public static final int TYPE_BURKES_ERROR_DIFFUSION = 4;
public static final int TYPE_SIERRA_ERROR_DIFFUSION = 5;
public static final int TYPE_JARVIS_JUDICE_NINKE_ERROR_DIFFUSION = 6;
public static final int TYPE_STEVENSON_ARCE_ERROR_DIFFUSION = 7;
public final int[][] DITHERING_METHODS =
{
{
TYPE_DITHERING_NONE,
TYPE_ORDERED_DITHERING,
TYPE_FLOYD_STEINBERG_ERROR_DIFFUSION,
TYPE_STUCKI_ERROR_DIFFUSION,
TYPE_BURKES_ERROR_DIFFUSION,
TYPE_SIERRA_ERROR_DIFFUSION,
TYPE_JARVIS_JUDICE_NINKE_ERROR_DIFFUSION,
TYPE_STEVENSON_ARCE_ERROR_DIFFUSION
},
{
Strings.DITHERING_NONE,
Strings.ORDERED_DITHERING,
Strings.FLOYD_STEINBERG_ERROR_DIFFUSION,
Strings.STUCKI_ERROR_DIFFUSION,
Strings.BURKES_ERROR_DIFFUSION,
Strings.SIERRA_ERROR_DIFFUSION,
Strings.JARVIS_JUDICE_NINKE_ERROR_DIFFUSION,
Strings.STEVENSON_ARCE_ERROR_DIFFUSION
}
};
private Strings strings;
private Button ok;
private Button cancel;
private Scrollbar redScrollbar;
private Scrollbar greenScrollbar;
private Scrollbar blueScrollbar;
private Choice ditheringMethod;
private Label infoLabel1;
private Label infoLabel2;
private Label redLabel;
private Label greenLabel;
private Label blueLabel;
private boolean pressedOk;
/**
* Creates a modal dialog to enter the parameter.
* @param owner the parent of this modal dialog
* @param strings an object to get String constants in the current language
* @param redBits the initial selection of the number of bits for the red channel
* @param greenBits the initial selection of the number of bits for the green channel
* @param blueBits the initial selection of the number of bits for the blue channel
* @param ditheringMethodSelection initial selection for dithering method
*/
public UniformPaletteQuantizerDialog(Frame owner, Strings strings, int redBits,
int greenBits, int blueBits, int ditheringMethodSelection)
{
super(owner, strings.get(Strings.UNIFORM_PALETTE_COLOR_QUANTIZATION), true);
pressedOk = false;
this.strings = strings;
Panel panel = new Panel();
panel.setLayout(new GridLayout(0, 2));
redLabel = new Label(strings.get(Strings.NUMBER_OF_BITS_RED));
panel.add(redLabel);
redScrollbar = new Scrollbar(Scrollbar.HORIZONTAL, redBits, 1, 1, 7);
redScrollbar.addAdjustmentListener(this);
panel.add(redScrollbar);
greenLabel = new Label(strings.get(Strings.NUMBER_OF_BITS_GREEN));
panel.add(greenLabel);
greenScrollbar = new Scrollbar(Scrollbar.HORIZONTAL, greenBits, 1, 1, 7);
greenScrollbar.addAdjustmentListener(this);
panel.add(greenScrollbar);
blueLabel = new Label(strings.get(Strings.NUMBER_OF_BITS_BLUE));
panel.add(blueLabel);
blueScrollbar = new Scrollbar(Scrollbar.HORIZONTAL, blueBits, 1, 1, 7);
blueScrollbar.addAdjustmentListener(this);
panel.add(blueScrollbar);
infoLabel1 = new Label();
infoLabel2 = new Label();
panel.add(infoLabel1);
panel.add(infoLabel2);
panel.add(new Label(strings.get(Strings.DITHERING_METHOD)));
ditheringMethod = new Choice();
for (int i = 0; i < DITHERING_METHODS[0].length; i++)
{
ditheringMethod.add(strings.get(DITHERING_METHODS[1][i]));
if (ditheringMethodSelection == i)
{
ditheringMethod.select(i);
}
}
ditheringMethod.addItemListener(this);
panel.add(ditheringMethod);
add(panel, BorderLayout.CENTER);
ok = new Button(strings.get(Strings.OK));
ok.addActionListener(this);
cancel = new Button(strings.get(Strings.CANCEL));
cancel.addActionListener(this);
panel = new Panel();
panel.add(ok);
panel.add(cancel);
add(panel, BorderLayout.SOUTH);
updateLabels();
pack();
center();
}
/**
* Hides (closes) this dialog if the OK button was source of the action event
* (e.g. if the button was pressed).
*/
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == ok)
{
pressedOk = true;
setVisible(false);
}
else
if (e.getSource() == cancel)
{
setVisible(false);
}
}
public void adjustmentValueChanged(AdjustmentEvent e)
{
updateLabels();
}
/**
* Centers the dialog on screen.
*/
public void center()
{
Rectangle rect = getBounds();
int width = rect.width;
int height = rect.height;
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
setLocation((screenSize.width / 2) - (width / 2),
(screenSize.height / 2) - (height / 2));
}
/*public int getNumColors()
{
return getValue(numColorsField);
}*/
public int getDitheringMethod()
{
return DITHERING_METHODS[0][ditheringMethod.getSelectedIndex()];
}
public int getBlueBits()
{
return blueScrollbar.getValue();
}
public int getGreenBits()
{
return greenScrollbar.getValue();
}
public int getRedBits()
{
return redScrollbar.getValue();
}
public boolean hasPressedOk()
{
return pressedOk;
}
public boolean isSelectionValid()
{
int r = getRedBits();
int g = getGreenBits();
int b = getBlueBits();
int sum = r + g + b;
if (getDitheringMethod() == TYPE_DITHERING_NONE)
{
return (sum < 9);
}
else
{
return (sum < 24);
}
}
public void itemStateChanged(ItemEvent e)
{
if (e.getSource() == ditheringMethod)
{
updateLabels();
}
}
private void updateLabels()
{
redLabel.setText(strings.get(Strings.NUMBER_OF_BITS_RED) + " (" + getRedBits() + ")");
greenLabel.setText(strings.get(Strings.NUMBER_OF_BITS_GREEN) + " (" + getGreenBits() + ")");
blueLabel.setText(strings.get(Strings.NUMBER_OF_BITS_BLUE) + " (" + getBlueBits() + ")");
boolean valid = isSelectionValid();
ok.setEnabled(valid);
if (valid)
{
int totalBits = getRedBits() + getGreenBits() + getBlueBits();
int totalColors = 1 << totalBits;
infoLabel1.setText(strings.get(Strings.TOTAL_NUMBER_OF_BITS_AND_COLORS));
infoLabel2.setText(Integer.toString(totalBits) + ", " + Integer.toString(totalColors));
}
else
{
infoLabel1.setText(strings.get(Strings.ERROR_NO_MORE_THAN_8_BITS));
infoLabel2.setText("");
}
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/gui/awt/dialogs/WindowSizeDialog.java 0000664 0000000 0000000 00000006717 07741250134 027132 0 ustar /*
* WindowSizeDialog
*
* Copyright (c) 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.gui.awt.dialogs;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Dialog;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.Panel;
import java.awt.TextComponent;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import net.sourceforge.jiu.apps.Strings;
/**
* A dialog to enter values for the width and height of a window (typically
* for a spatial filter like median or mean.
*
* @author Marco Schmidt
*/
public class WindowSizeDialog extends Dialog implements
ActionListener, KeyListener
{
private Button ok;
private Button cancel;
private TextField width;
private TextField height;
private boolean pressedOk;
/**
* @param owner the Frame this dialog will belong to
*/
public WindowSizeDialog(Frame owner, Strings strings, int titleIndex, int initialWidth, int initialHeight)
{
super(owner, strings.get(titleIndex), true);
pressedOk = false;
Panel panel = new Panel();
panel.setLayout(new GridLayout(0, 2));
panel.add(new Label(strings.get(Strings.ENTER_WINDOW_SIZE)));
panel.add(new Label(""));
panel.add(new Label(strings.get(Strings.WINDOW_WIDTH)));
width = new TextField(Integer.toString(initialWidth));
width.addKeyListener(this);
panel.add(width);
panel.add(new Label(strings.get(Strings.WINDOW_HEIGHT)));
height = new TextField(Integer.toString(initialHeight));
height.addKeyListener(this);
panel.add(height);
add(panel, BorderLayout.CENTER);
ok = new Button(strings.get(Strings.OK));
ok.addActionListener(this);
cancel = new Button(strings.get(Strings.CANCEL));
cancel.addActionListener(this);
panel = new Panel();
panel.add(ok);
panel.add(cancel);
add(panel, BorderLayout.SOUTH);
updateOkButton();
pack();
Dialogs.center(this);
}
/**
* Hides (closes) this dialog if the OK button was source of the action event
* (e.g. if the button was pressed).
*/
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == ok)
{
pressedOk = true;
setVisible(false);
}
else
if (e.getSource() == cancel)
{
setVisible(false);
}
}
public int getHeightValue()
{
return getValue(height);
}
public int getWidthValue()
{
return getValue(width);
}
/**
* Attempts to convert the content of the argument text component
* to an int
; if successful, returns that int, otherwise
* -1000 is returned.
* @param textField the text component that is supposed to hold an int value
* @return int representation of the text component's data
*/
private int getValue(TextComponent textField)
{
try
{
return Integer.parseInt(textField.getText());
}
catch (NumberFormatException nfe)
{
return -1000;
}
}
public boolean hasPressedOk()
{
return pressedOk;
}
private void updateOkButton()
{
int w = getWidthValue();
int h = getHeightValue();
ok.setEnabled(w >= 1 && h >= 1 && ((w % 2) == 1) && ((h % 2) == 1));
}
public void keyPressed(KeyEvent e)
{
updateOkButton();
}
public void keyReleased(KeyEvent e)
{
updateOkButton();
}
public void keyTyped(KeyEvent e)
{
updateOkButton();
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/gui/awt/dialogs/CropDialog.java 0000664 0000000 0000000 00000013302 07741250134 025717 0 ustar /*
* CropDialog
*
* Copyright (c) 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.gui.awt.dialogs;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Dialog;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.Panel;
import java.awt.TextComponent;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import net.sourceforge.jiu.apps.Strings;
/**
* A dialog to enter the parameters for an image crop operation.
* @author Marco Schmidt
*/
public class CropDialog extends Dialog implements ActionListener, KeyListener
{
private Button ok;
private Button cancel;
private TextField x1;
private TextField y1;
private TextField x2;
private TextField y2;
private int width;
private int height;
private Label newWidth;
private Label newHeight;
private boolean pressedOk;
/**
* @param owner the Frame this dialog will belong to
* @param strings Strings resource to be used for text messages
* @param width width of the original image, before cropping; this is used to
* determine the valid values for left and right column, from 0 to width - 1
* @param height height of the original image, before cropping; this is used to
* determine the valid values for top and bottom row, from 0 to height - 1
*/
public CropDialog(Frame owner, Strings strings, int width, int height)
{
super(owner, strings.get(Strings.CROP_IMAGE) + " (" + width + " x " + height + ")", true);
pressedOk = false;
this.width = width;
this.height = height;
Panel panel = new Panel();
panel.setLayout(new GridLayout(0, 6));
panel.add(new Label(strings.get(Strings.LEFT_COLUMN)));
x1 = new TextField("0");
x1.addKeyListener(this);
panel.add(x1);
panel.add(new Label(strings.get(Strings.RIGHT_COLUMN)));
x2 = new TextField(Integer.toString(width - 1));
x2.addKeyListener(this);
panel.add(x2);
panel.add(new Label(strings.get(Strings.NEW_WIDTH)));
newWidth = new Label();
panel.add(newWidth);
panel.add(new Label(strings.get(Strings.TOP_ROW)));
y1 = new TextField("0");
y1.addKeyListener(this);
panel.add(y1);
panel.add(new Label(strings.get(Strings.BOTTOM_ROW)));
y2 = new TextField(Integer.toString(height - 1));
y2.addKeyListener(this);
panel.add(y2);
panel.add(new Label(strings.get(Strings.NEW_HEIGHT)));
newHeight = new Label();
panel.add(newHeight);
add(panel, BorderLayout.CENTER);
ok = new Button(strings.get(Strings.OK));
ok.addActionListener(this);
cancel = new Button(strings.get(Strings.CANCEL));
cancel.addActionListener(this);
panel = new Panel();
panel.add(ok);
panel.add(cancel);
add(panel, BorderLayout.SOUTH);
updateLabels();
pack();
Dialogs.center(this);
}
/**
* Hides (closes) this dialog if the OK button was source of the action event
* (e.g. if the button was pressed).
*/
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == ok)
{
pressedOk = true;
setVisible(false);
}
else
if (e.getSource() == cancel)
{
setVisible(false);
}
}
public int getHeight()
{
int y1 = getY1();
int y2 = getY2();
if (y1 != -1 && y2 != -1 && y1 >= 0 && y2 >= y1 && y2 < height && y1 <= y2)
{
return y2 - y1 + 1;
}
else
{
return -1;
}
}
/**
* Attempts to convert the content of the argument text component
* to an int
; if successful, returns that int, otherwise
* -1 is returned.
* @param textField the text component that is supposed to hold an int value
* @return int representation of the text component's data
*/
private int getValue(TextComponent textField)
{
try
{
return Integer.parseInt(textField.getText());
}
catch (NumberFormatException nfe)
{
return -1;
}
}
/**
* Returns the width of the to-be-cropped image as given by the
* current values in the text fields for left column and right column.
* Computes the width from those values and returns it or returns -1
* if the data in the text fields is not valid for some reason.
* @return width of cropped image or -1 if information is invalid
*/
public int getWidth()
{
int x1 = getX1();
int x2 = getX2();
if (x1 != -1 && x2 != -1 && x1 >= 0 && x2 >= x1 && x2 < width && x1 <= x2)
{
return x2 - x1 + 1;
}
else
{
return -1;
}
}
public int getX1()
{
return getValue(x1);
}
public int getX2()
{
return getValue(x2);
}
public int getY1()
{
return getValue(y1);
}
public int getY2()
{
return getValue(y2);
}
public boolean hasPressedOk()
{
return pressedOk;
}
/**
* Computes width and height of new image and updates the
* corresponding labels.
* The labels will either display width and height or a single
* dash if the data in the text fields is invalid.
*/
private void updateLabels()
{
String text;
boolean enabled = true;
int valueWidth = getWidth();
if (valueWidth == -1)
{
text = "-";
enabled = false;
}
else
{
text = Integer.toString(valueWidth);
}
newWidth.setText(text);
int valueHeight = getHeight();
if (valueHeight == -1)
{
text = "-";
enabled = false;
}
else
{
text = Integer.toString(valueHeight);
}
newHeight.setText(text);
ok.setEnabled(enabled);
}
public void keyPressed(KeyEvent e)
{
updateLabels();
}
public void keyReleased(KeyEvent e)
{
updateLabels();
}
public void keyTyped(KeyEvent e)
{
updateLabels();
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/gui/awt/dialogs/GammaCorrectionDialog.java 0000664 0000000 0000000 00000006101 07741250134 030065 0 ustar /*
* GammaCorrectionDialog
*
* Copyright (c) 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.gui.awt.dialogs;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Dialog;
import java.awt.Frame;
import java.awt.Label;
import java.awt.Panel;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import net.sourceforge.jiu.apps.Strings;
/**
* A dialog to enter the parameters for a gamma correction operation.
* @author Marco Schmidt
*/
public class GammaCorrectionDialog extends Dialog implements ActionListener, KeyListener
{
private Button ok;
private Button cancel;
private TextField gammaTextField;
private boolean pressedOk;
private Double result;
private final double MAX_GAMMA;
/**
* Creates a GammaCorrectionDialog.
* @param owner the Frame this dialog will belong to
* @param strings Strings resource used for text messages
* @param initialValue the value to be set when the dialog pops up
* @param maxGamma the maximum allowed gamma value
*/
public GammaCorrectionDialog(Frame owner, Strings strings, double initialValue, double maxGamma)
{
super(owner, strings.get(Strings.ADJUST_GAMMA), true);
MAX_GAMMA = maxGamma;
Panel panel = new Panel(new BorderLayout());
panel.add(new Label(strings.get(Strings.ENTER_GAMMA_VALUE)), BorderLayout.CENTER);
gammaTextField = new TextField(Double.toString(initialValue));
gammaTextField.addKeyListener(this);
panel.add(gammaTextField, BorderLayout.EAST);
add(panel, BorderLayout.CENTER);
panel = new Panel();
ok = new Button(strings.get(Strings.OK));
ok.addActionListener(this);
cancel = new Button(strings.get(Strings.CANCEL));
cancel.addActionListener(this);
panel.add(ok);
panel.add(cancel);
add(panel, BorderLayout.SOUTH);
pack();
Dialogs.center(this);
}
/**
* Hides (closes) this dialog if the OK button was source of the action event
* (e.g. if the button was pressed).
*/
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == ok)
{
pressedOk = true;
result = getValue(gammaTextField);
setVisible(false);
}
else
if (e.getSource() == cancel)
{
setVisible(false);
}
}
private Double getValue(TextField tf)
{
if (tf == null)
{
return null;
}
double d;
try
{
d = (Double.valueOf(tf.getText())).doubleValue();
}
catch(NumberFormatException nfe)
{
return null;
}
if (d <= 0.0 || d > MAX_GAMMA)
{
return null;
}
return new Double(d);
}
public Double getValue()
{
return result;
}
public boolean hasPressedOk()
{
return pressedOk;
}
public void handleKeys(KeyEvent e)
{
ok.setEnabled(getValue(gammaTextField) != null);
}
public void keyPressed(KeyEvent e)
{
handleKeys(e);
}
public void keyReleased(KeyEvent e)
{
handleKeys(e);
}
public void keyTyped(KeyEvent e)
{
handleKeys(e);
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/gui/awt/dialogs/IntegerDialog.java 0000664 0000000 0000000 00000010026 10377273166 026422 0 ustar /*
* IntegerDialog
*
* Copyright (c) 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.gui.awt.dialogs;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Dialog;
import java.awt.Frame;
import java.awt.Label;
import java.awt.Panel;
import java.awt.Scrollbar;
import java.awt.TextComponent;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
/**
* An AWT dialog to select an int
value from a given interval.
*
* @author Marco Schmidt
*/
public class IntegerDialog extends Dialog implements ActionListener, AdjustmentListener, KeyListener
{
private Button cancel;
private int maxValue;
private int minValue;
private Button ok;
private Integer result;
private Scrollbar scrollbar;
private TextComponent valueTextField;
/**
* Creates an IntegerDialog, a modal dialog that lets the user select one int
* value from a given interval.
*
* @param owner the {@link java.awt.Frame} this dialog will belong to
* @param title the text that will be displayed in the title bar of the dialog
* @param message the message text that will be displayed in the upper part of the dialog
* @param minValue the minimum allowed int value to be selected by the user
* @param initialValue the int value that is selected when the dialog first pops up
* @param maxValue the maximum allowed int value to be selected by the user
* @param okText the value for OK (just "OK"
in English
* programs, may be different for other natural languages
* @param cancelText the value for Cancel (just "Cancel"
in English
* programs, may be different for other natural languages
*/
public IntegerDialog(Frame owner, String title, String message,
int minValue, int initialValue, int maxValue,
String okText, String cancelText)
{
super(owner, title, true);
this.minValue = minValue;
this.maxValue = maxValue;
add(new Label(message), BorderLayout.NORTH);
Panel panel = new Panel(new BorderLayout());
scrollbar = new Scrollbar(Scrollbar.HORIZONTAL, initialValue, 1, minValue, maxValue + 1);
scrollbar.addAdjustmentListener(this);
panel.add(scrollbar, BorderLayout.CENTER);
valueTextField = new TextField(Integer.toString(initialValue), 6);
valueTextField.addKeyListener(this);
panel.add(valueTextField, BorderLayout.EAST);
add(panel, BorderLayout.CENTER);
panel = new Panel();
ok = new Button(okText);
ok.addActionListener(this);
cancel = new Button(cancelText);
cancel.addActionListener(this);
panel.add(ok);
panel.add(cancel);
add(panel, BorderLayout.SOUTH);
pack();
Dialogs.center(this);
}
/**
* Hides (closes) this dialog if the OK button was source of the action event
* (e.g. if the button was pressed).
*/
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == ok)
{
result = new Integer(scrollbar.getValue());
setVisible(false);
}
else
if (e.getSource() == cancel)
{
setVisible(false);
}
}
public void adjustmentValueChanged(AdjustmentEvent e)
{
valueTextField.setText(Integer.toString(scrollbar.getValue()));
}
public Integer getValue()
{
return result;
}
public void handleKeys(KeyEvent e)
{
setScrollbarFromTextField();
}
public void keyPressed(KeyEvent e)
{
handleKeys(e);
}
public void keyReleased(KeyEvent e)
{
handleKeys(e);
}
public void keyTyped(KeyEvent e)
{
handleKeys(e);
}
private void setScrollbarFromTextField()
{
String text = valueTextField.getText().trim();
int number;
try
{
number = Integer.parseInt(text);
}
catch (NumberFormatException nfe)
{
return;
}
if (number < minValue || number > maxValue)
{
return;
}
scrollbar.setValue(number);
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/gui/awt/dialogs/ScaleDialog.java 0000664 0000000 0000000 00000013414 07741250134 026047 0 ustar /*
* ScaleDialog
*
* Copyright (c) 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.gui.awt.dialogs;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Checkbox;
import java.awt.Choice;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.Panel;
import java.awt.Rectangle;
import java.awt.TextComponent;
import java.awt.TextField;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import net.sourceforge.jiu.apps.Strings;
/**
* A dialog to enter the parameters for an image scaling operation.
* @author Marco Schmidt
*/
public class ScaleDialog extends Dialog implements ActionListener, KeyListener
{
private Button ok;
private Button cancel;
private TextComponent heightTextField;
private TextComponent widthTextField;
private Checkbox maintainAspectRatio;
private Choice types;
private boolean pressedOk;
private String oldWidthString;
private String oldHeightString;
private int oldWidth;
private int oldHeight;
private int type;
/**
* Creates an InfoDialog, a modal dialog to display a text message, centered on the desktop.
* @param owner the Frame this dialog will belong to
* @param strings the Strings resource used for text messages
* @param width the current width of the image
* @param height the current height of the image
* @param pickType determines whether the will be a Choice box for picking the type of scaling algorithm
* @param typeNames names of the image scaling algorithms
* @param initialType algorithm type to be initially selected
*/
public ScaleDialog(Frame owner, Strings strings, int width, int height, boolean pickType, String[] typeNames, int initialType)
{
super(owner, strings.get(Strings.SCALE_IMAGE), true);
pressedOk = false;
oldWidth = width;
oldWidthString = Integer.toString(oldWidth);
oldHeight = height;
oldHeightString = Integer.toString(oldHeight);
Panel panel = new Panel();
panel.setLayout(new GridLayout(0, 2));
Label widthLabel = new Label(strings.get(Strings.NEW_WIDTH));
widthTextField = new TextField(Integer.toString(width), 6);
widthTextField.addKeyListener(this);
Label heightLabel = new Label(strings.get(Strings.NEW_HEIGHT));
heightTextField = new TextField(Integer.toString(height), 6);
heightTextField.addKeyListener(this);
panel.add(widthLabel);
panel.add(widthTextField);
panel.add(heightLabel);
panel.add(heightTextField);
panel.add(new Label(""));
maintainAspectRatio = new Checkbox(strings.get(Strings.MAINTAIN_ASPECT_RATIO), true);
panel.add(maintainAspectRatio);
type = initialType;
if (pickType)
{
panel.add(new Label(strings.get(Strings.METHOD)));
types = new Choice();
for (int i = 0; i < typeNames.length; i++)
{
types.add(typeNames[i]);
}
types.select(initialType);
panel.add(types);
}
add(panel, BorderLayout.CENTER);
ok = new Button(strings.get(Strings.OK));
ok.addActionListener(this);
cancel = new Button(strings.get(Strings.CANCEL));
cancel.addActionListener(this);
panel = new Panel();
panel.add(ok);
panel.add(cancel);
add(panel, BorderLayout.SOUTH);
pack();
center();
}
/**
* Hides (closes) this dialog if the OK button was source of the action event
* (e.g. if the button was pressed).
*/
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == ok)
{
pressedOk = true;
setVisible(false);
}
else
if (e.getSource() == cancel)
{
setVisible(false);
}
}
/**
* Centers the dialog on screen.
*/
public void center()
{
Rectangle rect = getBounds();
int width = rect.width;
int height = rect.height;
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
setLocation((screenSize.width / 2) - (width / 2),
(screenSize.height / 2) - (height / 2));
}
public int getHeightValue()
{
return getValue(heightTextField);
}
public int getType()
{
if (types == null)
{
return type;
}
else
{
return types.getSelectedIndex();
}
}
private int getValue(TextComponent textField)
{
try
{
return Integer.parseInt(textField.getText());
}
catch (NumberFormatException nfe)
{
return -1;
}
}
public int getWidthValue()
{
return getValue(widthTextField);
}
public boolean hasPressedOk()
{
return pressedOk;
}
public void handleKeys(KeyEvent e)
{
if (e.getSource() == widthTextField)
{
String text = widthTextField.getText();
if (maintainAspectRatio.getState() && (!text.equals(oldWidthString)))
{
// compute height from current width
int w = getValue(widthTextField);
if (w > 0)
{
oldHeightString = Integer.toString((int)(w * (float)oldHeight / (float)oldWidth));
heightTextField.setText(oldHeightString);
}
}
}
else
if (e.getSource() == heightTextField)
{
String text = heightTextField.getText();
if (maintainAspectRatio.getState() && (!text.equals(oldHeightString)))
{
// compute width from current height
int h = getValue(heightTextField);
if (h > 0)
{
oldWidthString = Integer.toString((int)(h * (float)oldWidth / (float)oldHeight));
widthTextField.setText(oldWidthString);
}
}
}
oldWidthString = widthTextField.getText();
oldHeightString = heightTextField.getText();
}
public void keyPressed(KeyEvent e)
{
handleKeys(e);
}
public void keyReleased(KeyEvent e)
{
handleKeys(e);
}
public void keyTyped(KeyEvent e)
{
handleKeys(e);
}
}
././@LongLink 0000000 0000000 0000000 00000000152 00000000000 011563 L ustar root root java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/gui/awt/dialogs/MapToArbitraryPaletteDialog.java java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/gui/awt/dialogs/MapToArbitraryPaletteDialog0000664 0000000 0000000 00000012734 07741250134 030323 0 ustar /*
* MapToArbitraryPaletteDialog
*
* Copyright (c) 2001, 2002 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.gui.awt.dialogs;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Checkbox;
import java.awt.CheckboxGroup;
import java.awt.Choice;
import java.awt.Dialog;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import net.sourceforge.jiu.apps.Strings;
import net.sourceforge.jiu.color.dithering.ErrorDiffusionDithering;
/**
* A dialog to enter the parameters for an operation to map an RGB truecolor
* image to any given palette.
*
* @since 0.5.0
* @author Marco Schmidt
* @see net.sourceforge.jiu.color.quantization.ArbitraryPaletteQuantizer
*/
public class MapToArbitraryPaletteDialog extends Dialog implements
ActionListener
{
public static final int PALETTE_FILE = 0;
public static final int PALETTE_WEBSAFE = 1;
public static final int PALETTE_PALM_256_COLORS = 2;
public static final int PALETTE_PALM_16_COLORS = 3;
public static final int PALETTE_PALM_16_GRAY = 4;
public static final int PALETTE_PALM_4_GRAY = 5;
public static final int NUM_PALETTE_TYPES = 6;
private static final int[] PALETTE_STRING_CONSTANTS =
{
Strings.PALETTE_FROM_FILE,
Strings.WEBSAFE_PALETTE,
Strings.PALETTE_PALM_256_COLORS,
Strings.PALETTE_PALM_16_COLORS,
Strings.PALETTE_PALM_16_GRAY,
Strings.PALETTE_PALM_4_GRAY,
};
private static final int[] DITHERING_STRING_CONSTANTS =
{
Strings.DITHERING_NONE,
Strings.FLOYD_STEINBERG_ERROR_DIFFUSION,
Strings.STUCKI_ERROR_DIFFUSION,
Strings.BURKES_ERROR_DIFFUSION,
Strings.SIERRA_ERROR_DIFFUSION,
Strings.JARVIS_JUDICE_NINKE_ERROR_DIFFUSION,
Strings.STEVENSON_ARCE_ERROR_DIFFUSION
};
private static final int[] ERROR_DIFFUSION_TYPES =
{
ErrorDiffusionDithering.TYPE_FLOYD_STEINBERG,
ErrorDiffusionDithering.TYPE_STUCKI,
ErrorDiffusionDithering.TYPE_BURKES,
ErrorDiffusionDithering.TYPE_SIERRA,
ErrorDiffusionDithering.TYPE_JARVIS_JUDICE_NINKE,
ErrorDiffusionDithering.TYPE_STEVENSON_ARCE
};
private Button ok;
private Button cancel;
private Checkbox[] checkboxes;
private CheckboxGroup paletteType;
private Choice dithering;
private boolean pressedOk;
/**
* @param owner the Frame this dialog will belong to
*/
public MapToArbitraryPaletteDialog(Frame owner, Strings strings)
{
super(owner, strings.get(Strings.MAP_TO_ARBITRARY_PALETTE), true);
pressedOk = false;
// 1 (CENTER) main panel with components for the various options
Panel mainPanel = new Panel(new GridLayout(0, 1));
// 1.1 Label with message text
Panel panel = new Panel(new GridLayout(0, 1));
panel.add(new Label(strings.get(Strings.CHOOSE_PALETTE_TYPE)));
mainPanel.add(panel);
// 1.2 radio buttons (CheckboxGroup) with palette type
panel = new Panel(new GridLayout(0, 1));
paletteType = new CheckboxGroup();
checkboxes = new Checkbox[PALETTE_STRING_CONSTANTS.length];
boolean selected = true;
for (int i = 0; i < NUM_PALETTE_TYPES; i++)
{
checkboxes[i] = new Checkbox(strings.get(PALETTE_STRING_CONSTANTS[i]), paletteType, selected);
selected = false;
panel.add(checkboxes[i]);
}
mainPanel.add(panel);
// 1.3 Choice with dithering types
panel = new Panel();
panel.add(new Label(strings.get(Strings.DITHERING_METHOD)));
dithering = new Choice();
for (int i = 0; i < DITHERING_STRING_CONSTANTS.length; i++)
{
dithering.add(strings.get(DITHERING_STRING_CONSTANTS[i]));
}
dithering.select(1);
panel.add(dithering);
mainPanel.add(panel);
add(mainPanel, BorderLayout.CENTER);
// 2 (SOUTH) buttons OK and Cancel
panel = new Panel();
// 2.1 OK button
ok = new Button(strings.get(Strings.OK));
ok.addActionListener(this);
panel.add(ok);
// 2.2 Cancel button
cancel = new Button(strings.get(Strings.CANCEL));
cancel.addActionListener(this);
panel.add(cancel);
add(panel, BorderLayout.SOUTH);
pack();
Dialogs.center(this);
}
/**
* Hides (closes) this dialog if the OK button was source of the action event
* (e.g. if the button was pressed).
*/
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == ok)
{
pressedOk = true;
setVisible(false);
}
else
if (e.getSource() == cancel)
{
setVisible(false);
}
}
/**
* If the use of error diffusion was selected, this method
* returns on of the ErrorDiffusionDithering TYPE constants
*/
public int getErrorDiffusionType()
{
int sel = dithering.getSelectedIndex();
if (sel > 0 && sel <= ERROR_DIFFUSION_TYPES.length)
{
return ERROR_DIFFUSION_TYPES[sel - 1];
}
else
{
return -1;
}
}
/**
* Return the palette type (one of the PALETTE_xyz constants of this class)
* that is currently selected in the dialog.
*/
public int getPaletteType()
{
for (int i = 0; i < checkboxes.length; i++)
{
if (checkboxes[i].getState())
{
return i;
}
}
return -1;
}
/**
* Returns true if the OK button was pressed, false if
* it was the Cancel button.
*/
public boolean hasPressedOk()
{
return pressedOk;
}
/**
* Returns whether the use of one of the error diffusion
* algorithms is selected in the dialog.
*/
public boolean useErrorDiffusion()
{
return dithering.getSelectedIndex() > 0;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/gui/awt/dialogs/package.html 0000664 0000000 0000000 00000000335 07741250134 025314 0 ustar
AWT dialogs that are used in the jiuawt application.
././@LongLink 0000000 0000000 0000000 00000000147 00000000000 011567 L ustar root root java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/gui/awt/dialogs/HueSaturationValueDialog.java java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/gui/awt/dialogs/HueSaturationValueDialog.ja0000664 0000000 0000000 00000011627 07741250134 030265 0 ustar /*
* HueSaturationValueDialog
*
* Copyright (c) 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.gui.awt.dialogs;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Checkbox;
import java.awt.Color;
import java.awt.Dialog;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.Panel;
import java.awt.TextComponent;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import net.sourceforge.jiu.apps.Strings;
/**
* A dialog to enter the parameters for an hue/saturation/value adjustment operation.
* Saturation and value are specified as percentage values between -100 and 100,
* where 0 means no change.
* Hue can be specified optionally (a Choice component must be checked so
* that the hue value will be used); it is a value between 0 and 359.
*
* @since 0.5.0
* @author Marco Schmidt
* @see net.sourceforge.jiu.color.adjustment.HueSaturationValue
*/
public class HueSaturationValueDialog extends Dialog implements
ActionListener, ItemListener, KeyListener
{
private Button ok;
private Button cancel;
private Panel colorPanel;
private TextField hue;
private TextField saturation;
private TextField value;
private Checkbox setHue;
private boolean pressedOk;
/**
* @param owner the Frame this dialog will belong to
*/
public HueSaturationValueDialog(Frame owner, Strings strings, boolean initialSetHue, int h, int s, int v)
{
super(owner, strings.get(Strings.ADJUST_HUE_SATURATION_AND_VALUE), true);
pressedOk = false;
Panel panel = new Panel();
panel.setLayout(new GridLayout(0, 2));
setHue = new Checkbox(strings.get(Strings.SET_HUE), initialSetHue);
setHue.addItemListener(this);
panel.add(setHue);
colorPanel = new Panel();
panel.add(colorPanel);
panel.add(new Label(strings.get(Strings.HUE)));
hue = new TextField(Integer.toString(h));
hue.addKeyListener(this);
panel.add(hue);
panel.add(new Label(strings.get(Strings.SATURATION)));
saturation = new TextField(Integer.toString(s));
saturation.addKeyListener(this);
panel.add(saturation);
panel.add(new Label(strings.get(Strings.VALUE)));
value = new TextField(Integer.toString(v));
value.addKeyListener(this);
panel.add(value);
add(panel, BorderLayout.CENTER);
ok = new Button(strings.get(Strings.OK));
ok.addActionListener(this);
cancel = new Button(strings.get(Strings.CANCEL));
cancel.addActionListener(this);
panel = new Panel();
panel.add(ok);
panel.add(cancel);
add(panel, BorderLayout.SOUTH);
updateTextFields();
pack();
Dialogs.center(this);
}
/**
* Hides (closes) this dialog if the OK button was source of the action event
* (e.g. if the button was pressed).
*/
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == ok)
{
pressedOk = true;
setVisible(false);
}
else
if (e.getSource() == cancel)
{
setVisible(false);
}
}
public int getHue()
{
return getValue(hue);
}
public int getSaturation()
{
return getValue(saturation);
}
public int getValue()
{
return getValue(value);
}
/**
* Attempts to convert the content of the argument text component
* to an int
; if successful, returns that int, otherwise
* -1000 is returned.
* @param textField the text component that is supposed to hold an int value
* @return int representation of the text component's data
*/
private int getValue(TextComponent textField)
{
try
{
return Integer.parseInt(textField.getText());
}
catch (NumberFormatException nfe)
{
return -1000;
}
}
public boolean hasPressedOk()
{
return pressedOk;
}
public void itemStateChanged(ItemEvent e)
{
updateTextFields();
}
public boolean isHueSet()
{
return setHue.getState();
}
/**
* Computes width and height of new image and updates the
* corresponding labels.
* The labels will either display width and height or a single
* dash if the data in the text fields is invalid.
*/
private void updateTextFields()
{
hue.setEnabled(setHue.getState());
int h = getValue(hue);
int s = getValue(saturation);
int v = getValue(value);
boolean enabled = s >= -100 && s <= 100 && v >= -100 && v <= 100;
if (setHue.getState())
{
enabled = enabled && h >= 0 && h <= 359;
}
ok.setEnabled(enabled);
Color color = new Color(Color.HSBtoRGB(h / 360f, 1.0f, 1.0f));
colorPanel.setBackground(color);
}
public void keyPressed(KeyEvent e)
{
updateTextFields();
}
public void keyReleased(KeyEvent e)
{
updateTextFields();
}
public void keyTyped(KeyEvent e)
{
updateTextFields();
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/gui/awt/dialogs/ShearDialog.java 0000664 0000000 0000000 00000007060 07741250134 026062 0 ustar /*
* ShearDialog
*
* Copyright (c) 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.gui.awt.dialogs;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Dialog;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.Panel;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import net.sourceforge.jiu.apps.Strings;
import net.sourceforge.jiu.geometry.Shear;
/**
* An AWT dialog to enter the angle for a shearing operation.
* @author Marco Schmidt
*/
public class ShearDialog extends Dialog implements ActionListener, KeyListener
{
private Button ok;
private Button cancel;
private TextField angleTextField;
private boolean pressedOk;
private Double result;
private Label newWidthLabel;
private int imageWidth;
private int imageHeight;
/**
* Creates a ShearDialog.
* @param owner the Frame this dialog will belong to
*/
public ShearDialog(Frame owner, Strings strings, double initialValue, int imageWidth, int imageHeight)
{
super(owner, strings.get(Strings.SHEAR_IMAGE) + " (" + imageWidth + " x " + imageHeight + ")", true);
this.imageWidth = imageWidth;
this.imageHeight = imageHeight;
Panel panel = new Panel(new GridLayout(0, 2));
panel.add(new Label(strings.get(Strings.SHEAR_ENTER_ANGLE)));
angleTextField = new TextField(Double.toString(initialValue));
angleTextField.addKeyListener(this);
panel.add(angleTextField);
panel.add(new Label(strings.get(Strings.NEW_WIDTH)));
newWidthLabel = new Label("");
panel.add(newWidthLabel);
add(panel, BorderLayout.CENTER);
panel = new Panel();
ok = new Button(strings.get(Strings.OK));
ok.addActionListener(this);
cancel = new Button(strings.get(Strings.CANCEL));
cancel.addActionListener(this);
panel.add(ok);
panel.add(cancel);
add(panel, BorderLayout.SOUTH);
handleKeys(null);
pack();
Dialogs.center(this);
}
/**
* Hides (closes) this dialog if the OK button was source of the action event
* (e.g. if the button was pressed).
*/
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == ok)
{
pressedOk = true;
result = getValue(angleTextField);
setVisible(false);
}
else
if (e.getSource() == cancel)
{
setVisible(false);
}
}
private Double getValue(TextField tf)
{
if (tf == null)
{
return null;
}
double d;
try
{
d = (Double.valueOf(tf.getText())).doubleValue();
}
catch(NumberFormatException nfe)
{
return null;
}
if (d <= -90.0 || d >= 90.0)
{
return null;
}
return new Double(d);
}
public Double getValue()
{
return result;
}
public boolean hasPressedOk()
{
return pressedOk;
}
public void handleKeys(KeyEvent e)
{
Double d = getValue(angleTextField);
double angle = -90.0;
if (d != null)
{
angle = d.doubleValue();
}
String labelText;
if (angle > -90.0 && angle < 90.0)
{
ok.setEnabled(true);
int newWidth = Shear.computeNewImageWidth(imageWidth, imageHeight, angle);
labelText = Integer.toString(newWidth);
}
else
{
ok.setEnabled(false);
labelText = "-";
}
newWidthLabel.setText(labelText);
}
public void keyPressed(KeyEvent e)
{
handleKeys(e);
}
public void keyReleased(KeyEvent e)
{
handleKeys(e);
}
public void keyTyped(KeyEvent e)
{
handleKeys(e);
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/gui/awt/dialogs/OctreeDialog.java 0000664 0000000 0000000 00000012460 07741250134 026241 0 ustar /*
* OctreeDialog
*
* Copyright (c) 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.gui.awt.dialogs;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Choice;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.Panel;
import java.awt.Rectangle;
import java.awt.TextField;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import net.sourceforge.jiu.apps.Strings;
import net.sourceforge.jiu.color.dithering.ErrorDiffusionDithering;
/**
* A dialog to enter the parameters for an Octree color quantization operation.
* It also allows to enter the optional algorithms that can be applied in combination with Octree.
*
* @author Marco Schmidt
* @since 0.6.0
* @see MedianCutDialog
*/
public class OctreeDialog extends Dialog implements
ActionListener, KeyListener
{
public final int[] DITHERING_STRINGS =
{
Strings.DITHERING_NONE,
Strings.FLOYD_STEINBERG_ERROR_DIFFUSION,
Strings.STUCKI_ERROR_DIFFUSION,
Strings.BURKES_ERROR_DIFFUSION,
Strings.SIERRA_ERROR_DIFFUSION,
Strings.JARVIS_JUDICE_NINKE_ERROR_DIFFUSION,
Strings.STEVENSON_ARCE_ERROR_DIFFUSION
};
public final int[] DITHERING_TYPES =
{
0,
ErrorDiffusionDithering.TYPE_FLOYD_STEINBERG,
ErrorDiffusionDithering.TYPE_STUCKI,
ErrorDiffusionDithering.TYPE_BURKES,
ErrorDiffusionDithering.TYPE_SIERRA,
ErrorDiffusionDithering.TYPE_JARVIS_JUDICE_NINKE,
ErrorDiffusionDithering.TYPE_STEVENSON_ARCE
};
private Button ok;
private Button cancel;
private TextField numColorsField;
private Choice outputColorType;
private Choice dithering;
private boolean pressedOk;
/**
* Creates a modal dialog to enter the parameter.
* @param owner the parent of this modal dialog
* @param strings an object to get String constants in the current language
* @param numColors the number of colors in the resulting image
* @param paletted if true, the output image will be paletted, otherwise truecolor
*/
public OctreeDialog(Frame owner, Strings strings, int numColors, boolean paletted)
{
super(owner, strings.get(Strings.OCTREE_COLOR_QUANTIZATION), true);
pressedOk = false;
Panel panel = new Panel();
panel.setLayout(new GridLayout(0, 2));
panel.add(new Label(strings.get(Strings.NUM_COLORS)));
numColorsField = new TextField(Integer.toString(numColors), 6);
numColorsField.addKeyListener(this);
panel.add(numColorsField);
/*panel.add(new Label(strings.get(Strings.OUTPUT_COLOR_TYPE)));
outputColorType = new Choice();
outputColorType.add(strings.get(Strings.OUTPUT_COLOR_TYPE_PALETTED));
outputColorType.add(strings.get(Strings.OUTPUT_COLOR_TYPE_RGB));
outputColorType.select(paletted ? 0 : 1);
panel.add(outputColorType);*/
panel.add(new Label(strings.get(Strings.DITHERING_METHOD)));
dithering = new Choice();
for (int i = 0; i < DITHERING_STRINGS.length; i++)
{
dithering.add(strings.get(DITHERING_STRINGS[i]));
}
dithering.select(1);
panel.add(dithering);
add(panel, BorderLayout.CENTER);
ok = new Button(strings.get(Strings.OK));
ok.addActionListener(this);
cancel = new Button(strings.get(Strings.CANCEL));
cancel.addActionListener(this);
panel = new Panel();
panel.add(ok);
panel.add(cancel);
add(panel, BorderLayout.SOUTH);
pack();
center();
}
/**
* Hides (closes) this dialog if the OK button was source of the action event
* (e.g. if the button was pressed).
*/
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == ok)
{
pressedOk = true;
setVisible(false);
}
else
if (e.getSource() == cancel)
{
setVisible(false);
}
}
/**
* Centers the dialog on screen.
*/
public void center()
{
Rectangle rect = getBounds();
int width = rect.width;
int height = rect.height;
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
setLocation((screenSize.width / 2) - (width / 2),
(screenSize.height / 2) - (height / 2));
}
public int getErrorDiffusion()
{
int sel = dithering.getSelectedIndex();
if (sel > 0)
{
return DITHERING_TYPES[sel];
}
else
{
return -1;
}
}
private int getIntValue(TextField textField)
{
try
{
return Integer.parseInt(textField.getText());
}
catch (NumberFormatException nfe)
{
return -1;
}
}
public int getNumColors()
{
return getIntValue(numColorsField);
}
public boolean hasPressedOk()
{
return pressedOk;
}
public boolean isOutputTypePaletted()
{
return outputColorType.getSelectedIndex() == 0;
}
public void keyPressed(KeyEvent e)
{
updateOkButton();
}
public void keyReleased(KeyEvent e)
{
updateOkButton();
}
public void keyTyped(KeyEvent e)
{
updateOkButton();
}
private void updateOkButton()
{
int nc = getNumColors();
boolean enabled = nc >= 1 && nc <= 256;
ok.setEnabled(enabled);
}
public boolean useErrorDiffusion()
{
return dithering.getSelectedIndex() > 0;
}
public boolean useNoDithering()
{
return dithering.getSelectedIndex() == 0;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/gui/awt/dialogs/Dialogs.java 0000664 0000000 0000000 00000003714 10572433445 025270 0 ustar /*
* Dialogs
*
* Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.gui.awt.dialogs;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
/**
* Convenience class that provides a number of static helper methods to deal with dialogs.
* @author Marco Schmidt
*/
public class Dialogs
{
private Dialogs()
{
}
/**
* Centers the argument window on screen.
*/
public static void center(Window window)
{
if (window == null)
{
return;
}
Rectangle rect = window.getBounds();
int width = rect.width;
int height = rect.height;
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
window.setLocation((screenSize.width / 2) - (width / 2),
(screenSize.height / 2) - (height / 2));
}
/**
* Creates a new IntegerDialog, displays it and returns the Integer
* value specified by the user (or null if the dialog was canceled).
* @param owner frame from which the dialog is spawned
* @param title text for the title bar of the dialog
* @param message message displayed in the dialog
* @param minValue minimal allowed integer value to be entered by the user
* @param initialValue initial integer value shown in the dialog
* @param maxValue maximal allowed integer value to be entered by the user
* @param okText the text for the OK button
* @param cancelText the text for the cancel button
* @return the specified integer value or null if the Cancel button was pressed
*/
public static Integer getInteger(Frame owner, String title, String message,
int minValue, int initialValue, int maxValue, String okText,
String cancelText)
{
IntegerDialog dialog = new IntegerDialog(owner, title, message,
minValue, initialValue, maxValue, okText, cancelText);
dialog.setVisible(true);
return dialog.getValue();
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/gui/awt/dialogs/MedianCutDialog.java 0000664 0000000 0000000 00000020503 07741250134 026666 0 ustar /*
* MedianCutDialog
*
* Copyright (c) 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.gui.awt.dialogs;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Choice;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.Panel;
import java.awt.Rectangle;
import java.awt.TextField;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import net.sourceforge.jiu.apps.Strings;
import net.sourceforge.jiu.color.dithering.ErrorDiffusionDithering;
import net.sourceforge.jiu.color.quantization.MedianCutQuantizer;
/**
* A dialog to enter the parameters for a Median Cut color quantization operation.
* It also allows to enter the optional algorithms that can be applied in combination with Median Cut.
* @author Marco Schmidt
*/
public class MedianCutDialog extends Dialog implements
ActionListener, ItemListener, KeyListener
{
public final int[][] METHODS =
{
{
MedianCutQuantizer.METHOD_REPR_COLOR_WEIGHTED_AVERAGE,
MedianCutQuantizer.METHOD_REPR_COLOR_AVERAGE,
MedianCutQuantizer.METHOD_REPR_COLOR_MEDIAN
},
{
Strings.METHOD_REPR_COLOR_WEIGHTED_AVERAGE,
Strings.METHOD_REPR_COLOR_AVERAGE,
Strings.METHOD_REPR_COLOR_MEDIAN
}
};
public final int[] ERROR_DIFFUSION_STRINGS =
{
Strings.FLOYD_STEINBERG_ERROR_DIFFUSION,
Strings.STUCKI_ERROR_DIFFUSION,
Strings.BURKES_ERROR_DIFFUSION,
Strings.SIERRA_ERROR_DIFFUSION,
Strings.JARVIS_JUDICE_NINKE_ERROR_DIFFUSION,
Strings.STEVENSON_ARCE_ERROR_DIFFUSION
};
public final int[] ERROR_DIFFUSION_TYPES =
{
ErrorDiffusionDithering.TYPE_FLOYD_STEINBERG,
ErrorDiffusionDithering.TYPE_STUCKI,
ErrorDiffusionDithering.TYPE_BURKES,
ErrorDiffusionDithering.TYPE_SIERRA,
ErrorDiffusionDithering.TYPE_JARVIS_JUDICE_NINKE,
ErrorDiffusionDithering.TYPE_STEVENSON_ARCE
};
private Button ok;
private Button cancel;
private TextField numColorsField;
private Choice outputColorType;
private Choice reprColorMethod;
private Choice algorithms;
private Choice errorDiffusion;
private TextField numPassesField;
private TextField tauField;
private boolean pressedOk;
/**
* Creates a modal dialog to enter the parameter.
* @param owner the parent of this modal dialog
* @param strings an object to get String constants in the current language
* @param numColors the number of colors in the resulting image
* @param representativeColorMethod the method to determine the representative color from a set of colors
* @param paletted if true, the output image will be paletted, otherwise truecolor
* @param numPasses number of contour removal iterations
* @param initialTau maximum distance for two colors to be considered similar in contour removal
*/
public MedianCutDialog(Frame owner, Strings strings, int numColors, int representativeColorMethod, boolean paletted, int numPasses, double initialTau)
{
super(owner, strings.get(Strings.MEDIAN_CUT_COLOR_QUANTIZATION), true);
pressedOk = false;
Panel panel = new Panel();
panel.setLayout(new GridLayout(0, 2));
panel.add(new Label(strings.get(Strings.NUM_COLORS)));
numColorsField = new TextField(Integer.toString(numColors), 6);
numColorsField.addKeyListener(this);
panel.add(numColorsField);
panel.add(new Label(strings.get(Strings.OUTPUT_COLOR_TYPE)));
outputColorType = new Choice();
outputColorType.add(strings.get(Strings.OUTPUT_COLOR_TYPE_PALETTED));
outputColorType.add(strings.get(Strings.OUTPUT_COLOR_TYPE_RGB));
outputColorType.select(paletted ? 0 : 1);
panel.add(outputColorType);
panel.add(new Label(strings.get(Strings.METHOD_REPR_COLOR)));
reprColorMethod = new Choice();
for (int i = 0; i < METHODS[0].length; i++)
{
reprColorMethod.add(strings.get(METHODS[1][i]));
if (representativeColorMethod == METHODS[0][i])
{
reprColorMethod.select(i);
}
}
panel.add(reprColorMethod);
panel.add(new Label(strings.get(Strings.OUTPUT_QUALITY_IMPROVEMENT_ALGORITHM)));
algorithms = new Choice();
algorithms.add(strings.get(Strings.ALGORITHMS_NONE));
algorithms.add(strings.get(Strings.ERROR_DIFFUSION));
algorithms.add(strings.get(Strings.CONTOUR_REMOVAL));
algorithms.select(1);
algorithms.addItemListener(this);
panel.add(algorithms);
panel.add(new Label(strings.get(Strings.ERROR_DIFFUSION)));
errorDiffusion = new Choice();
for (int i = 0; i < ERROR_DIFFUSION_STRINGS.length; i++)
{
errorDiffusion.add(strings.get(ERROR_DIFFUSION_STRINGS[i]));
}
errorDiffusion.select(0);
panel.add(errorDiffusion);
panel.add(new Label(strings.get(Strings.CONTOUR_REMOVAL_NUM_PASSES)));
numPassesField = new TextField(Integer.toString(numPasses));
numPassesField.addKeyListener(this);
panel.add(numPassesField);
panel.add(new Label(strings.get(Strings.CONTOUR_REMOVAL_TAU)));
tauField = new TextField(Double.toString(initialTau));
tauField.addKeyListener(this);
panel.add(tauField);
add(panel, BorderLayout.CENTER);
ok = new Button(strings.get(Strings.OK));
ok.addActionListener(this);
cancel = new Button(strings.get(Strings.CANCEL));
cancel.addActionListener(this);
updateStates();
panel = new Panel();
panel.add(ok);
panel.add(cancel);
add(panel, BorderLayout.SOUTH);
pack();
center();
}
/**
* Hides (closes) this dialog if the OK button was source of the action event
* (e.g. if the button was pressed).
*/
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == ok)
{
pressedOk = true;
setVisible(false);
}
else
if (e.getSource() == cancel)
{
setVisible(false);
}
}
/**
* Centers the dialog on screen.
*/
public void center()
{
Rectangle rect = getBounds();
int width = rect.width;
int height = rect.height;
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
setLocation((screenSize.width / 2) - (width / 2),
(screenSize.height / 2) - (height / 2));
}
public int getErrorDiffusion()
{
if (algorithms.getSelectedIndex() == 1)
{
return ERROR_DIFFUSION_TYPES[errorDiffusion.getSelectedIndex()];
}
else
{
return -1;
}
}
private double getDoubleValue(TextField textField)
{
try
{
Double d = new Double(textField.getText());
return d.doubleValue();
}
catch (NumberFormatException nfe)
{
return Double.NaN;
}
}
private int getIntValue(TextField textField)
{
try
{
return Integer.parseInt(textField.getText());
}
catch (NumberFormatException nfe)
{
return -1;
}
}
public int getNumColors()
{
return getIntValue(numColorsField);
}
public int getNumPasses()
{
return getIntValue(numPassesField);
}
public int getReprColorMethod()
{
return METHODS[0][reprColorMethod.getSelectedIndex()];
}
public double getTau()
{
return getDoubleValue(tauField);
}
public boolean hasPressedOk()
{
return pressedOk;
}
public boolean isOutputTypePaletted()
{
return outputColorType.getSelectedIndex() == 0;
}
public void itemStateChanged(ItemEvent event)
{
if (event.getSource() == algorithms)
{
updateStates();
}
}
public void keyPressed(KeyEvent e)
{
updateOkButton();
}
public void keyReleased(KeyEvent e)
{
updateOkButton();
}
public void keyTyped(KeyEvent e)
{
updateOkButton();
}
private void updateOkButton()
{
int nc = getNumColors();
boolean enabled = nc >= 1 && nc <= 256;
if (enabled && algorithms.getSelectedIndex() == 2)
{
enabled = getTau() >= 0.0 && getNumPasses() >= 1;
}
ok.setEnabled(enabled);
}
private void updateStates()
{
int algorithmSelection = algorithms.getSelectedIndex();
boolean ed = algorithmSelection == 1;
errorDiffusion.setEnabled(ed);
ed = algorithmSelection == 2;
tauField.setEnabled(ed);
numPassesField.setEnabled(ed);
}
public boolean useContourRemoval()
{
return algorithms.getSelectedIndex() == 2;
}
public boolean useErrorDiffusion()
{
return algorithms.getSelectedIndex() == 1;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/gui/awt/dialogs/YesNoDialog.java 0000664 0000000 0000000 00000005527 07741250134 026063 0 ustar /*
* YesNoDialog
*
* Copyright (c) 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.gui.awt.dialogs;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Dialog;
import java.awt.Frame;
import java.awt.Label;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import net.sourceforge.jiu.apps.Strings;
/**
* A dialog that asks a question and offers a Yes and a No button
* (and optionally a Cancel button).
* @author Marco Schmidt
* @since 0.11.0
*/
public class YesNoDialog extends Dialog implements ActionListener
{
/**
* Will be returned in {@link #getResult} if the YES button was chosen.
*/
public static final int RESULT_YES = 0;
/**
* Will be returned in {@link #getResult} if the NO button was chosen.
*/
public static final int RESULT_NO = 1;
/**
* Will be returned in {@link #getResult} if the CANCEL button was chosen.
*/
public static final int RESULT_CANCEL = 2;
private Button yes;
private Button no;
private Button cancel;
private int result;
/**
* Creates a new YesNoDialog object and shows it centered on the screen.
* @param owner the frame that owns this modal dialog
* @param strings the String resources
* @param titleIndex the index into the String resource of the title text
* @param questionIndex the index into the String resource of the question text
* @param includeCancel determines whether a third button 'Cancel' will be included
*/
public YesNoDialog(Frame owner, Strings strings, int titleIndex, int questionIndex, boolean includeCancel)
{
super(owner, strings.get(titleIndex), true);
add(new Label(strings.get(questionIndex)), BorderLayout.CENTER);
yes = new Button(strings.get(Strings.YES));
yes.addActionListener(this);
no = new Button(strings.get(Strings.NO));
no.addActionListener(this);
cancel = new Button(strings.get(Strings.CANCEL));
cancel.addActionListener(this);
Panel panel = new Panel();
panel.add(yes);
panel.add(no);
if (includeCancel)
{
panel.add(cancel);
}
add(panel, BorderLayout.SOUTH);
pack();
Dialogs.center(this);
}
/**
* Hides (closes) this dialog if the OK button was source of the action event
* (e.g. if the button was pressed).
*/
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == yes)
{
result = RESULT_YES;
setVisible(false);
}
else
if (e.getSource() == no)
{
result = RESULT_NO;
setVisible(false);
}
else
if (e.getSource() == cancel)
{
result = RESULT_CANCEL;
setVisible(false);
}
}
/**
* Returns one of the RESULT_xyz constants of this class.
* @return the RESULT constant of the button which the user has chosen
*/
public int getResult()
{
return result;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/gui/awt/dialogs/InfoDialog.java 0000664 0000000 0000000 00000004342 07741250134 025713 0 ustar /*
* InfoDialog
*
* Copyright (c) 2000, 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.gui.awt.dialogs;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Panel;
import java.awt.Rectangle;
import java.awt.TextArea;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/**
* A modal AWT dialog that displays text in a non-editable text area component
* (so that it can be selected and easily copied to the system's clipboard).
* Provides an OK button so that user can remove the dialog.
* @author Marco Schmidt
*/
public class InfoDialog extends Dialog implements ActionListener
{
private Button ok;
private TextArea textArea;
/**
* Creates an InfoDialog, a modal dialog to display a text message, centered on the desktop.
* @param owner the Frame this dialog will belong to
* @param title the text that will be displayed in the title bar of the dialog
* @param text the message text that will be displayed in the main part of the dialog
*/
public InfoDialog(Frame owner, String title, String text)
{
super(owner, title, true);
ok = new Button("OK");
ok.addActionListener(this);
Panel panel = new Panel();
panel.add(ok);
add(panel, BorderLayout.SOUTH);
textArea = new TextArea(text);
textArea.setEditable(false);
textArea.setSize(textArea.getMinimumSize());
//ScrollPane scrollPane = new ScrollPane(ScrollPane.SCROLLBARS_AS_NEEDED);
//scrollPane.add(textArea);
add(textArea);
pack();
center();
}
/**
* Hides (closes) this dialog if the OK button was source of the action event
* (e.g. if the button was pressed).
*/
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == ok)
{
setVisible(false);
}
}
/**
* Centers the dialog on screen.
*/
public void center()
{
Rectangle rect = getBounds();
int width = rect.width;
int height = rect.height;
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
setLocation((screenSize.width / 2) - (width / 2),
(screenSize.height / 2) - (height / 2));
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/gui/awt/BufferedRGB24Image.java 0000664 0000000 0000000 00000023667 07741250134 025457 0 ustar /*
* BufferedRGB24Image
*
* Copyright (c) 2002 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.gui.awt;
import java.awt.image.BufferedImage;
import net.sourceforge.jiu.data.PixelImage;
import net.sourceforge.jiu.data.RGB24Image;
/**
* A bridge class to use {@link java.awt.image.BufferedImage} objects (class defined
* in the standard runtime library, package java.awt.image
) as
* {@link net.sourceforge.jiu.data.RGB24Image} objects within JIU.
* This class encapsulates a single {@link java.awt.image.BufferedImage} object.
* It enables reusing existing BufferedImage objects as input or
* output of JIU operations,
* removing the necessity for the conversion step from java.awt.Image
* to net.sourceforge.jiu.data.PixelImage
(or vice versa)
* and thus reducing memory consumption.
* The name of this class is a combination of BufferedImage (the class of the object
* that is encapsulated) and RGB24Image (the JIU image data interface).
*
* Internally, this class uses {@link java.awt.image.BufferedImage}'s getRGB and * setRGB methods to access image data. * This approach is slower than working directly on the BufferedImage's data * buffers. * However, using getRGB and setRGB, this class will work with all types of BufferedImage objects. *
* Note that while the abstract java.awt.Image
class existed from the very
* beginning (version 1.0) of the Java runtime library, java.awt.image.BufferedImage
* has not been added until version 1.2.
*
* import java.awt.image.BufferedImage; * import java.io.File; * import javax.imageio.ImageIO; * import net.sourceforge.jiu.color.Invert; * import net.sourceforge.jiu.data.PixelImage; * import net.sourceforge.jiu.gui.awt.BufferedRGB24Image; * ... * BufferedImage bufferedImage = ImageIO.read(new File("image.jpg")); * BufferedRGB24Image image = new BufferedRGB24Image(bufferedImage); * Invert invert = new Invert(); * invert.setInputImage(image); * invert.process(); * PixelImage outputImage = invert.getOutputImage(); ** If you can be sure that an image object can be input and output * image at the same time (as is the case with some operations), you * can even work with only one BufferedRGB24Image object. * Invert is one of these operations, so the following would work: *
* Invert invert = new Invert(); * invert.setInputImage(image); * invert.setOutputImage(image); * invert.process(); * // image now is inverted ** * @author Marco Schmidt * @since 0.10.0 */ public class BufferedRGB24Image implements RGB24Image { private static final int RED_SHIFT = 16; private static final int GREEN_SHIFT = 8; private static final int BLUE_SHIFT = 0; /** * Masks for the three RGB channels. * RGB_CLEAR[i] is an int with all bits on, except for those occupied by the channel i. * RGB_CLEAR[i] can thus be used to bitwise AND an ARGB value so that the sample for channel i will be cleared. */ private static final int[] RGB_CLEAR = new int[3]; private static final int[] RGB_SHIFT = new int[3]; static { RGB_SHIFT[INDEX_RED] = RED_SHIFT; RGB_SHIFT[INDEX_GREEN] = GREEN_SHIFT; RGB_SHIFT[INDEX_BLUE] = BLUE_SHIFT; RGB_CLEAR[INDEX_RED] = 0xff00ffff; RGB_CLEAR[INDEX_GREEN] = 0xffff00ff; RGB_CLEAR[INDEX_BLUE] = 0xffffff00; } private final int HEIGHT; private final BufferedImage image; private final int WIDTH; /** * Creates a new BufferedRGB24Image object, storing the argument * BufferedImage object internally. * All image data access will be delegated to that BufferedImage object's methods. * @param bufferedImage the underlying BufferedImage object for this BufferedRGB24Image object */ public BufferedRGB24Image(BufferedImage bufferedImage) { image = bufferedImage; if (image == null) { throw new IllegalArgumentException("Argument image object must not be null."); } WIDTH = image.getWidth(); HEIGHT = image.getHeight(); } /** * Sets all the RGB samples in this image to the argument, keeping * the alpha value. * @param newValue all samples in the image will be set to this value */ public void clear(byte newValue) { final int RGB = (newValue & 0xff) | (newValue & 0xff) << 8 | (newValue & 0xff) << 16; for (int y = 0; y < getHeight(); y++) { for (int x = 0; x < getWidth(); x++) { int rgba = image.getRGB(x, y); rgba = (rgba & 0xff000000) | RGB; image.setRGB(x, y, rgba); } } } public void clear(int newValue) { clear((byte)newValue); } public void clear(int channelIndex, byte newValue) { final int MASK = RGB_CLEAR[channelIndex]; final int SAMPLE = (newValue & 0xff) << RGB_SHIFT[channelIndex]; for (int y = 0; y < getHeight(); y++) { for (int x = 0; x < getWidth(); x++) { int rgba = image.getRGB(x, y); rgba = (rgba & MASK) | SAMPLE; image.setRGB(x, y, rgba); } } } public void clear(int channelIndex, int newValue) { clear(channelIndex, (byte)newValue); } public PixelImage createCompatibleImage(int width, int height) { BufferedImage newBufferedImage = new BufferedImage(width, height, image.getType()); return new BufferedRGB24Image(newBufferedImage); } public PixelImage createCopy() { BufferedImage newBufferedImage = new BufferedImage(getWidth(), getHeight(), image.getType()); image.copyData(newBufferedImage.getRaster()); return new BufferedRGB24Image(newBufferedImage); } public long getAllocatedMemory() { /* actually, number of pixels times 4 is just a guess, BufferedImage allows for all kinds of data buffers; for a more accurate approximation these data buffers must be examined */ return 4L * (long)getWidth() * (long)getHeight(); } public int getBitsPerPixel() { return 24; } public byte getByteSample(int x, int y) { return getByteSample(0, x, y); } public byte getByteSample(int channelIndex, int x, int y) { return (byte)((image.getRGB(x, y) >> RGB_SHIFT[channelIndex]) & 0xff); } public void getByteSamples(int channelIndex, int x, int y, int w, int h, byte[] dest, int destOffset) { final int SHIFT = RGB_SHIFT[channelIndex]; int[] row = new int[w]; while (h-- > 0) { image.getRGB(x, y++, w, 1, row, 0, w); int columns = w; int rowIndex = 0; while (columns-- > 0) { dest[destOffset++] = (byte)((row[rowIndex++] >> SHIFT) & 0xff); } } } public void getByteSamples(int x, int y, int w, int h, byte[] dest, int destOffset) { getByteSamples(0, x, y, w, h, dest, destOffset); } public int getHeight() { return HEIGHT; } public Class getImageType() { return RGB24Image.class; } public int getMaxSample(int channel) { if (channel == INDEX_BLUE || channel == INDEX_RED || channel == INDEX_GREEN) { return 255; } else { throw new IllegalArgumentException("Not a valid channel index: " + channel); } } public int getNumChannels() { return 3; } public int getSample(int x, int y) { return getSample(0, x, y); } public int getSample(int channelIndex, int x, int y) { return (image.getRGB(x, y) >> RGB_SHIFT[channelIndex]) & 0xff; } public void getSamples(int x, int y, int w, int h, int[] dest, int destOffs) { getSamples(0, x, y, w, h, dest, destOffs); } public void getSamples(int channelIndex, int x, int y, int w, int h, int[] dest, int destOffs) { final int SHIFT = RGB_SHIFT[channelIndex]; int[] row = new int[w]; while (h-- > 0) { image.getRGB(x, y++, w, 1, row, 0, w); int columns = w; int rowIndex = 0; while (columns-- > 0) { dest[destOffs++] = (row[rowIndex++] >> SHIFT) & 0xff; } } } public int getWidth() { return WIDTH; } public void putByteSample(int channelIndex, int x, int y, byte newValue) { int argb = image.getRGB(x, y) & RGB_CLEAR[channelIndex]; image.setRGB(x, y, argb | ((newValue & 0xff) << RGB_SHIFT[channelIndex])); } public void putByteSample(int x, int y, byte newValue) { putByteSample(0, x, y, newValue); } public void putByteSamples(int channelIndex, int x, int y, int w, int h, byte[] src, int srcOffset) { final int SHIFT = RGB_SHIFT[channelIndex]; final int MASK = RGB_CLEAR[channelIndex]; int[] row = new int[w]; while (h-- > 0) { image.getRGB(x, y, w, 1, row, 0, w); int columns = w; int rowIndex = 0; while (columns-- > 0) { int argb = row[rowIndex] & MASK; row[rowIndex++] = argb | ((src[srcOffset++] & 0xff) << SHIFT); } image.setRGB(x, y++, w, 1, row, 0, w); } } public void putByteSamples(int x, int y, int w, int h, byte[] src, int srcOffset) { putByteSamples(0, x, y, w, h, src, srcOffset); } public void putSample(int x, int y, int newValue) { putSample(0, x, y, newValue); } public void putSample(int channelIndex, int x, int y, int newValue) { int argb = image.getRGB(x, y) & RGB_CLEAR[channelIndex]; image.setRGB(x, y, argb | (newValue << RGB_SHIFT[channelIndex])); } public void putSamples(int channelIndex, int x, int y, int w, int h, int[] src, int srcOffset) { final int SHIFT = RGB_SHIFT[channelIndex]; final int MASK = RGB_CLEAR[channelIndex]; int[] row = new int[w]; while (h-- > 0) { image.getRGB(x, y, w, 1, row, 0, w); int columns = w; int rowIndex = 0; while (columns-- > 0) { int argb = row[rowIndex] & MASK; row[rowIndex++] = argb | (src[srcOffset++] << SHIFT); } image.setRGB(x, y++, w, 1, row, 0, w); } } } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/gui/awt/JiuAwtFrame.java 0000664 0000000 0000000 00000023554 10572433573 024450 0 ustar /* * JiuAwtFrame * * Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.gui.awt; import java.awt.BorderLayout; import java.awt.Cursor; import java.awt.Dimension; import java.awt.Frame; import java.awt.Image; import java.awt.Label; import java.awt.ScrollPane; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ComponentListener; import java.awt.event.ComponentEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import net.sourceforge.jiu.apps.EditorState; import net.sourceforge.jiu.apps.ImageDescriptionCreator; import net.sourceforge.jiu.apps.JiuInfo; import net.sourceforge.jiu.apps.StringIndexConstants; import net.sourceforge.jiu.apps.Strings; import net.sourceforge.jiu.data.PixelImage; import net.sourceforge.jiu.gui.awt.AwtMenuWrapper; import net.sourceforge.jiu.gui.awt.ImageCanvas; import net.sourceforge.jiu.gui.awt.dialogs.InfoDialog; import net.sourceforge.jiu.ops.ProgressListener; /** * The frame class for the AWT demo program {@link net.sourceforge.jiu.apps.jiuawt}. * @author Marco Schmidt * @since 0.8.0 */ public class JiuAwtFrame extends Frame implements ActionListener, ComponentListener, JiuInfo, ProgressListener { /** * The name of this application, jiuawt, plus the version number taken * from {@link JiuInfo}. * Example:
jiuawt 0.8.0
.
* Will be displayed in the title bar of this frame.
*/
public static final String APP_NAME = "jiuawt " + JiuInfo.JIU_VERSION;
static final long serialVersionUID = 2592450425245L;
private EditorState editor;
private AwtMenuWrapper menuWrapper;
private AwtOperationProcessor processor;
private Label statusBar;
private ScrollPane scrollPane;
private ImageCanvas canvas;
/**
* Create an object of this class, using the argument editor
* state.
* String resources to initialize the menu etc. will be taken
* from the EditorState object's Strings variable
* @param editorState EditorState object used by this frame
*/
public JiuAwtFrame(EditorState editorState)
{
super(APP_NAME);
processor = new AwtOperationProcessor(editorState, this);
editor = editorState;
editor.addProgressListener(this);
addComponentListener(this);
addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
processor.fileExit();
}
});
// MENU
menuWrapper = new AwtMenuWrapper(editor.getStrings(), this);
setMenuBar(menuWrapper.getMenuBar());
menuWrapper.updateEnabled(processor);
// IMAGE CANVAS
// STATUS BAR
statusBar = new Label("");
add(statusBar, BorderLayout.SOUTH);
maximize();
//pack();
repaint();
setVisible(true);
if (editor.getStartupImageName() != null)
{
processor.fileOpen(null);
}
}
/**
* Processes event objects that get created when menu items are
* picked.
* Determines the {@link net.sourceforge.jiu.apps.MenuIndexConstants} value for a given
* event object and calls the internal {@link AwtOperationProcessor}
* object's process method with the menu value.
* The operation will then be performed.
* @param e the ActionEvent object
*/
public void actionPerformed(ActionEvent e)
{
Object source = e.getSource();
int index = menuWrapper.findIndex(source);
if (index != -1)
{
processor.process(index);
}
}
public void componentHidden(ComponentEvent e)
{
}
public void componentMoved(ComponentEvent e)
{
}
public void componentResized(ComponentEvent e)
{
if (scrollPane != null)
{
canvas.computeZoomToFitSize();
scrollPane.doLayout();
}
}
public void componentShown(ComponentEvent e)
{
}
/**
* Maximize the frame on the desktop.
* There is no such function in the 1.1 AWT (was added in 1.4), so
* this class determines the screen size and sets the frame to be
* a little smaller than that (to make up for task bars etc.).
* So this is just a heuristical approach.
*/
public void maximize()
{
/*
The following line:
setExtendedState(getExtendedState() | MAXIMIZED_BOTH);
does a nice maximization, but works only with Java 1.4+
*/
Toolkit toolkit = Toolkit.getDefaultToolkit();
if (toolkit == null)
{
return;
}
Dimension screenSize = toolkit.getScreenSize();
if (screenSize == null)
{
return;
}
int w = screenSize.width;
int h = screenSize.height;
int x = 20;
int y = 80;
setLocation(x / 2, y / 2);
setSize(w - x, h - y);
}
/**
* Displays the argument text in a message box with
* error in the title bar.
* @param text the error message to be displayed
*/
public void showError(String text)
{
Strings strings = editor.getStrings();
showInfo(strings.get(StringIndexConstants.ERROR_MESSAGE), text);
}
/**
* Sets the current cursor to be {@link java.awt.Cursor#DEFAULT_CURSOR}.
*/
public void setDefaultCursor()
{
Cursor cursor = new Cursor(Cursor.DEFAULT_CURSOR);
setCursor(cursor);
}
/**
* If an image is currently loaded,
*/
public void setOriginalSize()
{
if (canvas != null && !editor.isZoomOriginalSize())
{
editor.zoomSetOriginalSize();
canvas.setZoomFactors(editor.getZoomFactorX(), editor.getZoomFactorY());
updateTitle();
menuWrapper.updateEnabled(processor);
}
}
public void setProgress(int zeroBasedIndex, int totalItems)
{
if (totalItems < 1)
{
throw new IllegalArgumentException("Total number of items (second parameter) must be larger than zero.");
}
if (zeroBasedIndex < 0)
{
throw new IllegalArgumentException("Zero-based index must be at least zero.");
}
if (zeroBasedIndex >= totalItems)
{
throw new IllegalArgumentException("Zero-based index must be smaller than total " +
"number of items; zeroBasedIndex=" + zeroBasedIndex + ", totalItems=" +
totalItems);
}
setProgress((float)(zeroBasedIndex + 1) / (float)totalItems);
}
/**
* Set a new progress status.
* @param progress float from 0.0f to 1.0f, indicating the progress between 0 and 100 percent
*/
public void setProgress(float progress)
{
if (progress >= 0.0f && progress <= 1.0f)
{
setStatusBar(" " + Math.round(progress * 100.0f) + "%");
}
}
public void setStatusBar(String text)
{
statusBar.setText(text);
}
public void setWaitCursor()
{
Cursor cursor = new Cursor(Cursor.WAIT_CURSOR);
setCursor(cursor);
}
/**
* Shows a modal dialog with given title bar and message text.
* @param title will be displayed in the dialog's title bar
* @param text will be displayed in the dialog's center part
*/
public void showInfo(String title, String text)
{
InfoDialog d = new InfoDialog(this, title, text);
d.setVisible(true);
}
/**
* If there is an image loaded, forces a canvas redraw by
* calling repaint.
*/
public void updateCanvas()
{
if (canvas != null)
{
canvas.setInterpolation(editor.getInterpolation());
//canvas.revalidate();
canvas.repaint();
}
}
/**
* Removes the current canvas from the frame (if there
* is an image loaded) and creates a new canvas for the
* current image.
*/
public void updateImage()
{
PixelImage image = editor.getImage();
if (scrollPane != null)
{
remove(scrollPane);
}
if (image != null)
{
//editor.zoomSetOriginalSize();
Image awtImage = ImageCreator.convertToAwtImage(image, RGBA.DEFAULT_ALPHA);
scrollPane = new ScrollPane(ScrollPane.SCROLLBARS_AS_NEEDED);
canvas = new ImageCanvas(scrollPane);
canvas.setInterpolation(editor.getInterpolation());
canvas.setZoomToFit(editor.getZoomToFit());
canvas.setImage(awtImage);
canvas.setZoomFactors(editor.getZoomFactorX(), editor.getZoomFactorY());
//canvas.computeZoomToFitSize();
scrollPane.add(canvas);
add(scrollPane);
}
updateStatusBar();
updateTitle();
validate();
menuWrapper.updateEnabled(processor);
}
/**
* Creates a description string for the current image and sets the
* status bar to that text.
*/
public void updateStatusBar()
{
PixelImage image = editor.getImage();
String statusBarText;
if (image == null)
{
statusBarText = "";
}
else
{
statusBarText = ImageDescriptionCreator.getDescription(image, editor.getLocale(), editor.getStrings());
}
setStatusBar(statusBarText);
}
/**
* Sets the frame's title bar to the application name, plus the file name of
* the currently loaded image file, plus the current zoom factor, plus an
* optional asterisk in case the image was modified but not yet saved.
*/
public void updateTitle()
{
StringBuffer sb = new StringBuffer(APP_NAME);
String fileName = editor.getFileName();
if (fileName != null && fileName.length() > 0)
{
sb.append(" [");
sb.append(fileName);
if (editor.getModified())
{
sb.append('*');
}
sb.append(']');
}
if (editor.getImage() != null)
{
double zoom = editor.getZoomFactorX();
int percent = (int)(zoom * 100.0);
sb.append(' ');
sb.append(Integer.toString(percent));
sb.append('%');
}
setTitle(sb.toString());
}
/**
* If an image is currently displayed, zoom in one level.
*/
public void zoomIn()
{
if (canvas != null && !editor.isMaximumZoom())
{
editor.zoomIn();
canvas.setZoomFactors(editor.getZoomFactorX(), editor.getZoomFactorY());
updateTitle();
menuWrapper.updateEnabled(processor);
}
}
/**
* If an image is currently displayed, zoom out one level.
*/
public void zoomOut()
{
if (canvas != null && !editor.isMinimumZoom())
{
editor.zoomOut();
canvas.setZoomFactors(editor.getZoomFactorX(), editor.getZoomFactorY());
updateTitle();
menuWrapper.updateEnabled(processor);
}
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/gui/awt/AwtOperationProcessor.java 0000664 0000000 0000000 00000120631 10572433001 026562 0 ustar /*
* AwtOperationProcessor
*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.gui.awt;
import java.awt.*;
import java.io.*;
import net.sourceforge.jiu.apps.*;
import net.sourceforge.jiu.color.*;
import net.sourceforge.jiu.color.adjustment.*;
import net.sourceforge.jiu.color.analysis.*;
import net.sourceforge.jiu.color.data.*;
import net.sourceforge.jiu.color.dithering.*;
import net.sourceforge.jiu.color.io.*;
import net.sourceforge.jiu.color.promotion.*;
import net.sourceforge.jiu.color.quantization.*;
import net.sourceforge.jiu.color.reduction.*;
import net.sourceforge.jiu.gui.awt.dialogs.*;
import net.sourceforge.jiu.codecs.*;
import net.sourceforge.jiu.data.*;
import net.sourceforge.jiu.filters.*;
import net.sourceforge.jiu.geometry.*;
import net.sourceforge.jiu.ops.*;
import net.sourceforge.jiu.util.*;
/**
* Performs operations specified by parent class {@link OperationProcessor},
* uses various AWT dialogs to get parameters from user in a GUI application.
* @author Marco Schmidt
* @since 0.8.0
*/
public class AwtOperationProcessor extends OperationProcessor
{
private JiuAwtFrame frame;
public AwtOperationProcessor(EditorState editorState, JiuAwtFrame awtFrame)
{
super(editorState);
frame = awtFrame;
}
public void colorAdjustBrightness()
{
EditorState state = getEditorState();
Strings strings = state.getStrings();
Integer value = Dialogs.getInteger(frame,
strings.get(StringIndexConstants.ADJUST_BRIGHTNESS),
strings.get(StringIndexConstants.ENTER_BRIGHTNESS_VALUE),
-100, 0, 100,
strings.get(StringIndexConstants.OK),
strings.get(StringIndexConstants.CANCEL));
if (value == null || value.intValue() == 0)
{
return;
}
Brightness brightness = new Brightness();
brightness.setBrightness(value.intValue());
process(brightness);
}
public void colorAdjustContrast()
{
EditorState state = getEditorState();
Strings strings = state.getStrings();
Integer value = Dialogs.getInteger(frame,
strings.get(StringIndexConstants.ADJUST_CONTRAST),
strings.get(StringIndexConstants.ENTER_CONTRAST_VALUE),
-100, 0, 100,
strings.get(StringIndexConstants.OK),
strings.get(StringIndexConstants.CANCEL));
if (value == null || value.intValue() == 0)
{
return;
}
Contrast contrast = new Contrast();
contrast.setContrast(value.intValue());
process(contrast);
}
public void colorAdjustGamma()
{
EditorState state = getEditorState();
Strings strings = state.getStrings();
GammaCorrectionDialog gcd = new GammaCorrectionDialog(frame, strings, 2.2, GammaCorrection.MAX_GAMMA);
gcd.setVisible(true);
Double result = gcd.getValue();
if (result == null)
{
return;
}
GammaCorrection gc = new GammaCorrection();
gc.setGamma(result.doubleValue());
process(gc);
}
public void colorAdjustHueSaturationValue()
{
EditorState state = getEditorState();
Strings strings = state.getStrings();
HueSaturationValueDialog hsvDialog = new HueSaturationValueDialog(frame, strings, false, 0, 0, 0);
hsvDialog.setVisible(true);
if (!hsvDialog.hasPressedOk())
{
return;
}
boolean setHue = hsvDialog.isHueSet();
int hue = hsvDialog.getHue();
int saturation = hsvDialog.getSaturation();
int value = hsvDialog.getValue();
HueSaturationValue hsv = new HueSaturationValue();
if (setHue)
{
hsv.setHueSaturationValue(hue, saturation, value);
}
else
{
hsv.setSaturationValue(saturation, value);
}
process(hsv);
}
public void colorHistogramCountColorsUsed()
{
EditorState state = getEditorState();
Strings strings = state.getStrings();
PixelImage image = state.getImage();
int numColors = 0;
frame.setWaitCursor();
try
{
if (image instanceof RGBIntegerImage)
{
Histogram3DCreator hc = new Histogram3DCreator();
hc.setImage((RGBIntegerImage)image);
hc.addProgressListeners(state.getProgressListeners());
hc.process();
Histogram3D hist = hc.getHistogram();
numColors = hist.getNumUsedEntries();
}
else
if (image instanceof IntegerImage && image.getNumChannels() == 1)
{
Histogram1DCreator hc = new Histogram1DCreator();
hc.setImage((IntegerImage)image);
hc.addProgressListeners(state.getProgressListeners());
hc.process();
Histogram1D hist = hc.getHistogram();
numColors = hist.getNumUsedEntries();
}
else
{
throw new UnsupportedTypeException("Not a supported image type for counting colors: " +
image.getImageType().getName());
}
}
catch (OperationFailedException ofe)
{
frame.setDefaultCursor();
frame.updateStatusBar();
frame.showError(ofe.toString());
return;
}
frame.setDefaultCursor();
frame.updateStatusBar();
frame.showInfo(
strings.get(StringIndexConstants.COUNT_COLORS_USED),
strings.get(StringIndexConstants.NUMBER_OF_USED_COLORS) + ": " + numColors);
}
public void colorHistogramEqualize()
{
EditorState state = getEditorState();
try
{
process(new EqualizeHistogram((IntegerImage)state.getImage()));
}
catch (OperationFailedException ofe)
{
frame.showError(ofe.toString());
}
}
public void colorHistogramNormalize()
{
EditorState state = getEditorState();
try
{
process(new NormalizeHistogram((IntegerImage)state.getImage()));
}
catch (OperationFailedException ofe)
{
frame.showError(ofe.toString());
}
}
public void colorHistogramTextureProperties()
{
EditorState state = getEditorState();
Strings strings = state.getStrings();
PixelImage img = state.getImage();
if (img == null || (!(img instanceof Gray8Image)))
{
return;
}
Gray8Image image = (Gray8Image)img;
frame.setWaitCursor();
CoOccurrenceMatrix matrix = MatrixCreator.createCoOccurrenceMatrix(image, 0);
TextureAnalysis ta = new TextureAnalysis();
ta.setMatrix(matrix);
ta.addProgressListeners(state.getProgressListeners());
try
{
ta.process();
}
catch (MissingParameterException mpe)
{
}
StringBuffer text = new StringBuffer();
text.append(strings.get(StringIndexConstants.CONTRAST) + "=" + ta.getContrast() + "\n");
text.append(strings.get(StringIndexConstants.CORRELATION) + "=" + ta.getCorrelation() + "\n");
text.append(strings.get(StringIndexConstants.DISSIMILARITY) + "=" + ta.getDissimilarity() + "\n");
text.append(strings.get(StringIndexConstants.ENTROPY) + "=" + ta.getEntropy() + "\n");
text.append(strings.get(StringIndexConstants.ENERGY) + "=" + ta.getEnergy() + "\n");
text.append(strings.get(StringIndexConstants.HOMOGENEITY) + "=" + ta.getHomogeneity());
frame.setDefaultCursor();
frame.updateStatusBar();
frame.showInfo(
strings.get(StringIndexConstants.TEXTURE_PROPERTIES),
text.toString());
}
public void colorHistogramSaveHistogramAs()
{
EditorState state = getEditorState();
PixelImage pi = state.getImage();
if (pi == null || !(pi instanceof IntegerImage))
{
return;
}
String textFileName = getUserSaveAsFileName(".txt", StringIndexConstants.SAVE_HISTOGRAM_AS);
if (textFileName == null)
{
return;
}
PrintStream out = null;
try
{
out = new PrintStream(new BufferedOutputStream(new FileOutputStream(textFileName)), false);
}
catch (IOException ioe)
{
frame.showError(ioe.toString());
return;
}
IntegerImage image = (IntegerImage)pi;
frame.setWaitCursor();
int numChannels = image.getNumChannels();
if (numChannels == 1)
{
Histogram1D hist = null;
try
{
Histogram1DCreator hc = new Histogram1DCreator();
hc.setImage(image);
hc.addProgressListeners(state.getProgressListeners());
hc.process();
hist = hc.getHistogram();
}
catch(OperationFailedException ofe)
{
frame.showError(ofe.toString());
frame.updateStatusBar();
return;
}
HistogramSerialization.save(hist, out);
}
else
if (numChannels == 3)
{
Histogram3D hist = null;
try
{
Histogram3DCreator hc = new Histogram3DCreator();
hc.setImage(image, RGBIndex.INDEX_RED, RGBIndex.INDEX_GREEN, RGBIndex.INDEX_BLUE);
hc.addProgressListeners(state.getProgressListeners());
hc.process();
hist = hc.getHistogram();
}
catch(OperationFailedException ofe)
{
frame.showError(ofe.toString());
frame.updateStatusBar();
return;
}
HistogramSerialization.save(hist, out);
}
out.close();
frame.setDefaultCursor();
frame.updateStatusBar();
}
public void colorHistogramSaveCoOccurrenceMatrixAs()
{
EditorState state = getEditorState();
PixelImage image = state.getImage();
String textFileName = getUserSaveAsFileName(".txt", StringIndexConstants.SAVE_COOCCURRENCE_MATRIX);
if (textFileName == null)
{
return;
}
CoOccurrenceMatrix matrix = MatrixCreator.createCoOccurrenceMatrix((IntegerImage)image, 0);
File textFile = new File(textFileName);
try
{
PrintStream out = new PrintStream(new FileOutputStream(textFile));
MatrixSerialization.save(matrix, out);
out.close();
}
catch(IOException ioe)
{
frame.showError(ioe.toString());
}
}
public void colorHistogramSaveCoOccurrenceFrequencyMatrixAs()
{
EditorState state = getEditorState();
PixelImage image = state.getImage();
String textFileName = getUserSaveAsFileName(".txt", StringIndexConstants.SAVE_COOCCURRENCE_FREQUENCY_MATRIX);
if (textFileName == null)
{
return;
}
CoOccurrenceMatrix com = MatrixCreator.createCoOccurrenceMatrix((IntegerImage)image, 0);
CoOccurrenceFrequencyMatrix matrix = MatrixCreator.createCoOccurrenceFrequencyMatrix(com);
File textFile = new File(textFileName);
try
{
PrintStream out = new PrintStream(new FileOutputStream(textFile));
MatrixSerialization.save(matrix, out);
out.close();
}
catch(IOException ioe)
{
frame.showError(ioe.toString());
}
}
public void colorPaletteSaveAs()
{
EditorState state = getEditorState();
PalettedImage image = (PalettedImage)state.getImage();
Palette palette = image.getPalette();
String paletteFileName = getUserSaveAsFileName(".ppm", StringIndexConstants.SAVE_PALETTE);
if (paletteFileName == null)
{
return;
}
File paletteFile = new File(paletteFileName);
try
{
PaletteSerialization.save(palette, paletteFile);
}
catch(IOException ioe)
{
frame.showError(ioe.toString());
}
}
public void colorPromotePromoteToPaletted()
{
process(new PromotionPaletted8());
}
public void colorPromotePromoteToGray8()
{
process(new PromotionGray8());
}
public void colorPromotePromoteToGray16()
{
process(new PromotionGray16());
}
public void colorPromotePromoteToRgb24()
{
process(new PromotionRGB24());
}
public void colorPromotePromoteToRgb48()
{
process(new PromotionRGB48());
}
public void colorReduceReduceNumberOfShadesOfGray()
{
EditorState state = getEditorState();
Strings strings = state.getStrings();
PixelImage image = state.getImage();
int maxBits = image.getBitsPerPixel() - 1;
ReduceGrayscaleDialog rgd = new ReduceGrayscaleDialog(frame, strings, 1, maxBits,
ReduceGrayscaleDialog.TYPE_FLOYD_STEINBERG_ERROR_DIFFUSION);
rgd.setVisible(true);
if (!rgd.hasPressedOk())
{
return;
}
int numBits = rgd.getNumBits();
ImageToImageOperation op = null;
switch (rgd.getDitheringMethod())
{
case(ReduceGrayscaleDialog.TYPE_DITHERING_NONE):
{
ReduceShadesOfGray rsog;
rsog = new ReduceShadesOfGray();
rsog.setBits(numBits);
op = rsog;
break;
}
case(ReduceGrayscaleDialog.TYPE_ORDERED_DITHERING):
{
OrderedDither od = new OrderedDither();
od.setOutputBits(numBits);
op = od;
break;
}
case(ReduceGrayscaleDialog.TYPE_FLOYD_STEINBERG_ERROR_DIFFUSION):
{
ErrorDiffusionDithering ed = new ErrorDiffusionDithering();
ed.setTemplateType(ErrorDiffusionDithering.TYPE_FLOYD_STEINBERG);
ed.setGrayscaleOutputBits(numBits);
op = ed;
break;
}
case(ReduceGrayscaleDialog.TYPE_STUCKI_ERROR_DIFFUSION):
{
ErrorDiffusionDithering ed = new ErrorDiffusionDithering();
ed.setTemplateType(ErrorDiffusionDithering.TYPE_STUCKI);
ed.setGrayscaleOutputBits(numBits);
op = ed;
break;
}
case(ReduceGrayscaleDialog.TYPE_BURKES_ERROR_DIFFUSION):
{
ErrorDiffusionDithering ed = new ErrorDiffusionDithering();
ed.setTemplateType(ErrorDiffusionDithering.TYPE_BURKES);
ed.setGrayscaleOutputBits(numBits);
op = ed;
break;
}
case(ReduceGrayscaleDialog.TYPE_SIERRA_ERROR_DIFFUSION):
{
ErrorDiffusionDithering ed = new ErrorDiffusionDithering();
ed.setTemplateType(ErrorDiffusionDithering.TYPE_SIERRA);
ed.setGrayscaleOutputBits(numBits);
op = ed;
break;
}
case(ReduceGrayscaleDialog.TYPE_JARVIS_JUDICE_NINKE_ERROR_DIFFUSION):
{
ErrorDiffusionDithering ed = new ErrorDiffusionDithering();
ed.setTemplateType(ErrorDiffusionDithering.TYPE_JARVIS_JUDICE_NINKE);
ed.setGrayscaleOutputBits(numBits);
op = ed;
break;
}
case(ReduceGrayscaleDialog.TYPE_STEVENSON_ARCE_ERROR_DIFFUSION):
{
ErrorDiffusionDithering ed = new ErrorDiffusionDithering();
ed.setTemplateType(ErrorDiffusionDithering.TYPE_STEVENSON_ARCE);
ed.setGrayscaleOutputBits(numBits);
op = ed;
break;
}
default:
{
return;
}
}
op.setInputImage(image);
op.addProgressListeners(state.getProgressListeners());
process(op);
}
public void colorReduceConvertToGrayscale()
{
process(new RGBToGrayConversion());
}
public void colorReduceMedianCut()
{
EditorState state = getEditorState();
Strings strings = state.getStrings();
PixelImage image = state.getImage();
MedianCutDialog mcd = new MedianCutDialog(
frame,
strings,
256,
MedianCutQuantizer.METHOD_REPR_COLOR_WEIGHTED_AVERAGE,
true,
MedianCutContourRemoval.DEFAULT_NUM_PASSES,
MedianCutContourRemoval.DEFAULT_TAU);
mcd.setVisible(true);
if (!mcd.hasPressedOk())
{
return;
}
int numColors = mcd.getNumColors();
int method = mcd.getReprColorMethod();
boolean palettedOutput = mcd.isOutputTypePaletted();
//int numBitsToBeCleared = 0;
ImageToImageOperation op = null;
if (mcd.useContourRemoval())
{
MedianCutQuantizer quantizer = new MedianCutQuantizer();
quantizer.setInputImage(image);
quantizer.setPaletteSize(numColors);
quantizer.setMethodToDetermineRepresentativeColors(method);
MedianCutContourRemoval removal = new MedianCutContourRemoval();
removal.setQuantizer(quantizer);
removal.setTau(mcd.getTau());
removal.setNumPasses(mcd.getNumPasses());
op = removal;
}
else
if (mcd.useErrorDiffusion())
{
MedianCutQuantizer medianCut = new MedianCutQuantizer();
medianCut.setInputImage(image);
medianCut.setPaletteSize(numColors);
medianCut.setMethodToDetermineRepresentativeColors(method);
medianCut.setMapping(false);
try
{
medianCut.process();
}
catch (OperationFailedException ofe)
{
frame.showError(ofe.toString());
return;
}
ErrorDiffusionDithering ed = new ErrorDiffusionDithering();
ed.setTemplateType(mcd.getErrorDiffusion());
ed.setQuantizer(medianCut);
op = ed;
}
else
{
MedianCutQuantizer medianCut = new MedianCutQuantizer();
medianCut.setInputImage(image);
medianCut.setPaletteSize(numColors);
medianCut.setTruecolorOutput(!palettedOutput);
medianCut.setMethodToDetermineRepresentativeColors(method);
op = medianCut;
}
process(op);
}
public void colorInvert()
{
process(new Invert());
}
public void colorConvertToMinimumColorType()
{
EditorState state = getEditorState();
PixelImage image = state.getImage();
AutoDetectColorType adct = new AutoDetectColorType();
adct.setInputImage(image);
adct.addProgressListeners(state.getProgressListeners());
try
{
frame.setWaitCursor();
adct.process();
}
catch (MissingParameterException mpe)
{
frame.setDefaultCursor();
return;
}
catch (WrongParameterException mpe)
{
frame.setDefaultCursor();
return;
}
if (!adct.isReducible())
{
frame.setDefaultCursor();
return;
}
frame.setDefaultCursor();
setImage(adct.getOutputImage(), true);
frame.updateImage();
}
public void colorReduceOctree()
{
EditorState state = getEditorState();
Strings strings = state.getStrings();
PixelImage image = state.getImage();
OctreeDialog od = new OctreeDialog(frame, strings, 256, true);
od.setVisible(true);
if (!(od.hasPressedOk()))
{
return;
}
OctreeColorQuantizer quantizer = new OctreeColorQuantizer();
quantizer.setPaletteSize(od.getNumColors());
quantizer.setInputImage(image);
if (od.useNoDithering())
{
quantizer.addProgressListeners(state.getProgressListeners());
try
{
quantizer.process();
}
catch(WrongParameterException wpe)
{
}
catch(MissingParameterException mpe)
{
}
image = quantizer.getOutputImage();
}
else
if (od.useErrorDiffusion())
{
try
{
quantizer.init();
}
catch(WrongParameterException wpe)
{
}
catch(MissingParameterException mpe)
{
}
ErrorDiffusionDithering ed = new ErrorDiffusionDithering();
ed.setTemplateType(od.getErrorDiffusion());
ed.setQuantizer(quantizer);
process(ed);
return;
}
setImage(image, true);
frame.updateImage();
}
public void colorReduceReduceToBilevelThreshold()
{
EditorState state = getEditorState();
Strings strings = state.getStrings();
IntegerImage image = (IntegerImage)state.getImage();
final int MAX = image.getMaxSample(0);
Integer value = Dialogs.getInteger(frame, strings.get(StringIndexConstants.REDUCE_TO_BILEVEL_THRESHOLD),
strings.get(Strings.ENTER_THRESHOLD_VALUE), 0, MAX / 2, MAX,
strings.get(Strings.OK),
strings.get(Strings.CANCEL));
if (value == null)
{
return;
}
ReduceToBilevelThreshold red = new ReduceToBilevelThreshold();
red.setThreshold(value.intValue());
process(red);
}
private int convertUniformToErrorDiffusion(int utype)
{
switch(utype)
{
case(UniformPaletteQuantizerDialog.TYPE_FLOYD_STEINBERG_ERROR_DIFFUSION): return ErrorDiffusionDithering.TYPE_FLOYD_STEINBERG;
case(UniformPaletteQuantizerDialog.TYPE_BURKES_ERROR_DIFFUSION): return ErrorDiffusionDithering.TYPE_BURKES;
case(UniformPaletteQuantizerDialog.TYPE_STUCKI_ERROR_DIFFUSION): return ErrorDiffusionDithering.TYPE_STUCKI;
case(UniformPaletteQuantizerDialog.TYPE_SIERRA_ERROR_DIFFUSION): return ErrorDiffusionDithering.TYPE_SIERRA;
case(UniformPaletteQuantizerDialog.TYPE_JARVIS_JUDICE_NINKE_ERROR_DIFFUSION): return ErrorDiffusionDithering.TYPE_JARVIS_JUDICE_NINKE;
case(UniformPaletteQuantizerDialog.TYPE_STEVENSON_ARCE_ERROR_DIFFUSION): return ErrorDiffusionDithering.TYPE_STEVENSON_ARCE;
default: return -1;
}
}
public void colorReduceUniformPalette()
{
EditorState state = getEditorState();
Strings strings = state.getStrings();
UniformPaletteQuantizerDialog upqd = new UniformPaletteQuantizerDialog
(frame, strings, 3, 3, 2, UniformPaletteQuantizerDialog.TYPE_FLOYD_STEINBERG_ERROR_DIFFUSION);
upqd.setVisible(true);
if (!upqd.hasPressedOk())
{
return;
}
int redBits = upqd.getRedBits();
int greenBits = upqd.getGreenBits();
int blueBits = upqd.getBlueBits();
int sum = redBits + greenBits + blueBits;
switch (upqd.getDitheringMethod())
{
case(UniformPaletteQuantizerDialog.TYPE_DITHERING_NONE):
{
UniformPaletteQuantizer upq = new UniformPaletteQuantizer(redBits, greenBits, blueBits);
process(upq);
return;
}
case(UniformPaletteQuantizerDialog.TYPE_ORDERED_DITHERING):
{
OrderedDither od = new OrderedDither();
od.setRgbBits(redBits, greenBits, blueBits);
process(od);
return;
}
case(UniformPaletteQuantizerDialog.TYPE_FLOYD_STEINBERG_ERROR_DIFFUSION):
case(UniformPaletteQuantizerDialog.TYPE_BURKES_ERROR_DIFFUSION):
case(UniformPaletteQuantizerDialog.TYPE_STUCKI_ERROR_DIFFUSION):
case(UniformPaletteQuantizerDialog.TYPE_SIERRA_ERROR_DIFFUSION):
case(UniformPaletteQuantizerDialog.TYPE_JARVIS_JUDICE_NINKE_ERROR_DIFFUSION):
case(UniformPaletteQuantizerDialog.TYPE_STEVENSON_ARCE_ERROR_DIFFUSION):
{
ErrorDiffusionDithering ed = new ErrorDiffusionDithering();
ed.setTemplateType(convertUniformToErrorDiffusion(upqd.getDitheringMethod()));
UniformPaletteQuantizer upq = new UniformPaletteQuantizer(redBits, greenBits, blueBits);
ed.setQuantizer(upq);
ed.setTruecolorOutput(sum > 8);
process(ed);
return;
}
default:
{
return;
}
}
}
public void colorReduceMapToArbitraryPalette()
{
EditorState state = getEditorState();
Strings strings = state.getStrings();
PixelImage image = state.getImage();
MapToArbitraryPaletteDialog d = new MapToArbitraryPaletteDialog(frame, strings);
d.setVisible(true);
if (!d.hasPressedOk())
{
return;
}
int paletteType = d.getPaletteType();
if (paletteType < 0)
{
return;
}
// load palette from file
Palette palette;
switch(paletteType)
{
case(MapToArbitraryPaletteDialog.PALETTE_FILE):
{
String name = getUserFileName(null, StringIndexConstants.LOAD_PALETTE, FileDialog.LOAD);
if (name == null)
{
return;
}
File file = new File(name);
palette = PaletteSerialization.load(file);
break;
}
case(MapToArbitraryPaletteDialog.PALETTE_WEBSAFE):
{
palette = WebsafePaletteCreator.create();
break;
}
case(MapToArbitraryPaletteDialog.PALETTE_PALM_256_COLORS):
{
palette = PalmCodec.createSystem8BitPalette();
break;
}
case(MapToArbitraryPaletteDialog.PALETTE_PALM_16_COLORS):
{
palette = PalmCodec.createSystem4BitColorPalette();
break;
}
case(MapToArbitraryPaletteDialog.PALETTE_PALM_16_GRAY):
{
palette = PalmCodec.createSystem4BitGrayscalePalette();
break;
}
case(MapToArbitraryPaletteDialog.PALETTE_PALM_4_GRAY):
{
palette = PalmCodec.createSystem2BitGrayscalePalette();
break;
}
default:
{
return;
}
}
ArbitraryPaletteQuantizer apq = new ArbitraryPaletteQuantizer(palette);
if (palette == null)
{
return;
}
if (d.useErrorDiffusion())
{
// error diffusion dithering
ErrorDiffusionDithering ed = new ErrorDiffusionDithering();
ed.setTemplateType(d.getErrorDiffusionType());
ed.setQuantizer(apq);
process(ed);
return;
}
else
{
// no dithering
apq.setInputImage(image);
apq.addProgressListeners(state.getProgressListeners());
try
{
apq.process();
}
catch (OperationFailedException ofe)
{
return;
}
image = apq.getOutputImage();
}
setImage(image, true);
frame.updateImage();
}
public void editRedo()
{
EditorState state = getEditorState();
if (!state.canRedo())
{
return;
}
state.redo();
frame.updateImage();
}
public void editUndo()
{
EditorState state = getEditorState();
if (!state.canUndo())
{
return;
}
state.undo();
frame.updateImage();
}
public void fileClose()
{
EditorState state = getEditorState();
if (state.getModified())
{
YesNoDialog dialog = new YesNoDialog(frame, state.getStrings(),
StringIndexConstants.CLOSE_FILE,
StringIndexConstants.DO_YOU_REALLY_WANT_TO_CLOSE_WITHOUT_SAVING,
false);
dialog.setVisible(true);
if (dialog.getResult() == YesNoDialog.RESULT_NO)
{
return;
}
}
setImage(null, false);
state.resetZoomFactors();
state.setFileName("");
state.clearRedo();
state.clearUndo();
frame.updateImage();
}
public void fileExit()
{
EditorState state = getEditorState();
if (state.getModified())
{
YesNoDialog dialog = new YesNoDialog(frame, state.getStrings(),
StringIndexConstants.QUIT_PROGRAM,
StringIndexConstants.DO_YOU_REALLY_WANT_TO_QUIT_WITHOUT_SAVING,
false);
dialog.setVisible(true);
if (dialog.getResult() == YesNoDialog.RESULT_NO)
{
return;
}
}
frame.setVisible(false);
System.exit(0);
}
public void fileOpen(String uri)
{
EditorState state = getEditorState();
Strings strings = state.getStrings();
if (state.getModified())
{
YesNoDialog dialog = new YesNoDialog(frame, state.getStrings(),
StringIndexConstants.CLOSE_FILE,
StringIndexConstants.DO_YOU_REALLY_WANT_TO_CLOSE_WITHOUT_SAVING,
false);
dialog.setVisible(true);
if (dialog.getResult() == YesNoDialog.RESULT_NO)
{
return;
}
}
File file = null;
if (uri != null)
{
}
else
if (state.getStartupImageName() != null)
{
file = new File(state.getStartupImageName());
state.setStartupImageName(null);
}
else
{
FileDialog fd = new FileDialog(frame, strings.get(StringIndexConstants.LOAD_IMAGE_FILE), FileDialog.LOAD);
String dir = state.getCurrentDirectory();
if (dir != null)
{
fd.setDirectory(dir);
}
//fd.setFilenameFilter(ImageLoader.createFilenameFilter());
fd.setVisible(true);
fd.setMode(FileDialog.LOAD);
String fn = fd.getFile();
String dn = fd.getDirectory();
if (fn == null || dn == null)
{
return;
}
state.setCurrentDirectory(dn);
file = new File(dn, fn);
}
PixelImage image = null;
String fullName = uri;
try
{
if (uri != null)
{
image = ImageLoader.loadToolkitImageUri(uri);
}
else
{
image = ImageLoader.load(file, state.getProgressListeners());
}
}
catch (Exception e)
{
frame.showInfo("Error loading image", e.toString());
e.printStackTrace();
return;
}
if (file != null)
{
fullName = file.getAbsolutePath();
if (image == null)
{
image = ToolkitLoader.loadAsRgb24Image(fullName);
}
}
if (image == null)
{
frame.showInfo(strings.get(StringIndexConstants.ERROR_LOADING_IMAGE),
strings.get(StringIndexConstants.FILE_FORMAT_UNKNOWN));
return;
}
setImage(image, false);
state.setFileName(fullName);
frame.updateImage();
}
public void fileSaveAsBmp()
{
EditorState editor = getEditorState();
PixelImage image = editor.getImage();
if (image == null)
{
return;
}
BMPCodec codec = new BMPCodec();
String name = getUserSaveAsFileName(codec.suggestFileExtension(image), StringIndexConstants.SAVE_IMAGE_AS);
if (name == null)
{
return;
}
codec.addProgressListeners(editor.getProgressListeners());
try
{
codec.setOutputStream(new BufferedOutputStream(new FileOutputStream(name)));
codec.setImage(image);
codec.process();
}
catch (Exception e)
{
frame.showError(e.toString());
return;
}
editor.setFileName(name);
setImage(image, false);
frame.updateImage();
}
public void fileSaveAsGif()
{
EditorState editor = getEditorState();
PixelImage image = editor.getImage();
if (image == null)
{
return;
}
GIFCodec codec = new GIFCodec();
String name = getUserSaveAsFileName(codec.suggestFileExtension(image),
StringIndexConstants.SAVE_IMAGE_AS);
if (name == null)
{
return;
}
codec.addProgressListeners(editor.getProgressListeners());
try
{
codec.setFile(name, CodecMode.SAVE);
codec.setImage(image);
codec.process();
}
catch (Exception e)
{
frame.showError(e.toString());
return;
}
editor.setFileName(name);
setImage(image, false);
frame.updateImage();
}
public void fileSaveAsPalm()
{
EditorState editor = getEditorState();
PixelImage image = editor.getImage();
if (image == null)
{
return;
}
PalmCodec codec = new PalmCodec();
String name = getUserSaveAsFileName(codec.suggestFileExtension(image), StringIndexConstants.SAVE_IMAGE_AS);
if (name == null)
{
return;
}
codec.setCompression(PalmCodec.COMPRESSION_SCANLINE);
codec.addProgressListeners(editor.getProgressListeners());
try
{
codec.setFile(name, CodecMode.SAVE);
codec.setImage(image);
codec.process();
}
catch (Exception e)
{
frame.showError(e.toString());
return;
}
editor.setFileName(name);
setImage(image, false);
frame.updateImage();
}
public void fileSaveAsPbm()
{
fileSaveAsPnm();
}
public void fileSaveAsPgm()
{
fileSaveAsPnm();
}
public void fileSaveAsPng()
{
EditorState editor = getEditorState();
PixelImage image = editor.getImage();
if (image == null)
{
return;
}
PNGCodec codec = new PNGCodec();
String name = getUserSaveAsFileName(codec.suggestFileExtension(image), StringIndexConstants.SAVE_IMAGE_AS);
if (name == null)
{
return;
}
codec.addProgressListeners(editor.getProgressListeners());
try
{
codec.setFile(name, CodecMode.SAVE);
codec.setImage(image);
codec.process();
}
catch (Exception e)
{
frame.showError(e.toString());
return;
}
editor.setFileName(name);
setImage(image, false);
frame.updateImage();
}
private void fileSaveAsPnm()
{
EditorState editor = getEditorState();
PixelImage image = editor.getImage();
if (image == null)
{
return;
}
PNMCodec codec = new PNMCodec();
String name = getUserSaveAsFileName(codec.suggestFileExtension(image), StringIndexConstants.SAVE_IMAGE_AS);
if (name == null)
{
return;
}
codec.addProgressListeners(editor.getProgressListeners());
try
{
codec.setOutputStream(new BufferedOutputStream(new FileOutputStream(name)));
codec.setImage(image);
codec.process();
}
catch (Exception e)
{
frame.showError(e.toString());
return;
}
editor.setFileName(name);
setImage(image, false);
frame.updateImage();
}
public void fileSaveAsPpm()
{
fileSaveAsPnm();
}
public void fileSaveAsRas()
{
EditorState editor = getEditorState();
PixelImage image = editor.getImage();
if (image == null)
{
return;
}
RASCodec codec = new RASCodec();
String name = getUserSaveAsFileName(codec.suggestFileExtension(image), StringIndexConstants.SAVE_IMAGE_AS);
if (name == null)
{
return;
}
codec.addProgressListeners(editor.getProgressListeners());
try
{
codec.setOutputStream(new BufferedOutputStream(new FileOutputStream(name)));
codec.setImage(image);
codec.process();
}
catch (Exception e)
{
frame.showError(e.toString());
return;
}
editor.setFileName(name);
setImage(image, false);
frame.updateImage();
}
public void filterConvolutionFilter(int type)
{
ConvolutionKernelFilter ckf = new ConvolutionKernelFilter();
ckf.setKernel(type);
process(ckf);
}
public void filtersBlur()
{
filterConvolutionFilter(ConvolutionKernelFilter.TYPE_BLUR);
}
public void filtersSharpen()
{
filterConvolutionFilter(ConvolutionKernelFilter.TYPE_SHARPEN);
}
public void filtersEdgeDetection()
{
filterConvolutionFilter(ConvolutionKernelFilter.TYPE_EDGE_DETECTION);
}
public void filtersEmboss()
{
filterConvolutionFilter(ConvolutionKernelFilter.TYPE_EMBOSS);
}
public void filtersPsychedelicDistillation()
{
filterConvolutionFilter(ConvolutionKernelFilter.TYPE_PSYCHEDELIC_DISTILLATION);
}
public void filtersLithograph()
{
filterConvolutionFilter(ConvolutionKernelFilter.TYPE_LITHOGRAPH);
}
public void filtersHorizontalSobel()
{
filterConvolutionFilter(ConvolutionKernelFilter.TYPE_HORIZONTAL_SOBEL);
}
public void filtersVerticalSobel()
{
filterConvolutionFilter(ConvolutionKernelFilter.TYPE_VERTICAL_SOBEL);
}
public void filtersHorizontalPrewitt()
{
filterConvolutionFilter(ConvolutionKernelFilter.TYPE_HORIZONTAL_PREWITT);
}
public void filtersVerticalPrewitt()
{
filterConvolutionFilter(ConvolutionKernelFilter.TYPE_VERTICAL_PREWITT);
}
public void filtersMaximum()
{
EditorState state = getEditorState();
Strings strings = state.getStrings();
WindowSizeDialog wsd = new WindowSizeDialog(frame, strings, StringIndexConstants.APPLY_MAXIMUM_FILTER, 3, 3);
wsd.setVisible(true);
if (!wsd.hasPressedOk())
{
return;
}
MaximumFilter mf = new MaximumFilter();
mf.setArea(wsd.getWidthValue(), wsd.getHeightValue());
process(mf);
}
public void filtersMedian()
{
EditorState state = getEditorState();
Strings strings = state.getStrings();
WindowSizeDialog wsd = new WindowSizeDialog(frame, strings, StringIndexConstants.APPLY_MEDIAN_FILTER, 3, 3);
wsd.setVisible(true);
if (!wsd.hasPressedOk())
{
return;
}
MedianFilter mf = new MedianFilter();
mf.setArea(wsd.getWidthValue(), wsd.getHeightValue());
process(mf);
}
public void filtersMean()
{
EditorState state = getEditorState();
Strings strings = state.getStrings();
WindowSizeDialog wsd = new WindowSizeDialog(frame, strings, StringIndexConstants.APPLY_MEAN_FILTER, 3, 3);
wsd.setVisible(true);
if (!wsd.hasPressedOk())
{
return;
}
MeanFilter mf = new MeanFilter();
mf.setArea(wsd.getWidthValue(), wsd.getHeightValue());
process(mf);
}
public void filtersMinimum()
{
EditorState state = getEditorState();
Strings strings = state.getStrings();
WindowSizeDialog wsd = new WindowSizeDialog(frame, strings, StringIndexConstants.APPLY_MINIMUM_FILTER, 3, 3);
wsd.setVisible(true);
if (!wsd.hasPressedOk())
{
return;
}
MinimumFilter mf = new MinimumFilter();
mf.setArea(wsd.getWidthValue(), wsd.getHeightValue());
process(mf);
}
public void filtersOil()
{
EditorState state = getEditorState();
Strings strings = state.getStrings();
WindowSizeDialog wsd = new WindowSizeDialog(frame, strings, StringIndexConstants.APPLY_OIL_FILTER, 3, 3);
wsd.setVisible(true);
if (!wsd.hasPressedOk())
{
return;
}
OilFilter of = new OilFilter();
of.setArea(wsd.getWidthValue(), wsd.getHeightValue());
process(of);
}
public String getUserFileName(String extension, int titleIndex, int fileDialogType)
{
EditorState editor = getEditorState();
Strings strings = editor.getStrings();
FileDialog fd = new FileDialog(frame, strings.get(titleIndex), fileDialogType);
String currentDirectory = editor.getCurrentDirectory();
if (currentDirectory != null)
{
fd.setDirectory(currentDirectory);
}
String fileName = editor.getFileName();
if (fileDialogType == FileDialog.SAVE &&
fileName != null &&
extension != null)
{
File existingFile = new File(fileName);
String name = existingFile.getName();
if (name != null)
{
int dotIndex = name.lastIndexOf(".");
if (dotIndex != -1)
{
name = name.substring(0, dotIndex);
name += extension;
}
}
fd.setFile(name);
}
fd.setVisible(true);
String fn = fd.getFile();
String dn = fd.getDirectory();
if (fn == null || dn == null)
{
return null;
}
File file = new File(dn, fn);
return file.getAbsolutePath();
}
public String getUserSaveAsFileName(String extension, int titleIndex)
{
return getUserFileName(extension, titleIndex, FileDialog.SAVE);
}
public void helpAbout()
{
EditorState state = getEditorState();
Strings strings = state.getStrings();
String message =
JiuAwtFrame.APP_NAME + "\n" +
strings.get(StringIndexConstants.HOMEPAGE) + "=" + JiuInfo.JIU_HOMEPAGE + "\n" +
strings.get(StringIndexConstants.FEEDBACK) + "=" + JiuInfo.JIU_FEEDBACK_ADDRESS;
frame.showInfo(strings.get(StringIndexConstants.ABOUT), message);
}
public void helpSystemInformation()
{
EditorState state = getEditorState();
Strings strings = state.getStrings();
frame.showInfo(strings.get(StringIndexConstants.SYSTEM_INFORMATION),
SystemInfo.getSystemInfo(strings) + "\n" +
AwtInfo.getAwtInfo(strings) + "\n" +
SystemInfo.getMemoryInfo(strings));
}
/**
* This method can be called for ImageToImageOperation objects.
*/
public void process(ImageToImageOperation op)
{
EditorState state = getEditorState();
PixelImage image = state.getImage();
if (image == null)
{
return;
}
frame.setWaitCursor();
op.setInputImage(image);
op.addProgressListeners(state.getProgressListeners());
try
{
op.process();
frame.setDefaultCursor();
}
catch (OperationFailedException ofe)
{
frame.setDefaultCursor();
frame.showError(ofe.toString());
return;
}
setImage(op.getOutputImage(), true);
frame.updateImage();
}
public void setImage(PixelImage newImage, boolean newModified)
{
EditorState state = getEditorState();
state.setImage(newImage, newModified);
}
public void transformationsFlip()
{
process(new Flip());
}
public void transformationsMirror()
{
process(new Mirror());
}
public void transformationsRotate90Left()
{
process(new Rotate90Left());
}
public void transformationsRotate90Right()
{
process(new Rotate90Right());
}
public void transformationsRotate180()
{
Rotate180 rot = new Rotate180();
EditorState state = getEditorState();
rot.setInputImage(state.getImage());
process(rot);
}
public void transformationsCrop()
{
EditorState state = getEditorState();
Strings strings = state.getStrings();
PixelImage image = state.getImage();
CropDialog cd = new CropDialog(frame, strings, image.getWidth(), image.getHeight());
cd.setVisible(true);
if (!cd.hasPressedOk())
{
return;
}
int x1 = cd.getX1();
int x2 = cd.getX2();
int y1 = cd.getY1();
int y2 = cd.getY2();
Crop crop = new Crop();
crop.setBounds(x1, y1, x2, y2);
process(crop);
}
public void transformationsShear()
{
EditorState state = getEditorState();
PixelImage image = state.getImage();
Strings strings = state.getStrings();
ShearDialog sd = new ShearDialog(frame, strings, 45.0, image.getWidth(), image.getHeight());
sd.setVisible(true);
if (!sd.hasPressedOk())
{
return;
}
Double angle = sd.getValue();
if (angle == null || angle.doubleValue() == 0.0)
{
return;
}
Shear shear = new Shear();
shear.setAngle(angle.doubleValue());
process(shear);
}
public void transformationsScale()
{
EditorState state = getEditorState();
PixelImage image = state.getImage();
Strings strings = state.getStrings();
// a type can be chosen by the user if rgb or gray image
boolean pickType = image instanceof RGB24Image || image instanceof Gray8Image;
int initialType;
if (pickType)
{
initialType = Resample.FILTER_TYPE_B_SPLINE;
}
else
{
initialType = Resample.FILTER_TYPE_BOX;
}
ScaleDialog sd = new ScaleDialog(frame, strings, image.getWidth(),
image.getHeight(), pickType, Resample.getFilterNames(), initialType);
sd.setVisible(true);
if (sd.hasPressedOk())
{
int newWidth = sd.getWidthValue();
int newHeight = sd.getHeightValue();
if (newWidth < 1 || newHeight < 1 ||
(newWidth == image.getWidth() && newHeight == image.getHeight()))
{
return;
}
if (pickType)
{
Resample resample = new Resample();
resample.setFilter(sd.getType());
ResampleFilter filter = resample.getFilter();
filter.setSamplingRadius(filter.getRecommendedSamplingRadius() * 50);
resample.setSize(newWidth, newHeight);
process(resample);
}
else
{
ScaleReplication sc = new ScaleReplication();
sc.setSize(newWidth, newHeight);
process(sc);
}
}
}
public void updateFrame(PixelImage image)
{
EditorState state = getEditorState();
state.setImage(image, true);
frame.setDefaultCursor();
frame.updateImage();
}
public void viewInterpolationTypeBicubic()
{
EditorState state = getEditorState();
state.setInterpolation(EditorState.INTERPOLATION_BICUBIC);
frame.updateCanvas();
}
public void viewInterpolationTypeBilinear()
{
EditorState state = getEditorState();
state.setInterpolation(EditorState.INTERPOLATION_BILINEAR);
frame.updateCanvas();
}
public void viewInterpolationTypeNearestNeighbor()
{
EditorState state = getEditorState();
state.setInterpolation(EditorState.INTERPOLATION_NEAREST_NEIGHBOR);
frame.updateCanvas();
}
public void viewZoomIn()
{
frame.zoomIn();
}
public void viewZoomOut()
{
frame.zoomOut();
}
public void viewSetOriginalSize()
{
frame.setOriginalSize();
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/gui/awt/RGBA.java 0000664 0000000 0000000 00000017125 07741250134 022774 0 ustar /*
* RGBA
*
* Copyright (c) 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.gui.awt;
/**
* This class converts between the 32 bit RGBA int values (used throughout the AWT) and
* various standard pixel formats like 24 bits RGB, 8 bits gray, 16 bits gray, 1 bit black and white.
* * The conversion is done in a number of static methods. * This class is not supposed to be instantiated. *
* The method names of this class can be interpreted as follows.
* If they contain
* fromXYZ
(where XYZ is a pixel format type like Gray8, RGB24 etc.),
* a conversion from another pixel format to RGBA is done.
* If the names contains toXYZ
, a conversion from RGBA to that pixel
* format will be performed.
*
* Not all conversions are lossless or well-defined.
* If 48 bpp RGB truecolor is used as source, only the top eight bits of each
* 16 bit sample will be used (thus, the procedure is lossy).
* If RGBA data is to be converted to bilevel (black and white), the conversion
* is undefined if there are input RGBA pixels that are neither black nor white.
*
* @author Marco Schmidt
*/
public class RGBA
{
/**
* The default value for the alpha part of RGBA.
* The alpha value is eight bits long left-shifted by 24.
* This default value is no transparency - the underlying image
* cannot be seen: 0xff000000
.
*/
public static final int DEFAULT_ALPHA = 0xff000000;
private RGBA()
{
}
/**
* Converts pixels from bilevel packed bytes to RGBA format.
* A byte is supposed to store eight pixels, the most significant bit being the leftmost pixel.
* @param src the array with the packed bytes
* @param srcOffset the index of the first byte to be converted from src
* @param alpha the alpha value to be used for the destination RGBA values
* @param dest the array where the destination RGBA pixels will be stored
* @param destOffset the index of the first destination pixel in the dest array;
* that array must be at least destOffset + ((num + 7) / 8) large
* @param num the number of pixels (not bytes) to be converted
*/
public static void convertFromPackedBilevel(byte[] src, int srcOffset, int alpha,
int[] dest, int destOffset, int num)
{
final int BLACK = alpha;
final int WHITE = alpha | 0x00ffffff;
int mask = 1;
int value = 0; // 0 will never be used; value will be assigned a value in the first pass of the loop
while (num-- > 0)
{
if (mask == 1)
{
mask = 128;
value = src[srcOffset++] & 0xff;
}
else
{
mask >>= 1;
}
if ((value & mask) == 0)
{
dest[destOffset++] = BLACK;
}
else
{
dest[destOffset++] = WHITE;
}
}
}
/**
* Convert a number of 8 bit grayscale pixels, shades of gray between 0 (for black)
* and 255 (for white), given as bytes, to RGBA type int pixels, adding the given
* alpha value.
* @param src array with grayscale pixels
* @param srcOffset index of first entry of src to be converted
* @param alpha transparency value to be used in resulting RGBA array (only top eight bits can be set)
* @param dest array to store resulting RGBA pixels
* @param destOffset index of first entry in dest to be used
* @param num number of pixels to be converted
*/
public static void convertFromGray8(byte[] src, int srcOffset, int alpha,
int[] dest, int destOffset, int num)
{
while (num-- > 0)
{
int grayValue = src[srcOffset++] & 0xff;
dest[destOffset++] = alpha | grayValue | (grayValue << 8) | (grayValue << 16);
}
}
/**
* Convert a number of 16 bit grayscale pixels to RGBA type int pixels, adding the given
* alpha value.
* Note that the lower 8 bits of each grayscale value are dropped.
* @param src array with grayscale pixels
* @param srcOffset index of first entry of src to be converted
* @param alpha transparency value to be used in resulting RGBA array (only top eight bits can be set)
* @param dest array to store resulting RGBA pixels
* @param destOffset index of first entry in dest to be used
* @param num number of pixels to be converted
*/
public static void convertFromGray16(short[] src, int srcOffset, int alpha,
int[] dest, int destOffset, int num)
{
while (num-- > 0)
{
int grayValue = (src[srcOffset++] & 0xffff) >> 8;
dest[destOffset++] = alpha | grayValue | (grayValue << 8) | (grayValue << 16);
}
}
/**
* Converts a byte array of palette index values to an array of RGBA values,
* using palette color data.
* @param src the byte array with the palette index values
* @param srcOffset index of the first entry of src to be used
* @param alpha transparency value to be used (only top eight bits should be set)
* @param red the red palette values
* @param green the green palette values
* @param blue the blue palette values
* @param dest the destination array to store the RGBA values
* @param destOffset the first entry of dest to be used
* @param num the number of pixels to be converted
*/
public static void convertFromPaletted8(byte[] src, int srcOffset, int alpha,
int[] red, int[] green, int[] blue, int[] dest, int destOffset, int num)
{
while (num-- > 0)
{
int index = src[srcOffset++] & 0xff;
dest[destOffset++] = alpha | (blue[index]) | (green[index] << 8) | (red[index] << 16);
}
}
/**
* Converts 24 bit RGB truecolor data to RGBA int values.
* @param srcRed the red pixel values
* @param srcRedOffset the first entry of srcRed to be used
* @param srcGreen the green pixel values
* @param srcGreenOffset the first entry of srcGreen to be used
* @param srcBlue the blue pixel values
* @param srcBlueOffset the first entry of srcBlue to be used
* @param alpha the transpancy value to be used in the destination RGBA array (only top 8 bits should be set)
* @param dest array to store RGBA pixel values
* @param destOffset first entry of dest to be used
* @param num number of pixels to be converted
*/
public static void convertFromRGB24(byte[] srcRed, int srcRedOffset, byte[] srcGreen,
int srcGreenOffset, byte[] srcBlue, int srcBlueOffset, int alpha,
int[] dest, int destOffset, int num)
{
while (num-- > 0)
{
dest[destOffset++] =
alpha |
(srcBlue[srcBlueOffset++] & 0xff) |
((srcGreen[srcGreenOffset++] & 0xff) << 8) |
((srcRed[srcRedOffset++] & 0xff) << 16);
}
}
/**
* Converts 48 bit RGB truecolor data to RGBA int values, dropping the least
* significant eight bits of each short sample.
* @param srcRed the red pixel values
* @param srcRedOffset the first entry of srcRed to be used
* @param srcGreen the green pixel values
* @param srcGreenOffset the first entry of srcGreen to be used
* @param srcBlue the blue pixel values
* @param srcBlueOffset the first entry of srcBlue to be used
* @param alpha the transpancy value to be used in the destination RGBA array (only top 8 bits should be set)
* @param dest array to store RGBA pixel values
* @param destOffset first entry of dest to be used
* @param num number of pixels to be converted
* @since 0.12.0
*/
public static void convertFromRGB48(short[] srcRed, int srcRedOffset, short[] srcGreen,
int srcGreenOffset, short[] srcBlue, int srcBlueOffset, int alpha,
int[] dest, int destOffset, int num)
{
while (num-- > 0)
{
dest[destOffset++] =
alpha |
((srcBlue[srcBlueOffset++] & 0xff00) >> 8) |
((srcGreen[srcGreenOffset++] & 0xff00)) |
((srcRed[srcRedOffset++] & 0xff00) << 8);
}
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/gui/awt/AwtMenuWrapper.java 0000664 0000000 0000000 00000031560 10404065410 025170 0 ustar /*
* AwtMenuWrapper
*
* Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.gui.awt;
import java.awt.Menu;
import java.awt.MenuBar;
import java.awt.MenuItem;
import java.awt.MenuShortcut;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import net.sourceforge.jiu.apps.MenuIndexConstants;
import net.sourceforge.jiu.apps.MenuWrapper;
import net.sourceforge.jiu.apps.OperationProcessor;
import net.sourceforge.jiu.apps.StringIndexConstants;
import net.sourceforge.jiu.apps.Strings;
/**
* A wrapper around an AWT MenuBar object.
* @author Marco Schmidt
* @since 0.8.0
*/
public class AwtMenuWrapper extends MenuWrapper
{
private ActionListener listener;
private MenuItem[] items;
private MenuBar menuBar;
/**
* Internally creates a MenuBar object and provides methods to update that
* menu bar.
* @param strings String resource used to initialize menu items
* @param actionListener a listener which will be registered with all menu items
*/
public AwtMenuWrapper(Strings strings, ActionListener actionListener)
{
items = new MenuItem[MenuIndexConstants.NUM_CONSTANTS];
listener = actionListener;
init(strings);
}
private Menu createMenu(Strings strings, int stringIndex)
{
String labelText = strings.get(stringIndex);
Menu result = new Menu(labelText);
return result;
}
private MenuShortcut createMenuShortcut(int menuIndex)
{
switch(menuIndex)
{
case(MenuIndexConstants.FILE_OPEN): return new MenuShortcut(KeyEvent.VK_O);
case(MenuIndexConstants.FILE_EXIT): return new MenuShortcut(KeyEvent.VK_Q);
case(MenuIndexConstants.EDIT_UNDO): return new MenuShortcut(KeyEvent.VK_Z);
case(MenuIndexConstants.EDIT_REDO): return new MenuShortcut(KeyEvent.VK_Y);
case(MenuIndexConstants.VIEW_ZOOMIN): return new MenuShortcut(KeyEvent.VK_ADD);
case(MenuIndexConstants.VIEW_ZOOMOUT): return new MenuShortcut(KeyEvent.VK_SUBTRACT);
case(MenuIndexConstants.VIEW_SETORIGINALSIZE): return new MenuShortcut(KeyEvent.VK_SEPARATER);
default: return null;
}
}
/**
* Attempts to find one of the menu items in the internal list.
* Returns its index or -1 if it is not one of the items.
*/
public int findIndex(Object o)
{
if (o != null && items != null)
{
for (int i = 0; i < items.length; i++)
{
if (o == items[i])
{
return i;
}
}
}
return -1;
}
/**
* Returns the encapsulated MenuBar object.
*/
public MenuBar getMenuBar()
{
return menuBar;
}
/**
* Initializes an object of type MenuBar.
*/
private void init(Strings strings)
{
// by default, create all items as MenuItem objects
for (int i = 0; i < items.length; i++)
{
int stringIndex = getStringIndex(i);
if (stringIndex == -1)
{
continue;
}
String labelText = strings.get(stringIndex);
items[i] = new MenuItem(labelText);
}
menuBar = new MenuBar();
// FILE - SAVE AS
Menu fileSaveAsMenu = createMenu(strings, StringIndexConstants.SAVEAS);
items[MenuIndexConstants.FILE_SAVEAS] = fileSaveAsMenu;
fileSaveAsMenu.add(items[MenuIndexConstants.FILE_SAVEAS_GIF]);
fileSaveAsMenu.add(items[MenuIndexConstants.FILE_SAVEAS_PALM]);
fileSaveAsMenu.add(items[MenuIndexConstants.FILE_SAVEAS_PBM]);
fileSaveAsMenu.add(items[MenuIndexConstants.FILE_SAVEAS_PGM]);
fileSaveAsMenu.add(items[MenuIndexConstants.FILE_SAVEAS_PNG]);
fileSaveAsMenu.add(items[MenuIndexConstants.FILE_SAVEAS_PPM]);
fileSaveAsMenu.add(items[MenuIndexConstants.FILE_SAVEAS_SUNRASTER]);
fileSaveAsMenu.add(items[MenuIndexConstants.FILE_SAVEAS_WINDOWSBMP]);
// FILE
Menu fileMenu = createMenu(strings, StringIndexConstants.FILE);
items[MenuIndexConstants.FILE] = fileMenu;
fileMenu.add(items[MenuIndexConstants.FILE_OPEN]);
fileMenu.add(fileSaveAsMenu);
fileMenu.add(items[MenuIndexConstants.FILE_CLOSE]);
fileMenu.addSeparator();
fileMenu.add(items[MenuIndexConstants.FILE_IMAGE_1]);
fileMenu.addSeparator();
fileMenu.add(items[MenuIndexConstants.FILE_EXIT]);
menuBar.add(fileMenu);
// EDIT
Menu editMenu = createMenu(strings, StringIndexConstants.EDIT);
items[MenuIndexConstants.EDIT] = editMenu;
editMenu.add(items[MenuIndexConstants.EDIT_UNDO]);
editMenu.add(items[MenuIndexConstants.EDIT_REDO]);
menuBar.add(editMenu);
// COLOR - ADJUST
Menu colorAdjustMenu = createMenu(strings, StringIndexConstants.ADJUST);
items[MenuIndexConstants.COLOR_ADJUST] = colorAdjustMenu;
colorAdjustMenu.add(items[MenuIndexConstants.COLOR_ADJUST_BRIGHTNESS]);
colorAdjustMenu.add(items[MenuIndexConstants.COLOR_ADJUST_CONTRAST]);
colorAdjustMenu.add(items[MenuIndexConstants.COLOR_ADJUST_GAMMA]);
colorAdjustMenu.add(items[MenuIndexConstants.COLOR_ADJUST_HUESATURATIONVALUE]);
// COLOR - HISTOGRAM
Menu colorHistogramMenu = createMenu(strings, StringIndexConstants.HISTOGRAM);
items[MenuIndexConstants.COLOR_HISTOGRAM] = colorHistogramMenu;
colorHistogramMenu.add(items[MenuIndexConstants.COLOR_HISTOGRAM_COUNTCOLORSUSED]);
colorHistogramMenu.add(items[MenuIndexConstants.COLOR_HISTOGRAM_EQUALIZE]);
colorHistogramMenu.add(items[MenuIndexConstants.COLOR_HISTOGRAM_NORMALIZE]);
colorHistogramMenu.add(items[MenuIndexConstants.COLOR_HISTOGRAM_TEXTUREPROPERTIES]);
colorHistogramMenu.add(items[MenuIndexConstants.COLOR_HISTOGRAM_SAVEHISTOGRAMAS]);
colorHistogramMenu.add(items[MenuIndexConstants.COLOR_HISTOGRAM_SAVECOOCCURRENCEMATRIXAS]);
colorHistogramMenu.add(items[MenuIndexConstants.COLOR_HISTOGRAM_SAVECOOCCURRENCEFREQUENCYMATRIXAS]);
// COLOR - PALETTE
Menu colorPaletteMenu = createMenu(strings, StringIndexConstants.PALETTE_MENU_ITEM);
items[MenuIndexConstants.COLOR_PALETTE] = colorPaletteMenu;
colorPaletteMenu.add(items[MenuIndexConstants.COLOR_PALETTE_SAVEAS]);
// COLOR - PROMOTE
Menu colorPromoteMenu = createMenu(strings, StringIndexConstants.PROMOTE);
items[MenuIndexConstants.COLOR_PROMOTE] = colorPromoteMenu;
colorPromoteMenu.add(items[MenuIndexConstants.COLOR_PROMOTE_PROMOTETOPALETTED]);
colorPromoteMenu.add(items[MenuIndexConstants.COLOR_PROMOTE_PROMOTETOGRAY8]);
colorPromoteMenu.add(items[MenuIndexConstants.COLOR_PROMOTE_PROMOTETOGRAY16]);
colorPromoteMenu.add(items[MenuIndexConstants.COLOR_PROMOTE_PROMOTETORGB24]);
colorPromoteMenu.add(items[MenuIndexConstants.COLOR_PROMOTE_PROMOTETORGB48]);
// COLOR - REDUCE
Menu colorReduceMenu = createMenu(strings, StringIndexConstants.REDUCE);
items[MenuIndexConstants.COLOR_REDUCE] = colorReduceMenu;
colorReduceMenu.add(items[MenuIndexConstants.COLOR_REDUCE_REDUCETOBILEVELTHRESHOLD]);
colorReduceMenu.add(items[MenuIndexConstants.COLOR_REDUCE_REDUCENUMBEROFSHADESOFGRAY]);
colorReduceMenu.add(items[MenuIndexConstants.COLOR_REDUCE_CONVERTTOGRAYSCALE]);
colorReduceMenu.add(items[MenuIndexConstants.COLOR_REDUCE_MEDIANCUT]);
colorReduceMenu.add(items[MenuIndexConstants.COLOR_REDUCE_OCTREE]);
colorReduceMenu.add(items[MenuIndexConstants.COLOR_REDUCE_UNIFORMPALETTE]);
colorReduceMenu.add(items[MenuIndexConstants.COLOR_REDUCE_MAPTOARBITRARYPALETTE]);
// COLOR
Menu colorMenu = createMenu(strings, StringIndexConstants.COLOR);
items[MenuIndexConstants.COLOR] = colorMenu;
colorMenu.add(colorAdjustMenu);
colorMenu.add(colorHistogramMenu);
colorMenu.add(colorPaletteMenu);
colorMenu.add(colorPromoteMenu);
colorMenu.add(colorReduceMenu);
colorMenu.add(items[MenuIndexConstants.COLOR_INVERT]);
colorMenu.add(items[MenuIndexConstants.COLOR_CONVERTTOMINIMUMCOLORTYPE]);
menuBar.add(colorMenu);
// TRANSFORMATIONS
Menu transformationsMenu = createMenu(strings, StringIndexConstants.TRANSFORMATIONS);
items[MenuIndexConstants.TRANSFORMATIONS] = transformationsMenu;
transformationsMenu.add(items[MenuIndexConstants.TRANSFORMATIONS_MIRROR]);
transformationsMenu.add(items[MenuIndexConstants.TRANSFORMATIONS_FLIP]);
transformationsMenu.addSeparator();
transformationsMenu.add(items[MenuIndexConstants.TRANSFORMATIONS_ROTATELEFT90]);
transformationsMenu.add(items[MenuIndexConstants.TRANSFORMATIONS_ROTATERIGHT90]);
transformationsMenu.add(items[MenuIndexConstants.TRANSFORMATIONS_ROTATE180]);
transformationsMenu.addSeparator();
transformationsMenu.add(items[MenuIndexConstants.TRANSFORMATIONS_CROP]);
transformationsMenu.add(items[MenuIndexConstants.TRANSFORMATIONS_SCALE]);
transformationsMenu.add(items[MenuIndexConstants.TRANSFORMATIONS_SHEAR]);
menuBar.add(transformationsMenu);
// FILTERS
Menu filtersMenu = createMenu(strings, StringIndexConstants.FILTERS);
items[MenuIndexConstants.FILTERS] = filtersMenu;
menuBar.add(filtersMenu);
filtersMenu.add(items[MenuIndexConstants.FILTERS_BLUR]);
filtersMenu.add(items[MenuIndexConstants.FILTERS_SHARPEN]);
filtersMenu.add(items[MenuIndexConstants.FILTERS_EDGEDETECTION]);
filtersMenu.add(items[MenuIndexConstants.FILTERS_EMBOSS]);
filtersMenu.add(items[MenuIndexConstants.FILTERS_PSYCHEDELICDISTILLATION]);
filtersMenu.add(items[MenuIndexConstants.FILTERS_LITHOGRAPH]);
filtersMenu.add(items[MenuIndexConstants.FILTERS_HORIZONTALSOBEL]);
filtersMenu.add(items[MenuIndexConstants.FILTERS_VERTICALSOBEL]);
filtersMenu.add(items[MenuIndexConstants.FILTERS_HORIZONTALPREWITT]);
filtersMenu.add(items[MenuIndexConstants.FILTERS_VERTICALPREWITT]);
filtersMenu.addSeparator();
filtersMenu.add(items[MenuIndexConstants.FILTERS_MINIMUM]);
filtersMenu.add(items[MenuIndexConstants.FILTERS_MAXIMUM]);
filtersMenu.add(items[MenuIndexConstants.FILTERS_MEDIAN]);
filtersMenu.add(items[MenuIndexConstants.FILTERS_MEAN]);
filtersMenu.add(items[MenuIndexConstants.FILTERS_OIL]);
// VIEW
Menu viewMenu = createMenu(strings, StringIndexConstants.VIEW);
items[MenuIndexConstants.VIEW] = viewMenu;
menuBar.add(viewMenu);
viewMenu.add(items[MenuIndexConstants.VIEW_ZOOMIN]);
viewMenu.add(items[MenuIndexConstants.VIEW_ZOOMOUT]);
viewMenu.add(items[MenuIndexConstants.VIEW_SETORIGINALSIZE]);
// VIEW - INTERPOLATION TYPE
Menu viewInterpolationMenu = createMenu(strings, StringIndexConstants.VIEW_INTERPOLATIONTYPE);
items[MenuIndexConstants.VIEW_INTERPOLATIONTYPE] = viewInterpolationMenu;
//viewMenu.add(viewInterpolationMenu);
/*CheckboxGroup checkboxGroup = new CheckboxGroup();
int stringIndex = getStringIndex(MenuIndexConstants.VIEW_INTERPOLATIONTYPE_NEARESTNEIGHBOR);
items[MenuIndexConstants.VIEW_INTERPOLATIONTYPE_NEARESTNEIGHBOR] = new CheckboxMenuItem(strings.get(stringIndex), true);
stringIndex = getStringIndex(MenuIndexConstants.VIEW_INTERPOLATIONTYPE_BILINEAR);
items[MenuIndexConstants.VIEW_INTERPOLATIONTYPE_BILINEAR] = new CheckboxMenuItem(strings.get(stringIndex), false);
stringIndex = getStringIndex(MenuIndexConstants.VIEW_INTERPOLATIONTYPE_BICUBIC);
items[MenuIndexConstants.VIEW_INTERPOLATIONTYPE_BICUBIC] = new CheckboxMenuItem(strings.get(stringIndex), false);*/
viewInterpolationMenu.add(items[MenuIndexConstants.VIEW_INTERPOLATIONTYPE_NEARESTNEIGHBOR]);
viewInterpolationMenu.add(items[MenuIndexConstants.VIEW_INTERPOLATIONTYPE_BILINEAR]);
viewInterpolationMenu.add(items[MenuIndexConstants.VIEW_INTERPOLATIONTYPE_BICUBIC]);
// HELP
Menu helpMenu = createMenu(strings, StringIndexConstants.HELP);
items[MenuIndexConstants.HELP] = helpMenu;
menuBar.add(helpMenu);
helpMenu.add(items[MenuIndexConstants.HELP_ABOUT]);
helpMenu.add(items[MenuIndexConstants.HELP_SYSTEMINFORMATION]);
// add the listener to all items
for (int i = 0; i < items.length; i++)
{
if (items[i] != null)
{
MenuShortcut shortcut = createMenuShortcut(i);
if (shortcut != null)
{
items[i].setShortcut(shortcut);
}
items[i].addActionListener(listener);
}
}
}
/**
* Changes the enabled status of one of the MenuItem objects,
* given by its index.
*/
public void setEnabled(int index, boolean enabled)
{
if (index >= 0 && index < items.length && items[index] != null)
{
items[index].setEnabled(enabled);
}
}
/**
* Changes the label text of one of the MenuItem objects,
* given by its index.
*/
public void setLabel(int index, String text)
{
if (index >= 0 && index < items.length && items[index] != null)
{
items[index].setLabel(text);
}
}
/**
* Changes the enabled status of all MenuItem objects
* using the argument OperationProcessor object (more
* precisely, its isAvailable(int) method).
*/
public void updateEnabled(OperationProcessor op)
{
for (int i = 0; i < items.length; i++)
{
setEnabled(i, op.isAvailable(i));
}
}
/**
* Sets the label text of all MenuItem objects to
* new values using the argument Strings information.
*/
public void updateLabels(Strings strings)
{
for (int i = 0; i < items.length; i++)
{
int stringIndex = getStringIndex(i);
String text = strings.get(stringIndex);
setLabel(i, text);
}
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/gui/awt/AwtInfo.java 0000664 0000000 0000000 00000002633 07741250134 023626 0 ustar /*
* AwtInfo
*
* Copyright (c) 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.gui.awt;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.image.ColorModel;
import net.sourceforge.jiu.apps.StringIndexConstants;
import net.sourceforge.jiu.apps.Strings;
/**
* Retrieve some information on the current graphical environment.
* @author Marco Schmidt
* @since 0.8.0
*/
public class AwtInfo
{
private AwtInfo()
{
}
/**
* Returns information on the current AWT settings, regarding the current
* language by using a {@link Strings} resource.
* Right now, only returns the screen resolution.
* All textual information is taken from the strings argument.
* @param strings String resources
* @return AWT information
*/
public static String getAwtInfo(Strings strings)
{
Toolkit toolkit = Toolkit.getDefaultToolkit();
Dimension screen = toolkit.getScreenSize();
StringBuffer result = new StringBuffer();
result.append(strings.get(StringIndexConstants.SCREEN_RESOLUTION) + "=" + screen.width + " x " + screen.height + "\n");
ColorModel model = toolkit.getColorModel();
if (model != null)
{
/* only in Java 1.2+
result.append("# components=" + model.getNumComponents() + "\n"); */
result.append("# bits per pixel=" + model.getPixelSize() + "\n");
}
return result.toString();
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/gui/awt/package.html 0000664 0000000 0000000 00000000536 07741250134 023675 0 ustar
Classes to interoperate with Java's first GUI toolkit, the AWT (Abstract Windowing Toolkit). This includes GUI components and conversion from JIU's image types to AWT's image types. java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/gui/awt/ToolkitLoader.java 0000664 0000000 0000000 00000013302 07741250134 025026 0 ustar /* * ToolkitLoader * * Copyright (c) 2000, 2001, 2002, 2003 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.gui.awt; import java.awt.Frame; import java.awt.Image; import java.awt.MediaTracker; import java.awt.Toolkit; import java.io.IOException; import java.util.Vector; import net.sourceforge.jiu.codecs.ImageLoader; import net.sourceforge.jiu.data.PixelImage; import net.sourceforge.jiu.data.RGB24Image; import net.sourceforge.jiu.gui.awt.ImageCreator; import net.sourceforge.jiu.ops.OperationFailedException; /** * This class loads an instance of {@link java.awt.Image} using * {@link java.awt.Toolkit}'s built-in loading capabilities and * converts it to {@link net.sourceforge.jiu.data.RGB24Image} using * {@link net.sourceforge.jiu.gui.awt.ImageCreator}. *
* Supported file formats are JPEG and GIF. * PNG is supported since Java 1.3. * I have heard that XBM are supposedly loaded as well. * I don't know that format and haven't tested this functionality. *
* In addition, this class can also use JIU's built-in codecs from * this class. *
* RGB24Image rgbImage = ToolkitLoader.loadAsRgb24Image("flower.jpg"); ** This will only load images from files in formats that are supported * by Toolkit - normally, that only includes JPEG, GIF and since Java 1.3 PNG. * A potential problem of this approach is that Toolkit always delivers RGB * data, even if the image file only contains a black and white image. * In order to get an image object of the "real" type, try * JIU's {@link net.sourceforge.jiu.color.reduction.AutoDetectColorType} with *
rgbImage
(if you follow the link you will get a usage example
* for that class as well).
*
* System.exit(0);
.
* @author Marco Schmidt
*/
public class ToolkitLoader
{
private static Frame frame = null;
/**
* This class has only static methods and fields, so there is no need to instantiate it.
* That's why the empty constructor is hidden here.
*/
private ToolkitLoader()
{
}
/**
* Loads an image from a file using the AWT's built-in loader.
* Returns that image as an AWT {@link java.awt.Image} object.
* This method does nothing more than call {@link java.awt.Toolkit#getImage(String)},
* wait for it using a {@link java.awt.MediaTracker} and return
* the resulting image.
*
* @param fileName name of the image file
* @return the image as AWT image object
*/
public static Image load(String fileName)
{
Toolkit toolkit = Toolkit.getDefaultToolkit();
Image image = toolkit.getImage(fileName);
if (frame == null)
{
frame = new Frame();
}
MediaTracker mt = new MediaTracker(frame);
mt.addImage(image, 0);
try
{
mt.waitForID(0);
}
catch (InterruptedException e)
{
return null;
}
return image;
}
/**
* Loads an image from a file using the AWT's built-in loader and
* converts the image to a {@link net.sourceforge.jiu.data.RGB24Image}
* object.
* First calls {@link #load} with the filename, then converts
* the loaded image using {@link ImageCreator#convertImageToRGB24Image}.
* @param fileName name of the file from which the image is to be loaded
* @return loaded image as {@link net.sourceforge.jiu.data.RGB24Image}
*/
public static RGB24Image loadAsRgb24Image(String fileName)
{
return ImageCreator.convertImageToRGB24Image(load(fileName));
}
/**
* Attempts to load an image from a file given by its name,
* using both the JIU codecs and the image loading functionality in
* java.awt.Toolkit.
* First tries JIU's codecs, then java.awt.Toolkit.
* Simply calls loadViaToolkitOrCodecs(fileName, false);
.
* @param fileName name of the image file
* @return image object or null
on failure
*/
public static PixelImage loadViaToolkitOrCodecs(String fileName)
{
return loadViaToolkitOrCodecs(fileName, false, null);
}
/**
* Attempts to load an image from a file given by its name,
* using both the JIU codecs and the image loading functionality in
* java.awt.Toolkit.
* The second argument determines which method is tried first,
* Toolkit (true) or the JIU codecs (false).
* Uses {@link #loadAsRgb24Image} from this class for Toolkit loading
* and {@link net.sourceforge.jiu.codecs.ImageLoader} for JIU's codecs.
* @param fileName name of the image file
* @return image object or null
on failure
*/
public static PixelImage loadViaToolkitOrCodecs(String fileName, boolean preferToolkit, Vector progressListeners)
{
PixelImage result = null;
try
{
if (preferToolkit)
{
result = loadAsRgb24Image(fileName);
if (result == null)
{
result = ImageLoader.load(fileName, progressListeners);
}
}
else
{
result = ImageLoader.load(fileName, progressListeners);
if (result == null)
{
result = loadAsRgb24Image(fileName);
}
}
}
catch (OperationFailedException ofe)
{
}
catch (IOException ioe)
{
}
return result;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/gui/awt/ImageCanvas.java 0000664 0000000 0000000 00000012307 10377272462 024443 0 ustar /*
* ImageCanvas
*
* Copyright (c) 2000, 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.gui.awt;
import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.Graphics;
//import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
//import java.awt.RenderingHints;
import java.awt.ScrollPane;
import net.sourceforge.jiu.apps.EditorState;
/**
* An AWT canvas that displays an {@link java.awt.Image} object.
* Capable to display at arbitrary zooming levels.
* Does not use rendering hints because they require Java 1.2 or higher
* (although bilinear and bicubic interpolation usually improve display quality
* when zooming at the cost of slowing down image drawing).
*
* @author Marco Schmidt
*/
public class ImageCanvas extends Canvas
{
private Image image;
private int width;
private int height;
private int scaledWidth;
private int scaledHeight;
private double zoomFactorX = 1.0;
private double zoomFactorY = 1.0;
private boolean zoomToFit;
private ScrollPane myScrollPane;
public ImageCanvas(ScrollPane scrollPane)
{
myScrollPane = scrollPane;
//interpolation = RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR;
}
public void computeZoomToFitSize()
{
if (!zoomToFit || myScrollPane == null)
{
return;
}
Dimension scrollPaneSize = myScrollPane.getSize();
int maxWidth = scrollPaneSize.width;
int maxHeight = scrollPaneSize.height;
double paneRatio = (double)maxWidth / (double)maxHeight;
double imageRatio = (double)width / (double)height;
if (paneRatio < imageRatio)
{
scaledWidth = maxWidth;
scaledHeight = (int)(scaledWidth * imageRatio);
}
else
{
scaledHeight = maxHeight;
scaledWidth = (int)(scaledHeight * imageRatio);
}
scaledHeight--;
scaledWidth--;
zoomFactorX = (double)scaledWidth / (double)width;
zoomFactorY = zoomFactorX;
}
public int getZoomPercentageX()
{
return (int)(zoomFactorX * 100.0);
}
public int getZoomPercentageY()
{
return (int)(zoomFactorY * 100.0);
}
public Dimension getPreferredSize()
{
return new Dimension(scaledWidth, scaledHeight);
}
/**
* Draws image to upper left corner.
*/
public void paint(Graphics g)
{
if (image == null)
{
super.paint(g);
}
else
{
Rectangle rect = getBounds();
int canvasWidth = rect.width;
int canvasHeight = rect.height;
int x1 = 0;
int y1 = 0;
if (canvasWidth > scaledWidth)
{
x1 = (canvasWidth - scaledWidth) / 2;
}
if (canvasHeight > scaledHeight)
{
y1 = (canvasHeight - scaledHeight) / 2;
}
if (canvasHeight > canvasWidth || canvasHeight > scaledHeight)
{
super.paint(g);
}
/* commented because Graphics2D requires Java 1.2+
if (g instanceof Graphics2D)
{
((Graphics2D)g).setRenderingHint(RenderingHints.KEY_INTERPOLATION, interpolation);
}
*/
g.drawImage(image, x1, y1, scaledWidth, scaledHeight, this);
}
}
/**
* Specifies a new Image object to be displayed in this canvas.
* @param newImage the new Image object, potentially null
*/
public void setImage(Image newImage)
{
image = newImage;
width = image.getWidth(this);
height = image.getHeight(this);
scaledWidth = (int)(width * zoomFactorX);
scaledHeight = (int)(height * zoomFactorY);
/*zoomFactorX = 1.0;
zoomFactorY = 1.0;*/
setSize(scaledWidth, scaledHeight);
validate();
}
/**
* Sets both zoom factors to 1.0
.
*/
public void setOriginalSize()
{
setZoomFactor(1.0);
}
public double getZoomFactorX()
{
return zoomFactorX;
}
public double getZoomFactorY()
{
return zoomFactorY;
}
/**
* Sets the interpolation type used for drawing to the argument
* (must be one of the
* INTERPOLATION_xyz constants of EditorState), but does not
* do a redraw.
*/
public void setInterpolation(int newType)
{
switch(newType)
{
case(EditorState.INTERPOLATION_BICUBIC):
{
//interpolation = RenderingHints.VALUE_INTERPOLATION_BICUBIC;
break;
}
case(EditorState.INTERPOLATION_BILINEAR):
{
//interpolation = RenderingHints.VALUE_INTERPOLATION_BILINEAR;
break;
}
case(EditorState.INTERPOLATION_NEAREST_NEIGHBOR):
{
//interpolation = RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR;
break;
}
}
}
public void setZoomFactor(double newZoomFactor)
{
setZoomFactors(newZoomFactor, newZoomFactor);
}
public void setZoomFactors(double newZoomFactorX, double newZoomFactorY)
{
if (newZoomFactorX <= 0.0 || newZoomFactorY <= 0.0)
{
throw new IllegalArgumentException("Zoom factors must be larger than 0.0.");
}
zoomFactorX = newZoomFactorX;
zoomFactorY = newZoomFactorY;
scaledWidth = (int)(width * zoomFactorX);
scaledHeight = (int)(height * zoomFactorY);
setSize(scaledWidth, scaledHeight);
myScrollPane.validate();
}
public void setZoomToFit(boolean newValue)
{
zoomToFit = newValue;
validate();
}
/**
* Simply calls {@link #paint(Graphics)} with the argument.
* @param g Graphics context
*/
public void update(Graphics g)
{
paint(g);
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/gui/awt/ImageCreator.java 0000664 0000000 0000000 00000031621 10612167015 024614 0 ustar /*
* ImageCreator
*
* Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.gui.awt;
import net.sourceforge.jiu.data.BilevelImage;
import net.sourceforge.jiu.data.Gray16Image;
import net.sourceforge.jiu.data.Gray8Image;
import net.sourceforge.jiu.data.MemoryRGB24Image;
import net.sourceforge.jiu.data.Palette;
import net.sourceforge.jiu.data.Paletted8Image;
import net.sourceforge.jiu.data.PixelImage;
import net.sourceforge.jiu.data.RGB24Image;
import net.sourceforge.jiu.data.RGB48Image;
import net.sourceforge.jiu.data.RGBIndex;
import java.awt.Frame;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import java.awt.image.MemoryImageSource;
import java.awt.image.PixelGrabber;
/**
* A class to create {@link java.awt.Image} objects from various JIU image data types
* and vice versa.
* java.awt.Image objects can be used with the AWT and Swing GUI environments.
*
* @author Marco Schmidt
*/
public class ImageCreator
{
/**
* The default transparency value to be used: full opacity.
*/
public static final int DEFAULT_ALPHA = 0xff000000;
private static Frame frame;
private ImageCreator()
{
}
/**
* Creates a {@link java.awt.Image} object from a pixel array.
* Internally, a {@link java.awt.Frame} object is used to call its
* {@link java.awt.Frame#createImage} method
* with a {@link java.awt.image.MemoryImageSource} object.
*
* @param pixels the image pixel data in the typical RGBA 32-bit format, one int per pixel
* @param width the horizontal resolution in pixels of the image to be created
* @param height the vertical resolution in pixels of the image to be created
*/
public static Image createImage(int[] pixels, int width, int height)
{
if (width < 1 || height < 1)
{
throw new IllegalArgumentException("Error -- width and height " +
"must both be larger than zero.");
}
if (pixels == null)
{
throw new IllegalArgumentException("Error -- the pixel array " +
"must be non-null.");
}
if (pixels.length < width * height)
{
throw new IllegalArgumentException("Error -- the pixel array " +
"must contain at least width times height items.");
}
if (frame == null)
{
frame = new Frame();
}
return frame.createImage(new MemoryImageSource(width, height, pixels, 0, width));
}
public static BufferedImage convertToAwtBufferedImage(PixelImage image)
{
if (image == null)
{
return null;
}
if (image instanceof RGB24Image)
{
return convertToAwtBufferedImage((RGB24Image)image);
}
else
{
throw new IllegalArgumentException("Unsupported input image type: " + image.getImageType());
}
}
/**
* Convert a JIU {@link RGB24Image} to a {@link BufferedImage} with the
* given alpha value (use {@link RGBA#DEFAULT_ALPHA} as default).
* @param image JIU image to be converted
* @param alpha alpha value to be used with each pixel
* @return a new BufferedImage
* @since 0.14.2
*/
public static BufferedImage convertToAwtBufferedImage(RGB24Image image)
{
if (image == null)
{
return null;
}
final int WIDTH = image.getWidth();
final int HEIGHT = image.getHeight();
BufferedImage out = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
int outBuffer[] = new int[WIDTH];
byte red[] = new byte[WIDTH];
byte green[] = new byte[WIDTH];
byte blue[] = new byte[WIDTH];
for (int y = 0; y < HEIGHT; y++)
{
image.getByteSamples(RGBIndex.INDEX_RED, 0, y, WIDTH, 1, red, 0);
image.getByteSamples(RGBIndex.INDEX_GREEN, 0, y, WIDTH, 1, green, 0);
image.getByteSamples(RGBIndex.INDEX_BLUE, 0, y, WIDTH, 1, blue, 0);
for (int x = 0; x < WIDTH; x++)
{
outBuffer[x] = //0xff000000 |
((red[x] & 0xff) << 16) |
((green[x] & 0xff) << 8) |
((blue[x] & 0xff));
}
out.setRGB(0, y, WIDTH,1, outBuffer, 0, WIDTH);
}
return out;
}
/**
* Creates an instance of {@link java.awt.Image} from an instance of
* {@link RGB24Image}.
* This will require image.getWidth() * image.getHeight() * 4
* bytes of free memory.
* This method checks the type of the argument image via instanceof
* and the calls the right convertToAwtImage method of this class.
* @param image the RGB24Image to be converted
* @return newly-created AWT image instance
*/
public static Image convertToAwtImage(PixelImage image, int alpha)
{
if (image == null)
{
return null;
}
if (image instanceof RGB24Image)
{
return convertToAwtImage((RGB24Image)image, alpha);
}
else
if (image instanceof RGB48Image)
{
return convertToAwtImage((RGB48Image)image, alpha);
}
else
if (image instanceof Gray8Image)
{
return convertToAwtImage((Gray8Image)image, alpha);
}
else
if (image instanceof Gray16Image)
{
return convertToAwtImage((Gray16Image)image, alpha);
}
else
if (image instanceof Paletted8Image)
{
return convertToAwtImage((Paletted8Image)image, alpha);
}
else
if (image instanceof BilevelImage)
{
return convertToAwtImage((BilevelImage)image, alpha);
}
else
{
return null;
}
}
/**
* Convert a BilevelImage object to an AWT image object.
* @param image the image to be converted
* @param alpha the transparency value to be written to each
* pixel in the resulting image
* @return newly-created AWT image
*/
public static Image convertToAwtImage(BilevelImage image, int alpha)
{
if (image == null)
{
return null;
}
Toolkit toolkit = Toolkit.getDefaultToolkit();
if (toolkit == null)
{
return null;
}
int width = image.getWidth();
int height = image.getHeight();
if (width < 1 || height < 1)
{
return null;
}
int bytesPerRow = (width + 7) / 8;
int[] pixels = new int[width * height];
byte[] row = new byte[bytesPerRow];
int destOffset = 0;
for (int y = 0; y < height; y++)
{
image.getPackedBytes(0, y, width, row, 0, 0);
RGBA.convertFromPackedBilevel(row, 0, alpha, pixels, destOffset, width);
destOffset += width;
}
return toolkit.createImage(new MemoryImageSource(width, height, pixels, 0, width));
}
/**
* Creates an AWT Image object from a Gray16Image object and an alpha value.
* This is done by allocating a new int array with image.getWidth() times
* image.getHeight() elements, copying the data to those ints (using transparency
* information from the top eight bits of the alpha argument) and calling
* Toolkit.createImage with a MemoryImageSource of those int[] pixels.
* @param image the grayscale image to be converted
* @param alpha the alpha value, bits must only be set in the top eight bits
* @return AWT image created from the argument input image
*/
public static Image convertToAwtImage(Gray16Image image, int alpha)
{
if (image == null)
{
return null;
}
Toolkit toolkit = Toolkit.getDefaultToolkit();
if (toolkit == null)
{
return null;
}
int width = image.getWidth();
int height = image.getHeight();
if (width < 1 || height < 1)
{
return null;
}
int[] pixels = new int[width * height];
short[] gray = new short[width];
int destOffset = 0;
for (int y = 0; y < height; y++)
{
image.getShortSamples(0, 0, y, width, 1, gray, 0);
RGBA.convertFromGray16(gray, 0, alpha, pixels, destOffset, width);
destOffset += width;
}
return toolkit.createImage(new MemoryImageSource(width, height, pixels, 0, width));
}
/**
* Creates an AWT Image object from a Gray8Image object and an alpha value.
* This is done by allocating a new int array with image.getWidth() times
* image.getHeight() elements, copying the data to those ints (using transparency
* information from the top eight bits of the alpha argument) and calling
* Toolkit.createImage with a MemoryImageSource of those int[] pixels.
*
* @param image the grayscale image to be converted
* @param alpha the alpha value, bits must only be set in the top eight bits
* @return AWT image created from the argument input image
*/
public static Image convertToAwtImage(Gray8Image image, int alpha)
{
if (image == null)
{
return null;
}
Toolkit toolkit = Toolkit.getDefaultToolkit();
if (toolkit == null)
{
return null;
}
int width = image.getWidth();
int height = image.getHeight();
if (width < 1 || height < 1)
{
return null;
}
int[] pixels = new int[width * height];
byte[] gray = new byte[width];
int destOffset = 0;
for (int y = 0; y < height; y++)
{
image.getByteSamples(0, 0, y, width, 1, gray, 0);
RGBA.convertFromGray8(gray, 0, alpha, pixels, destOffset, width);
destOffset += width;
}
return toolkit.createImage(new MemoryImageSource(width, height, pixels, 0, width));
}
public static Image convertToAwtImage(Paletted8Image image, int alpha)
{
if (image == null)
{
return null;
}
Toolkit toolkit = Toolkit.getDefaultToolkit();
if (toolkit == null)
{
return null;
}
int width = image.getWidth();
int height = image.getHeight();
Palette palette = image.getPalette();
if (width < 1 || height < 1 || palette == null)
{
return null;
}
int[] red = new int[palette.getNumEntries()];
int[] green = new int[palette.getNumEntries()];
int[] blue = new int[palette.getNumEntries()];
for (int i = 0; i < palette.getNumEntries(); i++)
{
red[i] = palette.getSample(RGBIndex.INDEX_RED, i);
green[i] = palette.getSample(RGBIndex.INDEX_GREEN, i);
blue[i] = palette.getSample(RGBIndex.INDEX_BLUE, i);
}
int[] pixels = new int[width * height];
byte[] data = new byte[width];
int destOffset = 0;
for (int y = 0; y < height; y++)
{
image.getByteSamples(0, 0, y, width, 1, data, 0);
RGBA.convertFromPaletted8(data, 0, alpha, red, green, blue, pixels, destOffset, width);
destOffset += width;
}
return toolkit.createImage(new MemoryImageSource(width, height, pixels, 0, width));
}
public static Image convertToAwtImage(RGB24Image image, int alpha)
{
if (image == null)
{
return null;
}
Toolkit toolkit = Toolkit.getDefaultToolkit();
if (toolkit == null)
{
return null;
}
int width = image.getWidth();
int height = image.getHeight();
if (width < 1 || height < 1)
{
return null;
}
int[] pixels = new int[width * height];
byte[] red = new byte[width];
byte[] green = new byte[width];
byte[] blue = new byte[width];
int destOffset = 0;
for (int y = 0; y < height; y++)
{
image.getByteSamples(RGBIndex.INDEX_RED, 0, y, width, 1, red, 0);
image.getByteSamples(RGBIndex.INDEX_GREEN, 0, y, width, 1, green, 0);
image.getByteSamples(RGBIndex.INDEX_BLUE, 0, y, width, 1, blue, 0);
RGBA.convertFromRGB24(red, 0, green, 0, blue, 0, alpha, pixels, destOffset, width);
destOffset += width;
}
return toolkit.createImage(new MemoryImageSource(width, height, pixels, 0, width));
}
public static Image convertToAwtImage(RGB48Image image, int alpha)
{
if (image == null)
{
return null;
}
Toolkit toolkit = Toolkit.getDefaultToolkit();
if (toolkit == null)
{
return null;
}
int width = image.getWidth();
int height = image.getHeight();
if (width < 1 || height < 1)
{
return null;
}
int[] pixels = new int[width * height];
short[] red = new short[width];
short[] green = new short[width];
short[] blue = new short[width];
int destOffset = 0;
for (int y = 0; y < height; y++)
{
image.getShortSamples(RGBIndex.INDEX_RED, 0, y, width, 1, red, 0);
image.getShortSamples(RGBIndex.INDEX_GREEN, 0, y, width, 1, green, 0);
image.getShortSamples(RGBIndex.INDEX_BLUE, 0, y, width, 1, blue, 0);
RGBA.convertFromRGB48(red, 0, green, 0, blue, 0, alpha, pixels, destOffset, width);
destOffset += width;
}
return toolkit.createImage(new MemoryImageSource(width, height, pixels, 0, width));
}
/**
* Creates an {@link RGB24Image} from the argument AWT image instance.
* @param image AWT image object to be converted to a {@link RGB24Image}
* @return a {@link RGB24Image} object holding the image data from the argument image
*/
public static RGB24Image convertImageToRGB24Image(Image image)
{
if (image == null)
{
return null;
}
int width = image.getWidth(null);
int height = image.getHeight(null);
if (width < 1 || height < 1)
{
return null;
}
int[] pixels = new int[width * height];
PixelGrabber pg = new PixelGrabber(image, 0, 0, width, height, pixels, 0, width);
try
{
pg.grabPixels();
}
catch (InterruptedException e)
{
return null;
}
if ((pg.getStatus() & ImageObserver.ABORT) != 0)
{
return null;
}
RGB24Image result = new MemoryRGB24Image(width, height);
int offset = 0;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
int pixel = pixels[offset++] & 0xffffff;
// TODO: store alpha value; requires some sort of
// transparency channel data type yet to be implemented
result.putSample(RGBIndex.INDEX_RED, x, y, pixel >> 16);
result.putSample(RGBIndex.INDEX_GREEN, x, y, (pixel >> 8) & 0xff);
result.putSample(RGBIndex.INDEX_BLUE, x, y, pixel & 0xff);
}
}
return result;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/filters/ 0000775 0000000 0000000 00000000000 10546532075 021505 5 ustar java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/filters/UnsharpMaskKernel.java 0000664 0000000 0000000 00000002061 10572431506 025740 0 ustar /*
* UnsharpMaskKernel
*
* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.filters;
/**
* An unsharp mask kernel to be used with {@link ConvolutionKernelFilter}.
*
* @author Marco Schmidt
* @author Niels Donvil
* @since 0.10.0
*/
public class UnsharpMaskKernel extends ConvolutionKernelData
{
/**
* Creates a new unsharp mask kernel.
* @param level adjusts the amount of 'unsharpness', must be from 1 to 50
*/
public UnsharpMaskKernel(int level)
{
super("Unsharp mask", new int[] {1}, 1, 1, 1, 0);
if (level < 1 || level > 50)
{
throw new IllegalArgumentException("The level argument must be >= 1 and <= 50.");
}
level = ((51 - level) * 4 ) + 20;
setDiv(level);
int[] data =
{
0, 0, -1, 0, 0,
0, -8, -21, -8, 0,
-1, -21, level + 120, -21, -1,
0, -8, -21, -8, 0,
0, 0, -1, 0, 0
};
setData(data);
setHeight(5);
setWidth(5);
check();
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/filters/MedianFilter.java 0000664 0000000 0000000 00000002313 07741250133 024705 0 ustar /*
* MedianFilter
*
* Copyright (c) 2001, 2002 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.filters;
import net.sourceforge.jiu.filters.AreaFilterOperation;
import net.sourceforge.jiu.util.Median;
/**
* Applies a Median filter that replaces each pixel by the median of
* itself and its neighbors.
* The number of neighbors can be defined with the setArea methods.
* * Can be used as despeckle filter, but the image will lose sharpness. * The larger the area becomes, the less noise and the less sharpness will remain, * and the longer it will take. *
* Uses {@link net.sourceforge.jiu.util.Median} to do the search for the median value. *
* PixelImage image = ...; // some GrayIntegerImage or RGBIntegerImage * MedianFilter filter = new MedianFilter(); * filter.setArea(5, 5); * filter.setInputImage(image); * filter.process(); * PixelImage filteredImage = filter.getOutputImage(); ** @author Marco Schmidt */ public class MedianFilter extends AreaFilterOperation { public final int computeSample(int[] samples, int numSamples) { return Median.find(samples, 0, numSamples - 1); } } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/filters/MaximumFilter.java 0000664 0000000 0000000 00000002137 07741250133 025131 0 ustar /* * MaximumFilter * * Copyright (c) 2001, 2002, 2003 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.filters; import net.sourceforge.jiu.filters.AreaFilterOperation; /** * Filter operation that replaces each sample by the maximum value of itself * and its neighbor samples. *
* Note that this is not the maximum operation that takes two input images * and, for each position, takes the maximum sample value and writes it * to output. * *
* MaximumFilter filter = new MaximumFilter(); * filter.setArea(7, 5); * filter.setInputImage(image); * filter.process(); * PixelImage filteredImage = filter.getOutputImage(); ** @author Marco Schmidt * @since 0.9.0 * @see MinimumFilter */ public class MaximumFilter extends AreaFilterOperation { public final int computeSample(int[] samples, int numSamples) { int max = samples[0]; int index = 1; while (index < numSamples) { int value = samples[index++]; if (value > max) { max = value; } } return max; } } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/filters/ConvolutionKernelData.java 0000664 0000000 0000000 00000010027 10572432153 026615 0 ustar /* * ConvolutionKernelData * * Copyright (c) 2001, 2002 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.filters; /** * This class encapsulates the information for a specific convolution kernel filter. * An object of this class is used in combination with {@link ConvolutionKernelFilter}. * Several kernel data objects are predefined in that class. * * @author Marco Schmidt * @see ConvolutionKernelFilter */ public class ConvolutionKernelData { private int[] data; private int width; private int height; private int div; private int bias; private String name; /** * Creates a new kernel from the arguments. * Calls the various set methods to actually store these arguments. */ public ConvolutionKernelData(String name, int[] data, int width, int height, int div, int bias) { setName(name); setData(data); setWidth(width); setHeight(height); setDiv(div); setBias(bias); check(); } /** * Checks if this kernel's data is valid and throws an IllegalArgumentException if anything * is wrong. * Otherwise, does nothing. */ public void check() { if (data.length < width * height) { throw new IllegalArgumentException("Kernel data array must have at least width * height elements."); } } /** * Returns this kernel's bias value. * See {@link ConvolutionKernelFilter} for an explanation of this and other kernel properties. * @see #setBias */ public int getBias() { return bias; } /** * Returns this kernel's div value. * Must not be
0
.
* See {@link ConvolutionKernelFilter} for an explanation of this and other kernel properties.
* @see #setDiv
*/
public int getDiv()
{
return div;
}
/**
* Returns the kernel data.
* See {@link ConvolutionKernelFilter} for an explanation of this and other kernel properties.
* @see #setData
*/
public int[] getData()
{
return data;
}
/**
* Returns this kernel's height, an odd positive number.
* See {@link ConvolutionKernelFilter} for an explanation of this and other kernel properties.
*/
public int getHeight()
{
return height;
}
/**
* Returns this kernel's name.
*/
public String getName()
{
return name;
}
/**
* Returns this kernel's width, an odd positive number.
* See {@link ConvolutionKernelFilter} for an explanation of this and other kernel properties.
*/
public int getWidth()
{
return width;
}
/**
* Set new bias value.
* See {@link ConvolutionKernelFilter} for an explanation of this and other kernel properties.
*/
public void setBias(int newBias)
{
bias = newBias;
}
/**
* Sets the data array to be used in this kernel.
* Must have at least getWidth() times getHeight() elements - however,
* this constraint is not checked in this method (setting
* width and height may happen later).
* Call {@link #check}
* @param newData
*/
public void setData(int[] newData)
{
if (newData == null)
{
throw new IllegalArgumentException("The data array must not be null.");
}
if (newData.length < 1)
{
throw new IllegalArgumentException("The data array must have a length of at least 1.");
}
data = newData;
}
public void setDiv(int newDiv)
{
if (newDiv == 0)
{
throw new IllegalArgumentException("Div value must not be 0.");
}
div = newDiv;
}
public void setHeight(int newHeight)
{
if (newHeight < 1)
{
throw new IllegalArgumentException("Height must be 1 or larger.");
}
if ((newHeight % 2) == 0)
{
throw new IllegalArgumentException("Height must not be an even number.");
}
height = newHeight;
}
public void setName(String newName)
{
name = newName;
}
public void setWidth(int newWidth)
{
if (newWidth < 1)
{
throw new IllegalArgumentException("Width must be 1 or larger.");
}
if ((newWidth % 2) == 0)
{
throw new IllegalArgumentException("Width must not be an even number.");
}
width = newWidth;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/filters/AreaFilterOperation.java 0000664 0000000 0000000 00000017750 07741250133 026254 0 ustar /*
* AreaFilterOperation
*
* Copyright (c) 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.filters;
import net.sourceforge.jiu.data.GrayIntegerImage;
import net.sourceforge.jiu.data.IntegerImage;
import net.sourceforge.jiu.data.PixelImage;
import net.sourceforge.jiu.data.RGBIntegerImage;
import net.sourceforge.jiu.ops.ImageToImageOperation;
import net.sourceforge.jiu.ops.MissingParameterException;
import net.sourceforge.jiu.ops.WrongParameterException;
/**
* Base class for operations that convert images to images and determine
* an output sample by doing calculations on the input sample at the same
* position plus some neighboring samples.
*
* Override {@link #computeSample} and the operation will work.
* @since 0.9.0
* @author Marco Schmidt
*/
public abstract class AreaFilterOperation extends ImageToImageOperation
{
private int areaWidth;
private int areaHeight;
/**
* Checks if the argument is a valid area height value.
* The default implementation requires the argument to be odd and larger than zero.
* Override this method if your extension of AreaFilterOperation requires different heights.
* @throws IllegalArgumentException if the argument is not valid
*/
public void checkAreaHeight(int height)
{
if (height < 1)
{
throw new IllegalArgumentException("Height must be larger than 0.");
}
if ((height & 1) == 0)
{
throw new IllegalArgumentException("Height must be odd.");
}
}
/**
* Checks if the argument is a valid area width value.
* The default implementation requires the argument to be odd and larger than zero.
* Override this method if your extension of AreaFilterOperation requires different widths.
* @throws IllegalArgumentException if the argument is not valid
*/
public void checkAreaWidth(int width)
{
if (width < 1)
{
throw new IllegalArgumentException("Width must be larger than 0.");
}
if ((width & 1) == 0)
{
throw new IllegalArgumentException("Width must be odd.");
}
}
/**
* Determine the resulting sample for an array with the source sample
* and zero or more of its neighbors.
* This abstract method must be implemented by classes extending this operation.
* The array will hold numSamples
samples, which will be stored
* starting at offset 0
.
*
* Normally, numSamples
is equal to {@link #getAreaWidth} times {@link #getAreaHeight}.
* Near the border of the image you may get less samples.
* Example: the top left sample of an image has only three neighbors (east, south-east and south),
* so you will only get four samples (three neighbors and the sample itself).
* @param samples the array holding the sample(s)
* @param numSamples number of samples in the array
* @return sample to be written to the output image
*/
public abstract int computeSample(int[] samples, int numSamples);
/**
* Returns the current area height.
* @return height of area window in pixels
* @see #setAreaHeight(int)
*/
public int getAreaHeight()
{
return areaHeight;
}
/**
* Returns the current area width.
* @return width of area window in pixels
* @see #setAreaWidth(int)
*/
public int getAreaWidth()
{
return areaWidth;
}
/**
* Applies the filter to one of the channels of an image.
*/
private void process(int channelIndex, IntegerImage in, IntegerImage out)
{
processBorders(channelIndex, in, out);
processCenter(channelIndex, in, out);
/*
final int HEIGHT = in.getHeight();
final int WIDTH = in.getWidth();
final int H_2 = areaWidth / 2;
final int V_2 = areaHeight / 2;
int processedItems = channelIndex * HEIGHT;
final int TOTAL_ITEMS = in.getNumChannels() * HEIGHT;
int[] samples = new int[areaWidth * areaHeight];
for (int y = 0; y < HEIGHT; y++)
{
for (int x = 0; x < WIDTH; x++)
{
// collect samples from area
int numSamples = 0;
for (int v = y - V_2; v <= y + V_2; v++)
{
if (v >= 0 && v < HEIGHT)
{
for (int u = x - H_2; u <= x + H_2; u++)
{
if (u >= 0 && u < WIDTH)
{
samples[numSamples++] = in.getSample(channelIndex, u, v);
}
}
}
}
// determine and set output sample
out.putSample(channelIndex, x, y, computeSample(samples, numSamples));
}
setProgress(processedItems++, TOTAL_ITEMS);
}
*/
}
private void process(IntegerImage in, IntegerImage out)
{
if (out == null)
{
out = (IntegerImage)in.createCompatibleImage(in.getWidth(), in.getHeight());
setOutputImage(out);
}
for (int channelIndex = 0; channelIndex < in.getNumChannels(); channelIndex++)
{
process(channelIndex, in, out);
}
}
public void process() throws
MissingParameterException,
WrongParameterException
{
if (areaWidth == 0)
{
throw new MissingParameterException("Area width has not been initialized.");
}
if (areaHeight == 0)
{
throw new MissingParameterException("Area height has not been initialized.");
}
ensureInputImageIsAvailable();
ensureImagesHaveSameResolution();
PixelImage in = getInputImage();
PixelImage out = getOutputImage();
if (in instanceof GrayIntegerImage || in instanceof RGBIntegerImage)
{
process((IntegerImage)in, (IntegerImage)out);
}
else
{
throw new WrongParameterException("Input image must implement GrayIntegerImage or RGBIntegerImage.");
}
}
private void processBorders(int channelIndex, IntegerImage in, IntegerImage out)
{
/*processBorderNorthWest(channelIndex, in, out);
processBorderNorth(channelIndex, in, out);
processBorderNorthEast(channelIndex, in, out);
processBorderEast(channelIndex, in, out);
processBorderSouthEast(channelIndex, in, out);
processBorderSouth(channelIndex, in, out);
processBorderSouthWest(channelIndex, in, out);
processBorderWest(channelIndex, in, out);*/
}
private void processCenter(int channelIndex, IntegerImage in, IntegerImage out)
{
final int HEIGHT = in.getHeight();
final int WIDTH = in.getWidth();
final int AREA_WIDTH = getAreaWidth();
final int H_2 = AREA_WIDTH / 2;
final int AREA_HEIGHT = getAreaHeight();
final int V_2 = AREA_HEIGHT / 2;
if (WIDTH < AREA_WIDTH || HEIGHT < AREA_HEIGHT)
{
return;
}
final int NUM_SAMPLES = AREA_WIDTH * AREA_HEIGHT;
final int TOTAL_ITEMS = in.getNumChannels() * HEIGHT;
int processedItems = channelIndex * HEIGHT + AREA_HEIGHT / 2;
int[] samples = new int[AREA_WIDTH * AREA_HEIGHT];
for (int y1 = 0, y2 = V_2; y2 < HEIGHT - V_2; y1++, y2++)
{
for (int x1 = 0, x2 = H_2; x2 < WIDTH - H_2; x1++, x2++)
{
in.getSamples(channelIndex, x1, y1, areaWidth, areaHeight, samples, 0);
out.putSample(channelIndex, x2, y2, computeSample(samples, NUM_SAMPLES));
}
setProgress(processedItems++, TOTAL_ITEMS);
}
}
/**
* Sets the area of the window to be used to determine each pixel's mean to
* the argument width and height.
* @param width width of window, must be 1 or larger
* @param height height of window, must be 1 or larger
* @see #setAreaHeight
* @see #setAreaWidth
*/
public void setArea(int width, int height)
{
setAreaWidth(width);
setAreaHeight(height);
}
/**
* Sets the height of the area of the window to be used to determine each pixel's mean to
* the argument value.
* @param height height of window, must be odd and 1 or larger
* @see #getAreaHeight
* @see #setArea
* @see #setAreaWidth
*/
public void setAreaHeight(int height)
{
checkAreaHeight(height);
areaHeight = height;
}
/**
* Sets the width of the area of the window to be used to determine each pixel's mean to
* the argument value.
* @param width width of window, must be odd and 1 or larger
* @see #getAreaWidth
* @see #setArea
* @see #setAreaHeight
*/
public void setAreaWidth(int width)
{
checkAreaWidth(width);
areaWidth = width;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/filters/package.html 0000664 0000000 0000000 00000000531 07741250133 023760 0 ustar
Various image filters that produce an output image from an input image, mostly reading a pixel and its neighbors in the input image to determine the pixel in the output image. java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/filters/OilFilter.java 0000664 0000000 0000000 00000006332 07741250133 024240 0 ustar /* * OilFilter * * Copyright (c) 2001, 2002, 2003 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.filters; import net.sourceforge.jiu.data.IntegerImage; import net.sourceforge.jiu.data.PixelImage; import net.sourceforge.jiu.filters.AreaFilterOperation; import net.sourceforge.jiu.ops.MissingParameterException; import net.sourceforge.jiu.ops.WrongParameterException; /** * Applies a filter that makes the image look like an oil painting. * This is accomplished by creating a histogram of the neighboring samples * for each input sample and storing the value that occurs most often * in the output image. * If two or more samples occur an equal number of times, the lowest * sample value is picked. *
* PixelImage image = ...; // some GrayIntegerImage or RGBIntegerImage * OilFilter filter = new OilFilter(); * filter.setArea(5, 5); * filter.setInputImage(image); * filter.process(); * PixelImage filteredImage = filter.getOutputImage(); **
* PixelImage image = ...; // some GrayIntegerImage or RGBIntegerImage * MeanFilter filter = new MeanFilter(); * filter.setArea(5, 5); * filter.setInputImage(image); * filter.process(); * PixelImage filteredImage = filter.getOutputImage(); ** @since 0.5.0 * @author Marco Schmidt */ public class MeanFilter extends AreaFilterOperation { public int computeSample(int[] samples, int numSamples) { int sum = 0; int index = numSamples; do { sum += samples[--index]; } while (index != 0); return sum / numSamples; } } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/filters/BorderSampleGenerator.java 0000664 0000000 0000000 00000007763 10541050265 026602 0 ustar /* * BorderSampleGenerator * * Copyright (c) 2002, 2003 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.filters; import net.sourceforge.jiu.data.IntegerImage; /** * Abstract base class for classes that fill an
int
array with samples
* from a rectangular region of an image's channel by
* (1) copying int
samples from an {@link net.sourceforge.jiu.data.IntegerImage} object
* and by (2) generating samples that lie outside of the image.
* To be used by {@link ConvolutionKernelFilter} and other operations
* that require rectangular parts of an image that may not lie fully
* inside of the image.
* @author Marco Schmidt
* @since 0.10.0
*/
public abstract class BorderSampleGenerator
{
private int areaWidth;
private int areaHeight;
private int channelIndex;
private IntegerImage image;
/**
* Initialize width and height of the area to be covered in every call to
* {@link #fill}, also provides the image to be used for data copying.
* The current channel is set to 0.
* @param integerImage the image from which samples will be copied
* @param areaWidth number of columns of the area to be covered in {@link #fill}
* @param areaHeight number of rows of the area to be covered in {@link #fill}
*/
public BorderSampleGenerator(IntegerImage integerImage, int areaWidth, int areaHeight)
{
image = integerImage;
if (image == null)
{
throw new IllegalArgumentException("The image argument must be non-null.");
}
this.areaWidth = areaWidth;
if (areaWidth < 1 || (areaWidth % 2) == 0)
{
throw new IllegalArgumentException("Area width must be a positive odd number.");
}
this.areaHeight = areaHeight;
if (areaHeight < 1 || (areaHeight % 2) == 0)
{
throw new IllegalArgumentException("Area height must be a positive odd number.");
}
}
/**
* Fills the argument array with samples from the current channel of the image
* given to the constructor, generating samples that lie outside of the image.
* The samples are copied (or generated) from the row y to row y + areaHeight - 1,
* and within each row from column x to x + areaWidth - 1.
* * The implementation of this method is left to the child classes. * There are different ways to generate new samples, and each child class * is supposed to implement another way. * Obviously, the child classes also must copy samples from the image. * @param x leftmost column to be copied or generated * @param y top row to be copied or generated * @param samples array to which samples will be written; must have at least * {@link #getAreaWidth} times {@link #getAreaHeight} elements */ public abstract void fill(int x, int y, int[] samples); /** * Returns the number of rows from which data is copied or generated * with every call to {@link #fill}. * @return number or rows of a fill area */ public int getAreaHeight() { return areaHeight; } /** * Returns the number of columns from which data is copied or generated * with every call to {@link #fill}. * @return number or columns of a fill area */ public int getAreaWidth() { return areaWidth; } /** * Returns the index of the channel of the image from which data is copied. * @see #setChannelIndex * @return number or rows */ public int getChannelIndex() { return channelIndex; } /** * Returns the image from which data is copied. * @return image object */ public IntegerImage getImage() { return image; } /** * Sets the channel from which data is copied in {@link #fill}. * @see #getChannelIndex */ public void setChannelIndex(int newChannelIndex) { if (newChannelIndex < 0 || newChannelIndex >= image.getNumChannels()) { throw new IllegalArgumentException("Illegal channel index: " + newChannelIndex + " (must be from 0 to " + (image.getNumChannels() - 1) + ")."); } else { channelIndex = newChannelIndex; } } } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/filters/MinimumFilter.java 0000664 0000000 0000000 00000001317 07741250133 025126 0 ustar /* * MinimumFilter * * Copyright (c) 2001, 2002 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.filters; import net.sourceforge.jiu.filters.AreaFilterOperation; /** * Filter operation that replaces each sample by the minimum value of itself * and its neighbors. * See {@link MaximumFilter} for a usage example. * @author Marco Schmidt * @since 0.9.0 */ public class MinimumFilter extends AreaFilterOperation { public final int computeSample(int[] samples, int numSamples) { int min = samples[--numSamples]; while (numSamples != 0) { int value = samples[--numSamples]; if (value < min) { min = value; } } return min; } } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/filters/ConvolutionKernelFilter.java 0000664 0000000 0000000 00000031321 10377272653 027203 0 ustar /* * ConvolutionKernelFilter * * Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.filters; import net.sourceforge.jiu.data.GrayIntegerImage; import net.sourceforge.jiu.data.IntegerImage; import net.sourceforge.jiu.data.PixelImage; import net.sourceforge.jiu.data.RGBIntegerImage; import net.sourceforge.jiu.ops.ImageToImageOperation; import net.sourceforge.jiu.ops.MissingParameterException; import net.sourceforge.jiu.ops.OperationFailedException; import net.sourceforge.jiu.ops.WrongParameterException; /** * Applies a convolution kernel filter to an image. *
* ConvolutionKernelFilter filter = new ConvolutionKernelFilter(); * filter.setKernel(ConvolutionKernelFilter.TYPE_SHARPEN); * filter.setInputImage(image); * filter.process(); * PixelImage sharpenedImage = filter.getOutputImage();* Use static convenience method on image
img
:
* * PixelImage filteredImage = ConvolutionKernelFilter.filter(img, ConvolutionKernelFilter.TYPE_BLUR); **
* The resulting implementation is significantly faster than the * reference implementation. * The contest was started by the posting [JPEC#3] Vorschläge to de.comp.lang.java * by Marco Schmidt (2001-02-18) and was ended by the posting [JPEC#3] Ergebnisse * (2001-03-07). * A Usenet archive like Google Groups should be * able to provide the postings. * * @author Bernd Eckenfels * @author Carl Rosenberger * @author Dietmar Münzenberger * @author Karsten Schulz * @author Marco Kaiser * @author Marco Schmidt * @author Peter Luschny * @author Peter Schneider * @author Ramin Sadre * @author Roland Dieterich * @author Thilo Schwidurski */ public class ConvolutionKernelFilter extends ImageToImageOperation { public static final int TYPE_BLUR = 0; public static final int TYPE_SHARPEN = 1; public static final int TYPE_EDGE_DETECTION = 2; public static final int TYPE_EMBOSS = 3; public static final int TYPE_PSYCHEDELIC_DISTILLATION = 4; public static final int TYPE_LITHOGRAPH = 5; public static final int TYPE_HORIZONTAL_SOBEL = 6; public static final int TYPE_VERTICAL_SOBEL = 7; public static final int TYPE_HORIZONTAL_PREWITT = 8; public static final int TYPE_VERTICAL_PREWITT = 9; private static final int[] BLUR_DATA = {1, 1, 1, 1, 1, 1, 1, 1, 1}; private static final int[] SHARPEN_DATA = {0, -1, 0, -1, 5, -1, 0, -1, 0}; private static final int[] EDGE_DETECTION_DATA = {-1, -1, -1, -1, 8, -1, -1, -1, -1}; private static final int[] EMBOSS_DATA = {1, 1, 0, 1, 0, -1, 0, -1, -1}; private static final int[] PSYCHEDELIC_DISTILLATION_DATA = {0, -1, -2, -3, -4, 0, -1, 3, 2, 1, 0, -1, 10, 2, 1, 0, -1, 3, 2, 1, 0, -1, -2, -3, -4}; private static final int[] LITHOGRAPH_DATA = {-1, -1, -1, -1, -1, -1,-10,-10,-10, -1, -1,-10, 98,-10, -1, -1,-10,-10,-10, -1, -1, -1, -1, -1, -1}; private static final int[] HORIZONTAL_SOBEL_DATA = {-1, 0, 1, -2, 0, 2, -1, 0, 1}; private static final int[] VERTICAL_SOBEL_DATA = {-1, -2, -1, 0, 0, 0, 1, 2, 1}; private static final int[] HORIZONTAL_PREWITT_DATA = {-1, 0, 1, -1, 0, 1, -1, 0, 1}; private static final int[] VERTICAL_PREWITT_DATA = {-1, -1, -1, 0, 0, 0, 1, 1, 1}; private static ConvolutionKernelData[] PREDEFINED_KERNELS = { new ConvolutionKernelData("Blur", BLUR_DATA, 3, 3, 9, 0), new ConvolutionKernelData("Sharpen", SHARPEN_DATA, 3, 3, 1, 0), new ConvolutionKernelData("Edge detection", EDGE_DETECTION_DATA, 3, 3, 1, 0), new ConvolutionKernelData("Emboss", EMBOSS_DATA, 3, 3, 1, 128), new ConvolutionKernelData("Psychedelic Distillation", PSYCHEDELIC_DISTILLATION_DATA, 5, 5, 1, 0), new ConvolutionKernelData("Lithograph", LITHOGRAPH_DATA, 5, 5, 1, 0), new ConvolutionKernelData("Horizontal Sobel", HORIZONTAL_SOBEL_DATA, 3, 3, 1, 0), new ConvolutionKernelData("Vertical Sobel", VERTICAL_SOBEL_DATA, 3, 3, 1, 0), new ConvolutionKernelData("Horizontal Prewitt", HORIZONTAL_PREWITT_DATA, 3, 3, 1, 0), new ConvolutionKernelData("Vertical Prewitt", VERTICAL_PREWITT_DATA, 3, 3, 1, 0) }; private int kernelBias; private int[] kernelData; private int kernelDiv; private int kernelHeight; private int kernelWidth; /** * Copies row data from input image to buffer and replicates * samples at the left and right border. */ private void copyRow(IntegerImage srcImage, int srcChannelIndex, int rowIndex, int[] dest, int destOffset, int numBorderColumns) { /* row has a width of N + 1 samples at positions 0 to N X X 0 1 ... N Y Y copy byte at 0 to all X positions copy byte at N to all Y positions */ final int WIDTH = srcImage.getWidth(); srcImage.getSamples(srcChannelIndex, 0, rowIndex, WIDTH, 1, dest, destOffset + numBorderColumns); // copy leftmost sample to X X positions int srcOffset = destOffset + numBorderColumns; int offset = numBorderColumns - 1; while (offset >= 0) { dest[offset--] = dest[srcOffset]; } // copy rightmost sample to Y Y positions srcOffset = destOffset + numBorderColumns + WIDTH - 1; offset = srcOffset + 1; int n = numBorderColumns; while (n-- > 0) { dest[offset++] = dest[srcOffset]; } } /** * Filters argument image with argument kernel type and returns output image. * Static convenience method to do filtering with one line of code: *
PixelImage blurredImage = ConvolutionKernelFilter.filter(in, ConvolutionKernelFilter.TYPE_BLUR);*/ public static PixelImage filter(PixelImage input, int kernelType) { return filter(input, PREDEFINED_KERNELS[kernelType]); } public static PixelImage filter(PixelImage input, ConvolutionKernelData data) { ConvolutionKernelFilter op = new ConvolutionKernelFilter(); op.setKernel(data); op.setInputImage(input); try { op.process(); return op.getOutputImage(); } catch (OperationFailedException ofe) { return null; } } /** * Applies the kernel to one of the channels of an image. * @param channelIndex index of the channel to be filtered, must be from 0 to ByteChannelImage.getNumChannels() - 1 */ private void process(int channelIndex, IntegerImage in, IntegerImage out) { final int H_DIM = kernelWidth; final int H_DIM_2 = (H_DIM / 2); final int V_DIM = kernelHeight; final int V_DIM_2 = (V_DIM / 2); final int HEIGHT = in.getHeight(); final int WIDTH = in.getWidth(); final int NEW_WIDTH = WIDTH + 2 * H_DIM_2; final int NEW_HEIGHT = HEIGHT + 2 * V_DIM_2; final int MAX = in.getMaxSample(channelIndex); int processedItems = channelIndex * HEIGHT; final int TOTAL_ITEMS = in.getNumChannels() * HEIGHT; int[] src = new int[NEW_WIDTH * NEW_HEIGHT]; // fill src with data for (int y = 0, offs = V_DIM_2 * NEW_WIDTH; y < HEIGHT; y++, offs += NEW_WIDTH) { copyRow(in, channelIndex, y, src, offs, H_DIM_2); } // copy row H_DIM_2 to 0 .. H_DIM_2 - 1 int srcOffset = V_DIM_2 * NEW_WIDTH; for (int y = 0; y < V_DIM_2; y++) { System.arraycopy(src, srcOffset, src, y * NEW_WIDTH, NEW_WIDTH); } // copy row H_DIM_2 + HEIGHT - 1 to H_DIM_2 + HEIGHT .. 2 * H_DIM_2 + HEIGHT - 1 srcOffset = (HEIGHT + V_DIM_2 - 1) * NEW_WIDTH; for (int y = V_DIM_2 + HEIGHT; y < NEW_HEIGHT; y++) { System.arraycopy(src, srcOffset, src, y * NEW_WIDTH, NEW_WIDTH); } // do the filtering int count = H_DIM * V_DIM; final int[] kernelLine = new int[count]; final int[] kernelD = new int[count]; int p; count = 0; final int j = H_DIM - 1; for (int x = H_DIM; x-- > 0;) { for (int y = V_DIM; y-- > 0;) { int index = y * H_DIM + x; if (kernelData[index] != 0) { kernelLine[count] = kernelData[index]; kernelD[count] = y * NEW_WIDTH + x; count++; } } } // all kernel elements are zero => nothing to do, resulting channel will be full of zeroes if (count == 0) { setProgress(channelIndex, in.getNumChannels()); return; } p = (HEIGHT - 1) * NEW_WIDTH + (WIDTH - 1); int[] dest = new int[WIDTH]; for (int y = HEIGHT; y-- > 0;) { for (int x = WIDTH; x-- > 0;) { int sum = 0; for (int i = count; i-- > 0;) { sum += (src[p + kernelD[i]] & MAX) * kernelLine[i]; } sum = (sum / kernelDiv) + kernelBias; if (sum <= 0) { dest[x] = 0; } else if (sum >= MAX) { dest[x] = MAX; } else { dest[x] = sum; } // (byte)(((0xFFFFFF00 & sum) == 0) ? sum : ((sum >>> 31) - 1)); p--; } out.putSamples(channelIndex, 0, y, WIDTH, 1, dest, 0); p -= j; setProgress(processedItems++, TOTAL_ITEMS); } } private void process(IntegerImage in, IntegerImage out) { for (int channelIndex = 0; channelIndex < in.getNumChannels(); channelIndex++) { process(channelIndex, in, out); } } public void process() throws MissingParameterException, WrongParameterException { ensureInputImageIsAvailable(); ensureImagesHaveSameResolution(); PixelImage in = getInputImage(); if (in instanceof GrayIntegerImage || in instanceof RGBIntegerImage) { PixelImage out = getOutputImage(); if (out == null) { out = (IntegerImage)in.createCompatibleImage(in.getWidth(), in.getHeight()); setOutputImage(out); } process((IntegerImage)in, (IntegerImage)out); } else { throw new WrongParameterException("Input image must implement GrayIntegerImage or RGBIntegerImage."); } } /** * Sets properties of the kernel to be used in this operation. * @param data the kernel coefficients; this one-dimensional array stores * them in order top-to-bottom, left-to-right; the length of this * array must be at least width times height * @param width the width of the kernel; must not be even * @param height the height of the kernel; must not be even * @param div the result is divided by this value after the addition of value * (so this value must not be zero) * @param bias this value is added to the result before the division */ public void setKernel(int[] data, int width, int height, int div, int bias) { if (data == null) { throw new IllegalArgumentException("Kernel data must be non-null."); } if (width < 1) { throw new IllegalArgumentException("Kernel width must be at least 1."); } if (width % 2 != 1) { throw new IllegalArgumentException("Kernel width must not be even."); } if (height < 1) { throw new IllegalArgumentException("Kernel height must be at least 1."); } if (height % 2 != 1) { throw new IllegalArgumentException("Kernel width must not be even."); } if (data.length < width * height) { throw new IllegalArgumentException("Kernel data must have a length >= " + (width * height) + " to hold " + width + " times " + height + " elements."); } if (div == 0) { throw new IllegalArgumentException("The div parameter must not be zero."); } kernelData = data; kernelWidth = width; kernelHeight = height; kernelDiv = div; kernelBias = bias; } /** * Sets kernel data to be used for filtering. * @param ckd all information necessary for filtering */ public void setKernel(ConvolutionKernelData ckd) { setKernel(ckd.getData(), ckd.getWidth(), ckd.getHeight(), ckd.getDiv(), ckd.getBias()); } /** * Sets one of the predefined kernel types to be used for filtering. * @param type one of the TYPE_xyz constants of this class * @throws IllegalArgumentException if the argument is not a valid TYPE_xyz constant */ public void setKernel(int type) { if (type < 0 || type >= PREDEFINED_KERNELS.length) { throw new IllegalArgumentException("Not a valid type index for predefined kernels: " + type); } else { setKernel(PREDEFINED_KERNELS[type]); } } } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/data/ 0000775 0000000 0000000 00000000000 10546532075 020746 5 ustar java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/data/Gray16Image.java 0000664 0000000 0000000 00000001456 07741250133 023626 0 ustar /* * Gray16Image * * Copyright (c) 2003 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.data; import net.sourceforge.jiu.data.ShortChannelImage; import net.sourceforge.jiu.data.GrayIntegerImage; /** * Interface for grayscale images using integer samples that are sixteen bits large. * Valid sample values must lie in the interval 0 to 65535 (including both of those values). * Like all grayscale images, implementations of this class are supposed to have one channel only. * Simply merges the two interfaces GrayIntegerImage and ShortChannelImage without adding methods of its own. * @author Marco Schmidt * @since 0.11.0 * @see ShortChannelImage * @see GrayIntegerImage */ public interface Gray16Image extends GrayIntegerImage, ShortChannelImage { } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/data/RGB24Image.java 0000664 0000000 0000000 00000000760 07741250133 023332 0 ustar /* * RGB24Image * * Copyright (c) 2000, 2001, 2002, 2003 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.data; import net.sourceforge.jiu.data.ByteChannelImage; import net.sourceforge.jiu.data.RGBIntegerImage; /** * An empty interface for RGB truecolor images with integer samples * that are each eight bits large (thus, 24 bits per pixel). * @author Marco Schmidt */ public interface RGB24Image extends ByteChannelImage, RGBIntegerImage { } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/data/RGBImage.java 0000664 0000000 0000000 00000000664 07741250133 023167 0 ustar /* * RGBImage * * Copyright (c) 2002, 2003 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.data; import net.sourceforge.jiu.data.RGBIndex; /** * An interface for RGB truecolor images. * This is an empty interface, useful for labeling an image type * as being an RGB image type. * @author Marco Schmidt * @since 0.9.0 */ public interface RGBImage extends PixelImage, RGBIndex { } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/data/MemoryRGB48Image.java 0000664 0000000 0000000 00000001741 07741250133 024531 0 ustar /* * MemoryRGB48Image * * Copyright (c) 2003 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.data; import net.sourceforge.jiu.data.MemoryShortChannelImage; import net.sourceforge.jiu.data.RGB48Image; /** * A class to store 48 bit RGB truecolor images in memory. * @author Marco Schmidt * @since 0.12.0 * @see RGB24Image */ public class MemoryRGB48Image extends MemoryShortChannelImage implements RGB48Image { /** * Creates a new object of this class, with width and height as * specified by the arguments. * @param width the horizontal resolution of the new image in pixels * @param height the vertical resolution of the new image in pixels */ public MemoryRGB48Image(int width, int height) { super(3, width, height); } public PixelImage createCompatibleImage(int width, int height) { return new MemoryRGB48Image(width, height); } public Class getImageType() { return RGB48Image.class; } } java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/data/MemoryPaletted8Image.java 0000664 0000000 0000000 00000006254 07741250133 025601 0 ustar /* * Paletted8Image * * Copyright (c) 2000, 2001, 2002, 2003 Marco Schmidt. * All rights reserved. */ package net.sourceforge.jiu.data; import net.sourceforge.jiu.data.Palette; import net.sourceforge.jiu.data.PixelImage; /** * This class stores a paletted image with one byte per sample in memory. * * @author Marco Schmidt * @see net.sourceforge.jiu.data.ByteChannelImage * @see net.sourceforge.jiu.data.IntegerImage * @see net.sourceforge.jiu.data.Palette */ public class MemoryPaletted8Image extends MemoryByteChannelImage implements Paletted8Image { /** * This image's palette. */ private Palette palette; private int maxSampleValue; /** * Create an image of byte channels. * Image data will be completely in memory, so memory requirements are *
width * height * numChannels
bytes.
* Note that the data will not be initialized, so you should not assume
* anything about its content.
* @param width the horizontal resolution, must be non-zero and positive
* @param height the vertical resolution, must be non-zero and positive
* @throws IllegalArgumentException if any of the parameters are smaller than 1
*/
public MemoryPaletted8Image(int width, int height)
{
super(1, width, height);
palette = null;
maxSampleValue = 255;
}
public MemoryPaletted8Image(int width, int height, Palette palette)
{
this(width, height);
setPalette(palette);
}
public static void checkPalette(Palette palette)
{
if (palette == null)
{
throw new IllegalArgumentException("Palette must be non-null.");
}
else
{
int numEntries = palette.getNumEntries();
if (numEntries < 1 || numEntries > 256)
{
throw new IllegalArgumentException("Number of entries must " +
"be from 1..256 for a Paletted8Image; got: " + numEntries);
}
}
}
public PixelImage createCompatibleImage(int width, int height)
{
Palette newPalette = null;
Palette myPalette = getPalette();
if (myPalette != null)
{
newPalette = (Palette)myPalette.clone();
}
return new MemoryPaletted8Image(width, height, newPalette);
}
public long getAllocatedMemory()
{
long result = super.getAllocatedMemory();
Palette myPalette = getPalette();
if (myPalette != null)
{
result += myPalette.getAllocatedMemory();
}
return result;
}
public Class getImageType()
{
return Paletted8Image.class;
}
public int getMaxSample(int channel)
{
return maxSampleValue;
}
/**
* Returns this image's palette.
* @see #setPalette
*/
public Palette getPalette()
{
return palette;
}
public String getTypeDescription()
{
return "Paletted image, 8 bits per pixel";
}
/**
* Sets this image's palette to a new value.
* @see #getPalette
*/
public void setPalette(Palette palette)
{
if (palette != null && palette.getNumEntries() > 256)
{
throw new IllegalArgumentException("Cannot use palette with more " +
"than 256 entries in a Paletted8Image.");
}
this.palette = palette;
if (palette == null)
{
maxSampleValue = 255;
}
else
{
maxSampleValue = palette.getNumEntries() - 1;
}
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/data/RGBIntegerImage.java 0000664 0000000 0000000 00000001036 07741250133 024477 0 ustar /*
* RGBIntegerImage
*
* Copyright (c) 2002 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.data;
import net.sourceforge.jiu.data.IntegerImage;
import net.sourceforge.jiu.data.RGBImage;
/**
* An interface for RGB truecolor images that have integer samples.
* A combination of {@link net.sourceforge.jiu.data.IntegerImage} and
* {@link net.sourceforge.jiu.data.RGBImage}.
*
* @author Marco Schmidt
* @since 0.9.0
*/
public interface RGBIntegerImage extends IntegerImage, RGBImage
{
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/data/TransparencyInformation.java 0000664 0000000 0000000 00000003235 07741250133 026466 0 ustar /*
* TransparencyInformation
*
* Copyright (c) 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.data;
import net.sourceforge.jiu.data.IntegerImage;
/**
* An interface that represents transparency information which may be
* available for a pixel image.
* Transparency information describes how an image is supposed to be
* drawn on a pixel background (e.g. another image).
* That way, irregularly shaped images can easily be handled by excluding
* those pixels of a rectangular image that are not part of the image.
* @author Marco Schmidt
*/
public interface TransparencyInformation
{
/**
* Returns an image object that contains an alpha channel.
* The first channel of that image is supposed to be the alpha channel.
* @return the alpha channel image object
* @see #setAlphaChannelImage
*/
IntegerImage getAlphaChannelImage();
/**
* If there is a transparency index, this method returns it.
* Otherwise, the return value is undefined.
* @return transparency index
* @see #setTransparencyIndex
*/
Integer getTransparencyIndex();
/**
* Set a new alpha channel image object.
* @see #getAlphaChannelImage
*/
void setAlphaChannelImage(IntegerImage newImage);
/**
* Set a new transparency value.
* Can be null
.
* However, if the value is non-null, it must encapsulate an
* integer number which is 0 or larger.
* @param newValue new transparency index
* @see #getAlphaChannelImage
* @throws IllegalArgumentException if the argument is non-null and contains a negative value
*/
void setTransparencyIndex(Integer newValue);
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/data/RGB48Image.java 0000664 0000000 0000000 00000000764 07741250133 023344 0 ustar /*
* RGB48Image
*
* Copyright (c) 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.data;
import net.sourceforge.jiu.data.RGBIntegerImage;
import net.sourceforge.jiu.data.ShortChannelImage;
/**
* An empty interface for RGB truecolor images with integer samples
* that are each sixteen bits large (thus, 48 bits per pixel).
* @author Marco Schmidt
* @since 0.12.0
*/
public interface RGB48Image extends ShortChannelImage, RGBIntegerImage
{
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/data/PixelImage.java 0000664 0000000 0000000 00000006063 07741250133 023635 0 ustar /*
* PixelImage
*
* Copyright (c) 2000, 2001, 2002 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.data;
/**
* The base interface for all image data types in JIU.
* These image data classes and interfaces share the following properties:
* null
otherwise).
* This {@link java.lang.Class} object, if available for two image objects,
* can be used to find out if they are compatible.
* Example: {@link net.sourceforge.jiu.data.MemoryGray8Image} returns
* net.sourceforge.jiu.data.Gray8Image.class
.
*/
Class getImageType();
/**
* Returns the number of channels in this image.
* Must be one or larger.
* @return the number of channels
*/
int getNumChannels();
/**
* Returns the horizontal resolution of the image in pixels.
* Must be one or larger.
* @return width in pixels
*/
int getWidth();
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/data/ShortChannelImage.java 0000664 0000000 0000000 00000011757 07741250133 025152 0 ustar /*
* ShortChannelImage
*
* Copyright (c) 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.data;
/**
* An extension of the {@link IntegerImage} interface that restricts the image to
* short
samples.
* The minimum sample value for all channels is 0
,
* the maximum sample value 65535
(216 - 1).
* * Number of channels and resolution must be given to the constructor * and cannot be changed after creation. *
* Each channel of the image is made up of short
values.
* Note that shorts in Java are signed, they can take values from -32768
to 32767
.
* If you use {@link IntegerImage}'s getSample and putSample methods
* you don't have to deal with this, you always get int
samples
* that are in the 0 .. 65535 interval.
*
* To manually convert a Java short
value to an int
value
* in the range of 0 to 65535, do the following:
*
* short s = ...; // initialize short value * int i = s & 0xffff; * // i now is a value between 0 and 65535 ** @author Marco Schmidt * @since 0.11.0 */ public interface ShortChannelImage extends IntegerImage { /** * Sets all samples of the first channel to the argument short value. * Equal to
clear(0, newValue);
.
* @param newValue all samples in the first channel are set to this value
* @see #clear(int, short)
* @see #clear(int)
* @see #clear(int, int)
*/
void clear(short newValue);
/**
* Sets all samples of one channel to a new value.
* @param channelIndex zero-based index of the channel to be cleared (must be smaller than {@link #getNumChannels()}
* @param newValue all samples in the channel will be set to this value
*/
void clear(int channelIndex, short newValue);
/**
* Returns a single short sample from the first channel and the specified position.
* A call to this method is the same as getShortSample(0, x, y)
.
* @param x horizontal position of the sample to be returned (must be between 0
and {@link #getWidth()} - 1
* @param y vertical position of the sample to be returned (must be between 0
and {@link #getHeight()} - 1
* @return the requested short sample
*/
short getShortSample(int x, int y);
/**
* Returns a single short sample from the image.
* When possible, try copying several samples at a time for higher speed ({@link #getShortSamples}).
* @param channel the number of the channel of the sample; must be from 0
to {@link #getNumChannels()} - 1
* @param x the column of the sample to be returned; must be from 0
to {@link #getWidth()} - 1
* @param y the row of the sample; must be from 0
to {@link #getHeight()} - 1
* @return the sample, a single short value
* @throws IllegalArgumentException if the arguments hurt one of the preconditions above
* @see #getShortSamples
*/
short getShortSample(int channel, int x, int y);
/**
* Copies samples from this image to a short array.
* Copies num
samples in row y
of channel
* channel
, starting at horizontal offset x
.
* Data will be written to the dest
array, starting at
* offset destOffset
.
* Data will be copied from one row only, so a maximum of
* getWidth()
* samples can be copied with a call to this method.
*
* @param channelIndex the index of the channel to be copied from; must be
* from 0
to getNumChannels() - 1
* @param x the horizontal offset where copying will start; must be from
* 0
to getWidth() - 1
* @param y the row from which will be copied; must be from
* 0
to getHeight() - 1
* @param w number of columns to be copied
* @param h number of rows to be copied
* @param dest the array where the data will be copied to; must have a
* length of at least destOffset + num
* @param destOffset the offset into dest
where this method
* will start copying data
* @throws IllegalArgumentException if the arguments hurt one of the many
* preconditions above
*/
void getShortSamples(int channelIndex, int x, int y, int w, int h, short[] dest, int destOffset);
/**
* Sets one short sample in one channel to a new value.
*/
void putShortSample(int channel, int x, int y, short newValue);
/**
* Sets one short sample in the first channel (index 0
) to a new value.
* Result is equal to putShortSample(0, x, y, newValue);
.
*/
void putShortSample(int x, int y, short newValue);
/**
* Copies a number of samples from the argument array to this image.
*/
void putShortSamples(int channel, int x, int y, int w, int h, short[] src, int srcOffset);
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/data/MemoryShortChannelImage.java 0000664 0000000 0000000 00000021500 07741250133 026326 0 ustar /*
* MemoryShortChannelImage
*
* Copyright (c) 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.data;
/**
* An implementation of {@link ShortChannelImage} that stores image channels as
* short[]
arrays in memory.
* An image can have an arbitrary number of channels.
*
* This class is abstract because it is merely a data container.
* It takes a subclass like {@link MemoryGray16Image} to give meaning to the values.
*
* @author Marco Schmidt
* @since 0.11.0
*/
public abstract class MemoryShortChannelImage implements ShortChannelImage
{
private final short[][] data;
private final short[] firstChannel; // == data[0]
private final int numChannels; // == data.length
private final int width;
private final int height;
private final int numPixels; // == width * height
/**
* Create an image of short channels.
* Image data will be completely in memory, so memory requirements are
* width * height * numChannels * 2
bytes.
* @param numChannels the number of channels in this image, must be
* larger than zero
* @param width the horizontal resolution, must be larger than zero
* @param height the vertical resolution, must be larger than zero
*/
public MemoryShortChannelImage(int numChannels, int width, int height)
{
if (width < 1)
{
throw new IllegalArgumentException("Width must be larger than " +
"0: " + width);
}
if (height < 1)
{
throw new IllegalArgumentException("Height must be larger than" +
" 0: " + height);
}
if (numChannels < 1)
{
throw new IllegalArgumentException("Number of channels must be " +
"larger than 0: " + numChannels);
}
this.width = width;
this.height = height;
this.numChannels = numChannels;
numPixels = width * height;
data = new short[numChannels][];
for (int i = 0; i < numChannels; i++)
{
data[i] = new short[numPixels];
}
firstChannel = data[0];
}
/**
* Throws an exception if the arguments do not form a valid horizontal
* sequence of samples.
* To be valid, all of the following requirements must be met:
*/
protected void checkPositionAndNumber(int channel, int x, int y, int w, int h)
{
if (channel < 0 || channel >= numChannels)
{
throw new IllegalArgumentException("Illegal channel index value: " + channel +
". Must be from 0 to " + (numChannels - 1) + ".");
}
if (x < 0 || x >= getWidth())
{
throw new IllegalArgumentException("The value for x is invalid: " + x + ".");
}
if (w < 1)
{
throw new IllegalArgumentException("The value for w is invalid: " + w + ".");
}
if (x + w > getWidth())
{
throw new IllegalArgumentException("The values x + w exceed the " +
"width of this image; x=" + x + ", w=" + w + ", width=" +
getWidth());
}
if (h < 1)
{
throw new IllegalArgumentException("The value for h is invalid: " + h + ".");
}
if (y < 0 || y >= getHeight())
{
throw new IllegalArgumentException("The value for y is invalid: " + y + ".");
}
if (y + h > getHeight())
{
throw new IllegalArgumentException("The values y + h exceed the " +
"height of this image; y=" + y + ", h=" + h + ", height=" +
getHeight());
}
}
public void clear(short newValue)
{
clear(0, newValue);
}
public void clear(int channelIndex, short newValue)
{
// check the validity of the channel index
checkPositionAndNumber(channelIndex, 0, 0, 1, 1);
// get the correct channel as short[]
final short[] CHANNEL = data[channelIndex];
// fill channel with the argument value
final short VALUE = (short)newValue;
final int LENGTH = CHANNEL.length;
for (int i = 0; i < LENGTH; i++)
{
CHANNEL[i] = VALUE;
}
}
public void clear(int newValue)
{
clear(0, (short)newValue);
}
public void clear(int channelIndex, int newValue)
{
clear(channelIndex, (short)newValue);
}
public abstract PixelImage createCompatibleImage(int width, int height);
public PixelImage createCopy()
{
PixelImage copy = createCompatibleImage(getWidth(), getHeight());
MemoryShortChannelImage result = (MemoryShortChannelImage)copy;
for (int channelIndex = 0; channelIndex < getNumChannels(); channelIndex++)
{
System.arraycopy(data[channelIndex], 0, result.data[channelIndex], 0, data[channelIndex].length);
}
return result;
}
public long getAllocatedMemory()
{
long result = 0;
if (data != null)
{
int channelIndex = 0;
while (channelIndex < data.length)
{
short[] array = data[channelIndex++];
if (array != null)
{
result += array.length * 2;
}
}
}
return result;
}
public int getBitsPerPixel()
{
return numChannels * 16;
}
public short getShortSample(int channel, int x, int y)
{
/* advantage of the following approach: we don't check arguments
before we access the data (too costly); instead, we have the VM
throw an array index out of bounds exception and then determine
which of the arguments was wrong;
that's better than checking before access all of the time =>
the VM checks anyway
we then throw a meaningful IllegalArgumentException (in
checkPositionAndNumber)
disadvantage: some erroneous arguments aren't noticed, example:
width=100, height=20, x=100, y=0
will not result in an error (because only 0..99 are valid for x)
but in the return of sample(0/1)
*/
try
{
return data[channel][y * width + x];
}
catch (ArrayIndexOutOfBoundsException aioobe)
{
checkPositionAndNumber(channel, x, y, 1, 1);
return -1;
}
}
public short getShortSample(int x, int y)
{
return getShortSample(0, x, y);
}
public void getShortSamples(int channel, int x, int y, int w, int h, short[] dest, int destOffset)
{
checkPositionAndNumber(channel, x, y, w, h);
short[] src = data[channel];
try
{
int srcOffset = y * width + x;
while (h-- > 0)
{
java.lang.System.arraycopy(src, srcOffset, dest, destOffset, w);
srcOffset += width;
destOffset += w;
}
}
catch (ArrayIndexOutOfBoundsException aioobe)
{
}
}
public final int getHeight()
{
return height;
}
public int getMaxSample(int channel)
{
return 65535;
}
public int getNumChannels()
{
return numChannels;
}
public final int getSample(int x, int y)
{
try
{
return firstChannel[y * width + x] & 0xffff;
}
catch (ArrayIndexOutOfBoundsException aioobe)
{
checkPositionAndNumber(0, x, y, 1, 1);
return -1;
}
}
public final int getSample(int channel, int x, int y)
{
try
{
return data[channel][y * width + x] & 0xffff;
}
catch (ArrayIndexOutOfBoundsException aioobe)
{
checkPositionAndNumber(channel, x, y, 1, 1);
return -1;
}
}
public void getSamples(int channel, int x, int y, int w, int h, int[] dest, int destOffs)
{
if (w < 1 || h < 1)
{
return;
}
short[] src = data[channel];
int srcOffs = y * width + x;
while (h-- != 0)
{
int loop = w;
int from = srcOffs;
while (loop-- != 0)
{
dest[destOffs++] = src[from++] & 0xffff;
}
srcOffs += width;
}
}
public final int getWidth()
{
return width;
}
public final void putShortSample(int channel, int x, int y, short newValue)
{
checkPositionAndNumber(channel, x, y, 1, 1);
try
{
data[channel][y * width + x] = newValue;
}
catch (ArrayIndexOutOfBoundsException aioobe)
{
checkPositionAndNumber(channel, x, y, 1, 1);
}
}
public final void putShortSample(int x, int y, short newValue)
{
checkPositionAndNumber(0, x, y, 1, 1);
try
{
firstChannel[y * width + x] = newValue;
}
catch (ArrayIndexOutOfBoundsException aioobe)
{
checkPositionAndNumber(0, x, y, 1, 1);
}
}
public void putShortSamples(int channel, int x, int y, int w, int h, short[] src, int srcOffset)
{
checkPositionAndNumber(channel, x, y, w, h);
short[] dest = data[channel];
int destOffset = y * width + x;
while (h-- > 0)
{
java.lang.System.arraycopy(src, srcOffset, dest, destOffset, w);
srcOffset += w;
destOffset += width;
}
}
public void putSamples(int channel, int x, int y, int w, int h, int[] src, int srcOffs)
{
checkPositionAndNumber(channel, x, y, w, h);
short[] dest = data[channel];
int destOffs = y * width + x;
while (h-- != 0)
{
int loop = w;
int to = destOffs;
while (loop-- != 0)
{
dest[to++] = (short)src[srcOffs++];
}
destOffs += width;
}
}
public final void putSample(int x, int y, int newValue)
{
putShortSample(0, x, y, (short)newValue);
}
public final void putSample(int channel, int x, int y, int newValue)
{
putShortSample(channel, x, y, (short)newValue);
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/data/MemoryBilevelImage.java 0000664 0000000 0000000 00000020344 07741250133 025325 0 ustar /*
* MemoryBilevelImage
*
* Copyright (c) 2002 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.data;
import net.sourceforge.jiu.data.BilevelImage;
import net.sourceforge.jiu.util.ArrayConverter;
/**
* An implementation of the {@link BilevelImage} interface that stores image
* data in a byte
array in memory.
* An image of width
times height
pixels will require
* (width + 7) / 8 * height
bytes of memory.
* @author Marco Schmidt
*/
public class MemoryBilevelImage implements BilevelImage
{
private final int BYTES_PER_ROW;
private final byte[] data;
private final int HEIGHT;
private final int WIDTH;
/**
* Create a new MemoryBilevelImage object with the specified resolution.
* @param width the horizontal resolution of the new image, must be larger than zero
* @param height the vertical resolution of the new image, must be larger than zero
* @throws IllegalArgumentException if any of the two parameters is smaller than one
*/
public MemoryBilevelImage(int width, int height)
{
if (width < 1)
{
throw new IllegalArgumentException("Width must be larger than zero; got " + width);
}
if (height < 1)
{
throw new IllegalArgumentException("Height must be larger than zero; got " + height);
}
BYTES_PER_ROW = (width + 7) / 8;
WIDTH = width;
HEIGHT = height;
data = new byte[BYTES_PER_ROW * HEIGHT];
}
private void checkBitOffset(int bitOffset)
{
if (bitOffset < 0 || bitOffset > 7)
{
throw new IllegalArgumentException("A bit offset value must be from the interval 0..7.");
}
}
private void checkPositionAndNumber(int x, int y, int w, int h)
{
if (w < 0)
{
throw new IllegalArgumentException("Negative number of samples " +
"to be copied: " + w);
}
if (h < 0)
{
throw new IllegalArgumentException("Negative number of rows " +
"to be copied: " + h);
}
if (x < 0 || x >= getWidth())
{
throw new IllegalArgumentException("The value for x is invalid: " + x + ".");
}
if (y < 0 || y >= getHeight())
{
throw new IllegalArgumentException("The value for y is invalid: " + y + ".");
}
if (x + w > getWidth())
{
throw new IllegalArgumentException("Cannot copy " + w + " values starting at " +
"offset " + x + " (width is only " + getWidth() + ").");
}
if (y + h > getHeight())
{
throw new IllegalArgumentException("Cannot copy " + h + " rows starting at " +
y + " (height is only " + getHeight() + ").");
}
}
private void checkValue(int value)
{
if (value != WHITE && value != BLACK)
{
throw new IllegalArgumentException("Sample value must be either BilevelImage.BLACK or BilevelImage.WHITE.");
}
}
public void clear(int newValue)
{
clear(0, newValue);
}
public void clear(int channelIndex, int newValue)
{
if (channelIndex != 0)
{
throw new IllegalArgumentException("Invalid channel index; " +
"bilevel images have only one channel, so 0 is the only " +
"valid argument; got " + channelIndex);
}
checkValue(newValue);
byte value;
if (newValue == BLACK)
{
value = 0;
}
else
{
value = (byte)0xff;
}
for (int i = 0; i < data.length; i++)
{
data[i] = value;
}
}
public PixelImage createCompatibleImage(int width, int height)
{
return new MemoryBilevelImage(width, height);
}
public PixelImage createCopy()
{
PixelImage copy = createCompatibleImage(getWidth(), getHeight());
MemoryBilevelImage result = (MemoryBilevelImage)copy;
System.arraycopy(data, 0, result.data, 0, data.length);
return result;
}
public long getAllocatedMemory()
{
return data.length;
}
public int getBitsPerPixel()
{
return 1;
}
public int getHeight()
{
return HEIGHT;
}
public Class getImageType()
{
return BilevelImage.class;
}
public int getMaxSample(int channelIndex)
{
return 1;
}
public int getNumChannels()
{
return 1;
}
public void getPackedBytes(int x, int y, int numSamples, byte[] dest, int destOffset, int destBitOffset)
{
checkPositionAndNumber(x, y, numSamples, 1);
checkBitOffset(destBitOffset);
int srcOffset = y * BYTES_PER_ROW + (x >> 3);
int srcBitOffset = x & 7;
ArrayConverter.copyPackedBytes(data, srcOffset, srcBitOffset, dest, destOffset, destBitOffset, numSamples);
}
public int getSample(int x, int y)
{
if (isBlack(x, y))
{
return BLACK;
}
else
{
return WHITE;
}
}
public int getSample(int channelIndex, int x, int y)
{
if (channelIndex == 0)
{
if (isBlack(x, y))
{
return BLACK;
}
else
{
return WHITE;
}
}
else
{
throw new IllegalArgumentException("The channelIndex argument must be 0 for bilevel images; got " + channelIndex);
}
}
public void getSamples(int channelIndex, int x, int y, int w, int h, int[] dest, int destOffset)
{
final int INITIAL_MASK = 1 << (7 - (x % 8));
int offset = y * BYTES_PER_ROW + x / 8;
while (h-- > 0)
{
int mask = INITIAL_MASK;
int srcOffset = offset;
int remainingColumns = w;
int srcValue = data[srcOffset++] & 0xff;
while (remainingColumns-- != 0)
{
if ((srcValue & mask) == 0)
{
dest[destOffset++] = BLACK;
}
else
{
dest[destOffset++] = WHITE;
}
if (mask == 1)
{
mask = 128;
srcValue = data[srcOffset++] & 0xff;
}
else
{
mask >>= 1;
}
}
offset += BYTES_PER_ROW;
}
}
public int getWidth()
{
return WIDTH;
}
public boolean isBlack(int x, int y)
{
try
{
int offset = y * BYTES_PER_ROW + (x >> 3);
return (data[offset] & (byte)(1 << (7 - (x & 7)))) == 0;
}
catch (ArrayIndexOutOfBoundsException aioobe)
{
checkPositionAndNumber(x, y, 1, 1);
}
return true;
}
public boolean isWhite(int x, int y)
{
try
{
int offset = y * BYTES_PER_ROW + (x >> 3);
return (data[offset] & (byte)(1 << (7 - (x & 7)))) != 0;
}
catch (ArrayIndexOutOfBoundsException aioobe)
{
checkPositionAndNumber(x, y, 1, 1);
}
return true;
}
public void putBlack(int x, int y)
{
try
{
int offset = y * BYTES_PER_ROW + (x >> 3);
data[offset] &= (byte)(255 - (1 << (7 - (x & 7))));
}
catch (ArrayIndexOutOfBoundsException aioobe)
{
checkPositionAndNumber(x, y, 1, 1);
}
}
public void putPackedBytes(int x, int y, int numSamples, byte[] src, int srcOffset, int srcBitOffset)
{
checkPositionAndNumber(x, y, numSamples, 1);
checkBitOffset(srcBitOffset);
int destOffset = y * BYTES_PER_ROW + (x >> 3);
int destBitOffset = x & 7;
ArrayConverter.copyPackedBytes(src, srcOffset, srcBitOffset, data, destOffset, destBitOffset, numSamples);
}
public void putSample(int x, int y, int newValue)
{
putSample(0, x, y, newValue);
}
public void putSample(int channelIndex, int x, int y, int newValue)
{
checkValue(newValue);
try
{
int offset = y * BYTES_PER_ROW + (x >> 3);
if (newValue == BLACK)
{
data[offset] &= (byte)(255 - (1 << (7 - (x & 7))));
}
else
{
data[offset] |= (byte)(1 << (7 - (x & 7)));
}
}
catch (ArrayIndexOutOfBoundsException aioobe)
{
checkPositionAndNumber(x, y, 1, 1);
}
}
public void putSamples(int channelIndex, int x, int y, int w, int h, int[] src, int srcOffset)
{
checkPositionAndNumber(x, y, w, h);
int INITIAL_ROW_MASK = 1 << (7 - (x & 7));
int initialDestOffset = y * BYTES_PER_ROW + (x >> 3);
while (h-- > 0)
{
int mask = INITIAL_ROW_MASK;
int destOffset = initialDestOffset;
int pixelsLeft = w;
while (pixelsLeft-- > 0)
{
if (src[srcOffset++] == BLACK)
{
data[destOffset] &= (byte)(255 - mask);
}
else
{
data[destOffset] |= (byte)mask;
}
if (mask == 1)
{
mask = 128;
destOffset++;
}
}
initialDestOffset += BYTES_PER_ROW;
}
}
public void putWhite(int x, int y)
{
try
{
int offset = y * BYTES_PER_ROW + (x >> 3);
data[offset] |= (byte)(1 << (7 - (x & 7)));
}
catch (ArrayIndexOutOfBoundsException aioobe)
{
checkPositionAndNumber(x, y, 1, 1);
}
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/data/Gray8Image.java 0000664 0000000 0000000 00000001421 07741250133 023537 0 ustar /*
* Gray8Image
*
* Copyright (c) 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.data;
import net.sourceforge.jiu.data.ByteChannelImage;
import net.sourceforge.jiu.data.GrayIntegerImage;
/**
* Interface for grayscale images using integer samples that are eight bits large.
* Valid sample values must lie in the interval 0 to 255 (including both of those values).
* Like all grayscale images, implementations of this class are supposed to have one channel only.
* Simply merges the two interfaces GrayIntegerImage and ByteChannelImage without adding new methods.
* @author Marco Schmidt
* @see ByteChannelImage
* @see GrayIntegerImage
*/
public interface Gray8Image extends GrayIntegerImage, ByteChannelImage
{
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/data/MemoryByteChannelImage.java 0000664 0000000 0000000 00000022126 07741250133 026137 0 ustar /*
* MemoryByteChannelImage
*
* Copyright (c) 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.data;
/**
* An implementation of {@link ByteChannelImage} that stores image channels as
* byte[]
arrays in memory.
* An image can have an arbitrary number of channels.
*
* This class is abstract because it is merely a data container.
* It takes a subclass like {@link MemoryGray8Image} to give meaning to the values.
*
* @author Marco Schmidt
*/
public abstract class MemoryByteChannelImage implements ByteChannelImage
{
private final byte[][] data;
private final byte[] firstChannel; // == data[0]
private final int numChannels; // == data.length
private final int width;
private final int height;
private final int numPixels; // == width * height
/**
* Create an image of byte channels.
* Image data will be completely in memory, so memory requirements are
* width * height * numChannels
bytes.
* Note that the data will not be initialized, so you should not assume
* anything about its content.
*
* @param numChannels the number of channels in this image, must be
* non-zero and positive
* @param width the horizontal resolution, must be non-zero and positive
* @param height the vertical resolution, must be non-zero and positive
* @throws IllegalArgumentException if any of the parameters are invalid
* or if width times height exceeds two GB
* @throws OutOfMemoryException if there is not enough free memory for
* the specified resolution
*/
public MemoryByteChannelImage(int numChannels, int width, int height)
{
if (width < 1)
{
throw new IllegalArgumentException("Width must be larger than " +
"0: " + width);
}
if (height < 1)
{
throw new IllegalArgumentException("Height must be larger than" +
" 0: " + height);
}
if (numChannels < 1)
{
throw new IllegalArgumentException("Number of channels must be " +
"larger than 0: " + numChannels);
}
this.width = width;
this.height = height;
this.numChannels = numChannels;
numPixels = width * height;
data = new byte[numChannels][];
for (int i = 0; i < numChannels; i++)
{
data[i] = new byte[numPixels];
}
firstChannel = data[0];
}
/**
* Throws an exception if the arguments do not form a valid horizontal
* sequence of samples.
* To be valid, all of the following requirements must be met:
*/
protected void checkPositionAndNumber(int channel, int x, int y, int w, int h)
{
if (channel < 0 || channel >= numChannels)
{
throw new IllegalArgumentException("Illegal channel index value: " + channel +
". Must be from 0 to " + (numChannels - 1) + ".");
}
if (x < 0 || x >= getWidth())
{
throw new IllegalArgumentException("The value for x is invalid: " + x + ".");
}
if (w < 1)
{
throw new IllegalArgumentException("The value for w is invalid: " + w + ".");
}
if (x + w > getWidth())
{
throw new IllegalArgumentException("The values x + w exceed the " +
"width of this image; x=" + x + ", w=" + w + ", width=" +
getWidth());
}
if (h < 1)
{
throw new IllegalArgumentException("The value for h is invalid: " + h + ".");
}
if (y < 0 || y >= getHeight())
{
throw new IllegalArgumentException("The value for y is invalid: " + y + ".");
}
if (y + h > getHeight())
{
throw new IllegalArgumentException("The values y + h exceed the " +
"height of this image; y=" + y + ", h=" + h + ", height=" +
getHeight());
}
}
public void clear(byte newValue)
{
clear(0, newValue);
}
public void clear(int channelIndex, byte newValue)
{
// check the validity of the channel index
checkPositionAndNumber(channelIndex, 0, 0, 1, 1);
// get the correct channel as byte[]
final byte[] CHANNEL = data[channelIndex];
// fill channel with the argument value
final byte VALUE = (byte)newValue;
final int LENGTH = CHANNEL.length;
for (int i = 0; i < LENGTH; i++)
{
CHANNEL[i] = VALUE;
}
}
public void clear(int newValue)
{
clear(0, (byte)newValue);
}
public void clear(int channelIndex, int newValue)
{
clear(channelIndex, (byte)newValue);
}
public abstract PixelImage createCompatibleImage(int width, int height);
public PixelImage createCopy()
{
PixelImage copy = createCompatibleImage(getWidth(), getHeight());
MemoryByteChannelImage result = (MemoryByteChannelImage)copy;
for (int channelIndex = 0; channelIndex < getNumChannels(); channelIndex++)
{
System.arraycopy(data[channelIndex], 0, result.data[channelIndex], 0, data[channelIndex].length);
}
return result;
}
public long getAllocatedMemory()
{
long result = 0;
if (data != null)
{
int channelIndex = 0;
while (channelIndex < data.length)
{
byte[] array = data[channelIndex++];
if (array != null)
{
result += array.length;
}
}
}
return result;
}
public int getBitsPerPixel()
{
return numChannels * 8;
}
public byte getByteSample(int channel, int x, int y)
{
/* advantage of the following approach: we don't check arguments
before we access the data (too costly); instead, we have the VM
throw an array index out of bounds exception and then determine
which of the arguments was wrong;
that's better than checking before access all of the time =>
the VM checks anyway
we then throw a meaningful IllegalArgumentException (in
checkPositionAndNumber)
disadvantage: some erroneous arguments aren't noticed, example:
width=100, height=20, x=100, y=0
will not result in an error (because only 0..99 are valid for x)
but in the return of sample(0/1)
*/
try
{
return data[channel][y * width + x];
}
catch (ArrayIndexOutOfBoundsException aioobe)
{
checkPositionAndNumber(channel, x, y, 1, 1);
return -1;
}
}
public byte getByteSample(int x, int y)
{
return getByteSample(0, x, y);
}
public void getByteSamples(int channel, int x, int y, int w, int h, byte[] dest, int destOffset)
{
checkPositionAndNumber(channel, x, y, w, h);
byte[] src = data[channel];
try
{
int srcOffset = y * width + x;
while (h-- > 0)
{
java.lang.System.arraycopy(src, srcOffset, dest, destOffset, w);
srcOffset += width;
destOffset += w;
}
}
catch (ArrayIndexOutOfBoundsException aioobe)
{
}
}
public final int getHeight()
{
return height;
}
public int getMaxSample(int channel)
{
return 255;
}
public int getNumChannels()
{
return numChannels;
}
public final int getSample(int x, int y)
{
try
{
return firstChannel[y * width + x] & 0xff;
}
catch (ArrayIndexOutOfBoundsException aioobe)
{
checkPositionAndNumber(0, x, y, 1, 1);
return -1;
}
}
public final int getSample(int channel, int x, int y)
{
try
{
return data[channel][y * width + x] & 0xff;
}
catch (ArrayIndexOutOfBoundsException aioobe)
{
checkPositionAndNumber(channel, x, y, 1, 1);
return -1;
}
}
public void getSamples(int channel, int x, int y, int w, int h, int[] dest, int destOffs)
{
if (w < 1 || h < 1)
{
return;
}
byte[] src = data[channel];
int srcOffs = y * width + x;
while (h-- != 0)
{
int loop = w;
int from = srcOffs;
while (loop-- != 0)
{
dest[destOffs++] = src[from++] & 0xff;
}
srcOffs += width;
}
}
public final int getWidth()
{
return width;
}
public final void putByteSample(int channel, int x, int y, byte newValue)
{
checkPositionAndNumber(channel, x, y, 1, 1);
try
{
data[channel][y * width + x] = newValue;
}
catch (ArrayIndexOutOfBoundsException aioobe)
{
checkPositionAndNumber(channel, x, y, 1, 1);
}
}
public final void putByteSample(int x, int y, byte newValue)
{
checkPositionAndNumber(0, x, y, 1, 1);
try
{
firstChannel[y * width + x] = newValue;
}
catch (ArrayIndexOutOfBoundsException aioobe)
{
checkPositionAndNumber(0, x, y, 1, 1);
}
}
public void putByteSamples(int channel, int x, int y, int w, int h, byte[] src, int srcOffset)
{
checkPositionAndNumber(channel, x, y, w, h);
byte[] dest = data[channel];
int destOffset = y * width + x;
while (h-- > 0)
{
java.lang.System.arraycopy(src, srcOffset, dest, destOffset, w);
srcOffset += w;
destOffset += width;
}
}
public void putSamples(int channel, int x, int y, int w, int h, int[] src, int srcOffs)
{
checkPositionAndNumber(channel, x, y, w, h);
byte[] dest = data[channel];
int destOffs = y * width + x;
while (h-- != 0)
{
int loop = w;
int to = destOffs;
while (loop-- != 0)
{
dest[to++] = (byte)src[srcOffs++];
}
destOffs += width;
}
}
public final void putSample(int x, int y, int newValue)
{
putByteSample(0, x, y, (byte)newValue);
}
public final void putSample(int channel, int x, int y, int newValue)
{
putByteSample(channel, x, y, (byte)newValue);
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/data/BilevelImage.java 0000664 0000000 0000000 00000010627 07741250133 024137 0 ustar /*
* BilevelImage
*
* Copyright (c) 2000, 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.data;
import net.sourceforge.jiu.data.GrayIntegerImage;
/**
* An interface for bilevel pixel image data classes.
* Each pixel in a bilevel image can have two possible values, {@link #BLACK} and {@link #WHITE}.
* Those two constants are guaranteed to be 0
and 1
, although
* you should not make any assumptions about what value any of the two constants has.
* This is the type of image used for faxes.
* Black and white photos are usually stored as grayscale images.
*
* Apart from implementing {@link PixelImage} - like all image data classes in JIU - * this interface is also an {@link IntegerImage} (each sample is either 0 or 1) and * a {@link GrayImage} (black and white are both grayscale values). * The combination of {@link IntegerImage} and {@link GrayImage} is {@link GrayIntegerImage}, * which is the direct superinterface of this interface. * *
byte
value that stores eight horizontally neighbored bilevel
* pixels in it (pixel and sample can be used interchangeably in the context of bilevel images
* because there is only one sample per pixel).
* The most significant bit of such a packed bit is defined to be the leftmost of the
* eight pixels, the second-most significant bit is the pixel to the right of that leftmost pixel,
* and so on. The least significant bit is the rightmost pixel.
* If a bit is set, the corresponing pixel value is supposed to be white, otherwise black.
*
* * BilevelImage image = new MemoryBilevelImage(2000, 500); * // now set all pixels in the first row to white * for (int x = 0; x < image.getWidth(); x++) * { * image.putWhite(x, 0); * } * // put vertical stripes on the rest * for (int y = 1; y < image.getHeight(); y++) * { * for (int x = 0; x < image.getWidth(); x++) * { * int sample; * if ((x % 2) == 0) * { * sample = BilevelImage.BLACK; * } * else * { * sample = BilevelImage.WHITE; * } * image.putSample(x, y, sample); * } * } ** * @author Marco Schmidt */ public interface BilevelImage extends GrayIntegerImage { /** * The value for a black pixel. * To be used with all methods that require
int
arguments for sample values.
* You can rely on this value being either 0 or 1 (that way you can safely store it
* in a byte or short).
*/
int BLACK = 0;
/**
* The value for a white pixel.
* To be used with all methods that require int
arguments for sample values.
* You can rely on this value being either 0 or 1 (that way you can safely store it
* in a byte or short).
*/
int WHITE = 1;
/**
* Sets a number of samples in the argument array from this image.
* @param x horizontal position of first sample of this image to read
* @param y vertical position of samples to be read from this image
* @param numSamples number of samples to be set
* @param dest array with packed pixels to which samples are copied
* @param destOffset index into dest array of the first byte value to write sample values to
* @param destBitOffset index of first bit of dest[destOffset]
to write a sample to (0 is leftmost, 1 is second-leftmost up to 7, which is the rightmost)
*/
void getPackedBytes(int x, int y, int numSamples, byte[] dest, int destOffset, int destBitOffset);
/**
* Sets a number of samples in the image from the argument array data.
* @param x horizontal position of first sample to be set
* @param y vertical position of samples to be set
* @param numSamples number of samples to be set
* @param src array with packed pixels to be set
* @param srcOffset index into src array of the first byte value to read sample values from
* @param srcBitOffset index of first bit of src[srcOffset]
to
* read a sample from (0 is leftmost, 1 is second-leftmost up to 7, which is the rightmost)
*/
void putPackedBytes(int x, int y, int numSamples, byte[] src, int srcOffset, int srcBitOffset);
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/data/Palette.java 0000664 0000000 0000000 00000015075 07741250133 023212 0 ustar /*
* Palette
*
* Copyright (c) 2000, 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.data;
import net.sourceforge.jiu.data.RGBIndex;
/**
* This class represents a palette, a list of RGB colors.
* An RGB color here has three int values for its red, green and blue
* intensity.
* Each intensity value must be larger than or equal to zero and
* smaller than or equal to the maximum intensity value that can be
* given to the constructor {@link #Palette(int, int)}.
* This maximum value is typically 255.
* Note that the number of entries in a palette is restricted only
* by the element index type int
so that palettes with
* more than 256 entries are no problem.
* When accessing (reading or writing) samples of this palette, use
* the constants {@link #INDEX_RED}, {@link #INDEX_GREEN} and {@link #INDEX_BLUE} of
* this class to define a color channel.
* @author Marco Schmidt
* @see net.sourceforge.jiu.data.PalettedImage
*/
public class Palette implements RGBIndex
{
private int[][] data;
private int numEntries;
private int maxValue;
/**
* Create a palette with the given number of entries and a maximum value
* for each sample.
* @param numEntries the number of entries to be accessible in this palette
* @param maxValue the maximum value to be allowed for each sample
*/
public Palette(int numEntries, int maxValue)
{
if (numEntries < 1)
{
throw new IllegalArgumentException("Error -- numEntries must be larger than 0.");
}
this.numEntries = numEntries;
this.maxValue = maxValue;
data = new int[3][];
for (int i = 0; i < 3; i++)
{
data[i] = new int[numEntries];
}
}
/**
* Create a palette with the given number of entries and a maximum value
* of 255
.
* @param numEntries the number of entries to be accessible in this palette
*/
public Palette(int numEntries)
{
this(numEntries, 255);
}
/**
* Creates a copy of this palette, allocating a new Palette object
* and copying each RGB triplet to the new palette.
* Then returns the new palette.
* Thus, a "deep" copy of this Palette object is created,
* not a "shallow" one.
*
* @return newly-created palette
*/
public Object clone()
{
Palette result = new Palette(getNumEntries(), getMaxValue());
for (int i = 0; i < getNumEntries(); i++)
{
result.putSample(INDEX_RED, i, getSample(INDEX_RED, i));
result.putSample(INDEX_GREEN, i, getSample(INDEX_GREEN, i));
result.putSample(INDEX_BLUE, i, getSample(INDEX_BLUE, i));
}
return result;
}
/**
* Returns the amount of memory in bytes allocated for this palette.
*
*/
public long getAllocatedMemory()
{
long result = 0;
if (data != null)
{
for (int i = 0; i < data.length; i++)
{
if (data[i] != null)
{
result += data[i].length;
}
}
}
return result;
}
/**
* Returns the maximum value allowed for a sample.
* @return the maximum sample value
*/
public int getMaxValue()
{
return maxValue;
}
/**
* Returns the number of entries in this palette.
* @return the number of entries in this palette
*/
public int getNumEntries()
{
return numEntries;
}
/**
* Returns one of the samples of this palette.
* @param entryIndex the index of the color to be addressed, must be from
* 0
to getNumEntries() - 1
* @param channelIndex one of the three channels; must be {@link #INDEX_RED},
* {@link #INDEX_GREEN} or {@link #INDEX_BLUE}
* @return the requested sample
*/
public int getSample(int channelIndex, int entryIndex)
{
try
{
return data[channelIndex][entryIndex];
}
catch (ArrayIndexOutOfBoundsException aioobe)
{
throw new IllegalArgumentException("Entry must be from 0 to " + (numEntries - 1) +
", channel from 0 to 2.");
}
}
/**
* Returns all samples of one channel as an int array.
* @param channelIndex index of the channel, one of the {@link RGBIndex} constants
* @return array with samples
*/
public int[] getSamples(int channelIndex)
{
if (channelIndex < 0 || channelIndex > 2)
{
throw new IllegalArgumentException("Invalid channel index, must be from 0 to 2.");
}
int[] result = new int[data[channelIndex].length];
System.arraycopy(data[channelIndex], 0, result, 0, result.length);
return result;
}
/**
* Checks if all entries of this palette are either black or white.
* An entry is black if all three intensitites (red, green and blue) are
* 0
, it is white if they are all equal to
* {@link #getMaxValue()}.
* No particular order of entries (e.g. first color black, second white)
* is demanded and no specific number of entries (e.g. 2).
* This means that a palette is black and white if it contains ten entries
* that are all black.
*
* @return if the palette contains only the colors black and white
*/
public boolean isBlackAndWhite()
{
int i = 0;
while (i < numEntries)
{
if (data[INDEX_RED][i] != data[INDEX_GREEN][i] ||
data[INDEX_GREEN][i] != data[INDEX_BLUE][i] ||
(data[INDEX_BLUE][i] != 0 && data[INDEX_BLUE][i] != maxValue))
{
return false;
}
i++;
}
return true;
}
/**
* Checks if this palette is gray, i.e., checks if all entries are
* gray. This is the case if for all entries red, green and blue
* have the same intensity.
* @return if the palette contains only shades of gray
*/
public boolean isGray()
{
int i = 0;
while (i < numEntries)
{
if (data[INDEX_RED][i] != data[INDEX_GREEN][i] ||
data[INDEX_GREEN][i] != data[INDEX_BLUE][i])
{
return false;
}
i++;
}
return true;
}
public void put(int entryIndex, int red, int green, int blue)
{
putSample(INDEX_RED, entryIndex, red);
putSample(INDEX_GREEN, entryIndex, green);
putSample(INDEX_BLUE, entryIndex, blue);
}
/**
* Sets one sample of one color entry in the palette to a new value.
* @param channelIndex
*/
public void putSample(int channelIndex, int entryIndex, int newValue)
{
if (newValue < 0 || newValue > maxValue)
{
throw new IllegalArgumentException("Value must be from 0 to " +
maxValue + "; argument is " + newValue + ".");
}
try
{
data[channelIndex][entryIndex] = newValue;
}
catch (ArrayIndexOutOfBoundsException aioobe)
{
throw new IllegalArgumentException("Entry must be from 0 to " + (numEntries - 1) +
", channel from 0 to 2.");
}
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/data/Paletted8Image.java 0000664 0000000 0000000 00000001115 07741250133 024377 0 ustar /*
* Paletted8Image
*
* Copyright (c) 2000, 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.data;
import net.sourceforge.jiu.data.ByteChannelImage;
import net.sourceforge.jiu.data.PalettedIntegerImage;
/**
* An interface for classes that store paletted images with
* eight bit integers for each pixel.
* @author Marco Schmidt
* @see net.sourceforge.jiu.data.ByteChannelImage
* @see net.sourceforge.jiu.data.PalettedIntegerImage
*/
public interface Paletted8Image extends ByteChannelImage, PalettedIntegerImage
{
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/data/RGBIndex.java 0000664 0000000 0000000 00000001414 07741250133 023206 0 ustar /*
* RGBIndex
*
* Copyright (c) 2000, 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.data;
/**
* This interface provides three int
constants as index
* values for the three channels of an RGB image: red, green and blue.
* The three values are guaranteed to lie in the interval 0 to 2.
* Furthermore, all three values are different from each other, so
* that the complete interval from 0 to 2 is used.
* @author Marco Schmidt
*/
public interface RGBIndex
{
/**
* The index value for the red channel.
*/
int INDEX_RED = 0;
/**
* The index value for the green channel.
*/
int INDEX_GREEN = 1;
/**
* The index value for the blue channel.
*/
int INDEX_BLUE = 2;
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/data/GrayIntegerImage.java 0000664 0000000 0000000 00000001156 07741250133 024772 0 ustar /*
* GrayIntegerImage
*
* Copyright (c) 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.data;
/**
* An empty interface for grayscale images which have integer values
* of up to 32 bits (int
or smaller) as samples.
* An interface composed of {@link GrayImage} and {@link IntegerImage}.
*
* Like all extensions of {@link GrayImage}, this image data class supports
* only one channel.
* @author Marco Schmidt
* @since 0.9.0
* @see GrayImage
* @see IntegerImage
*/
public interface GrayIntegerImage extends GrayImage, IntegerImage
{
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/data/PalettedIntegerImage.java 0000664 0000000 0000000 00000000716 07741250133 025633 0 ustar /*
* PalettedIntegerImage
*
* Copyright (c) 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.data;
import net.sourceforge.jiu.data.IntegerImage;
import net.sourceforge.jiu.data.PalettedImage;
/**
* An empty interface for a paletted image type that uses
* integer values as samples.
* @author Marco Schmidt
* @since 0.11.0
*/
public interface PalettedIntegerImage extends PalettedImage, IntegerImage
{
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/data/ByteChannelImage.java 0000664 0000000 0000000 00000011652 07741250133 024750 0 ustar /*
* ByteChannelImage
*
* Copyright (c) 2000, 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.data;
/**
* An extension of the {@link IntegerImage} interface that restricts the image to
* byte samples.
* The minimum sample value for all channels is 0
,
* the maximum sample value 255
.
*
* Number of channels and resolution must be given to the constructor * and cannot be changed after creation. *
* Each channel of the image is made up of byte
values.
* Note that bytes in Java are signed, they can take values from -128
to 127
.
* If you use {@link IntegerImage}'s getSample and putSample methods
* you don't have to deal with this, you always get int
samples
* that are in the 0 .. 255 interval.
*
* To manually convert a Java byte
value to an int
value
* in the range of 0 to 255, do the following:
*
* byte b = ...; // initialize byte value * int i = b & 0xff; * // i now is a value between 0 and 255 ** @author Marco Schmidt */ public interface ByteChannelImage extends IntegerImage { /** * Sets all samples of the first channel to the argument byte value. * Equal to
clear(0, newValue);
.
* @param newValue all samples in the first channel are set to this value
* @see #clear(int, byte)
* @see #clear(int)
* @see #clear(int, int)
*/
void clear(byte newValue);
/**
* Sets all samples of one channel to a new value.
* @param channelIndex zero-based index of the channel to be cleared (must be smaller than {@link #getNumChannels()}
* @param newValue all samples in the channel will be set to this value
*/
void clear(int channelIndex, byte newValue);
/**
* Returns a single byte sample from the first channel and the specified position.
* A call to this method is the same as getByteSample(0, x, y)
.
* @param x horizontal position of the sample to be returned (must be between 0
and {@link #getWidth()} - 1
* @param y vertical position of the sample to be returned (must be between 0
and {@link #getHeight()} - 1
* @return the requested byte sample
*/
byte getByteSample(int x, int y);
/**
* Returns a single byte sample from the image.
* When possible, try copying several samples at a time for
* higher speed ({@link #getByteSamples}).
* @param channel the number of the channel of the sample; must be from 0
to {@link #getNumChannels()} - 1
* @param x the column of the sample to be returned; must be from 0
to {@link #getWidth()} - 1
* @param y the row of the sample; must be from 0
to {@link #getHeight()} - 1
* @return the sample, a single byte value
* @throws IllegalArgumentException if the arguments hurt one of the preconditions above
* @see #getByteSamples
*/
byte getByteSample(int channel, int x, int y);
/**
* Copies samples from this image to a byte array.
* Copies num
samples in row y
of channel
* channel
, starting at horizontal offset x
.
* Data will be written to the dest
array, starting at
* offset destOffset
.
* Data will be copied from one row only, so a maximum of
* getWidth()
* samples can be copied with a call to this method.
*
* @param channelIndex the index of the channel to be copied from; must be
* from 0
to getNumChannels() - 1
* @param x the horizontal offset where copying will start; must be from
* 0
to getWidth() - 1
* @param y the row from which will be copied; must be from
* 0
to getHeight() - 1
* @param w the number of columns to be copied
* @param h the number of rows to be copied
* @param dest the array where the data will be copied to; must have a
* length of at least destOffset + num
* @param destOffset the offset into dest
where this method
* will start copying data
* @throws IllegalArgumentException if the arguments hurt one of the many
* preconditions above
*/
void getByteSamples(int channelIndex, int x, int y, int w, int h, byte[] dest, int destOffset);
/**
* Sets one byte sample in one channel to a new value.
*/
void putByteSample(int channel, int x, int y, byte newValue);
/**
* Sets one byte sample in the first channel (index 0
) to a new value.
* Result is equal to putByteSample(0, x, y, newValue);
.
*/
void putByteSample(int x, int y, byte newValue);
/**
* Copies a number of samples from the argument array to this image.
*/
void putByteSamples(int channel, int x, int y, int w, int h, byte[] src, int srcOffset);
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/data/MemoryGray8Image.java 0000664 0000000 0000000 00000003136 07741250133 024735 0 ustar /*
* MemoryGray8Image
*
* Copyright (c) 2002 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.data;
import net.sourceforge.jiu.data.Gray8Image;
import net.sourceforge.jiu.data.MemoryByteChannelImage;
import net.sourceforge.jiu.data.PixelImage;
/**
* An implementation of {@link Gray8Image} that keeps the complete image in memory.
* This class inherits most of its functionality from its parent class
* {@link MemoryByteChannelImage}, using one byte channel.
*
* @author Marco Schmidt
*/
public class MemoryGray8Image extends MemoryByteChannelImage implements Gray8Image
{
/**
* Creates a new MemoryGray8Image object with the specified resolution.
* Simply gives 1
(for one channel) and the two resolution arguments
* to the super constructor (of the parent class {@link MemoryByteChannelImage}).
* @param width the horizontal resolution, must be non-zero and positive
* @param height the vertical resolution, must be non-zero and positive
*/
public MemoryGray8Image(int width, int height)
{
super(1, width, height);
}
public PixelImage createCompatibleImage(int width, int height)
{
return new MemoryGray8Image(width, height);
}
public Class getImageType()
{
return Gray8Image.class;
}
public boolean isBlack(int x, int y)
{
return getByteSample(x, y) == 0;
}
public boolean isWhite(int x, int y)
{
return getByteSample(x, y) == (byte)255;
}
public void putBlack(int x, int y)
{
putSample(x, y, 0);
}
public void putWhite(int x, int y)
{
putSample(x, y, 255);
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/data/package.html 0000664 0000000 0000000 00000003162 07741250133 023224 0 ustar
Provides classes to store images and data directly related to them.
The base interface for image data in JIU is {@link net.sourceforge.jiu.data.PixelImage}. The concept of a pixel image includes the following properties:
The interface {@link net.sourceforge.jiu.data.IntegerImage} extends the
{@link net.sourceforge.jiu.data.PixelImage} interface.
All sample values belonging to an object of a class implementing IntegerImage
are supposed to be integer values that can be stored in an int
value (a signed 32 bit value).
int
values.
* Image types based on byte
, char
, short
and int
will work with this interface.
* long
will not.
*
* Using this interface provides a nice way of accessing a large variety of
* image types, but for performance reasons it might be preferable to use
* one of the class-specific access methods that get or put several values
* at a time, e.g. getByteSamples in {@link ByteChannelImage}.
*
* @author Marco Schmidt
*/
public interface IntegerImage extends PixelImage
{
/**
* Sets all samples in the first channel to the argument value.
* Equal to
* The Graphics Gems Repository can be found at
* http://www.acm.org/tog/GraphicsGems/.
* It also includes information on the books and how to order them.
*
* @author Marco Schmidt
*/
public class Resample extends ImageToImageOperation
{
/**
* Constant for the Box filter (also known as Nearest Neighbor filter).
*/
public static final int FILTER_TYPE_BOX = 0;
/**
* Constant for the Triangle filter (also known as Linear filter or Bilinear filter).
*/
public static final int FILTER_TYPE_TRIANGLE = 1;
/**
* Constant for the Hermite filter.
*/
public static final int FILTER_TYPE_HERMITE = 2;
/**
* Constant for the Bell filter.
*/
public static final int FILTER_TYPE_BELL = 3;
/**
* Constant for the B-Spline filter.
*/
public static final int FILTER_TYPE_B_SPLINE = 4;
/**
* Constant for the Lanczos3 filter.
*/
public static final int FILTER_TYPE_LANCZOS3 = 5;
/**
* Constant for the Mitchell filter.
*/
public static final int FILTER_TYPE_MITCHELL = 6;
class Contributor
{
int pixel; // Source pixel
float weight; // Pixel weight
}
class CList
{
int n;
Contributor[] p;
}
private Integer outWidth;
private Integer outHeight;
private ResampleFilter filter;
private static ResampleFilter createFilter(int filterType)
{
switch(filterType)
{
case(FILTER_TYPE_BOX): return new BoxFilter();
case(FILTER_TYPE_TRIANGLE): return new TriangleFilter();
case(FILTER_TYPE_HERMITE): return new HermiteFilter();
case(FILTER_TYPE_BELL): return new BellFilter();
case(FILTER_TYPE_B_SPLINE): return new BSplineFilter();
case(FILTER_TYPE_LANCZOS3): return new Lanczos3Filter();
case(FILTER_TYPE_MITCHELL): return new MitchellFilter();
default:
{
throw new IllegalArgumentException("Unknown filter type in Resample: " + filterType);
}
}
}
/**
* Returns the filter to be used in this operation.
* @return ResampleFilter object or
* Supported image types: {@link IntegerImage}.
*
* The Graphics Gems Repository can be found at
* http://www.acm.org/tog/GraphicsGems/.
* It also includes information on the books and how to order them.
*
* @author Marco Schmidt
*/
public class Resample extends ImageToImageOperation
{
/**
* Constant for the Box filter (also known as Nearest Neighbor filter).
*/
public static final int FILTER_TYPE_BOX = 0;
/**
* Constant for the Triangle filter (also known as Linear filter or Bilinear filter).
*/
public static final int FILTER_TYPE_TRIANGLE = 1;
/**
* Constant for the Hermite filter.
*/
public static final int FILTER_TYPE_HERMITE = 2;
/**
* Constant for the Bell filter.
*/
public static final int FILTER_TYPE_BELL = 3;
/**
* Constant for the B-Spline filter.
*/
public static final int FILTER_TYPE_B_SPLINE = 4;
/**
* Constant for the Lanczos3 filter.
*/
public static final int FILTER_TYPE_LANCZOS3 = 5;
/**
* Constant for the Mitchell filter.
*/
public static final int FILTER_TYPE_MITCHELL = 6;
class Contributor
{
int pixel; // Source pixel
float weight; // Pixel weight
}
class CList
{
int n;
Contributor[] p;
}
private Integer outWidth;
private Integer outHeight;
private ResampleFilter filter;
private static ResampleFilter createFilter(int filterType)
{
switch(filterType)
{
case(FILTER_TYPE_BOX): return new BoxFilter();
case(FILTER_TYPE_TRIANGLE): return new TriangleFilter();
case(FILTER_TYPE_HERMITE): return new HermiteFilter();
case(FILTER_TYPE_BELL): return new BellFilter();
case(FILTER_TYPE_B_SPLINE): return new BSplineFilter();
case(FILTER_TYPE_LANCZOS3): return new Lanczos3Filter();
case(FILTER_TYPE_MITCHELL): return new MitchellFilter();
default:
{
throw new IllegalArgumentException("Unknown filter type in Resample: " + filterType);
}
}
}
/**
* Returns the filter to be used in this operation.
* @return ResampleFilter object or
* Supported image types: {@link IntegerImage}.
*
* Usage example:
*
* Note that the arguments to this method are zero-based, so the first column and row
* are 0, the second 1, the third 2, and so on.
* If you have a image that is 200 pixels wide and 100 pixels high,
* values from 0 to 199 are valid for the x arguments, and values from 0 to 99 are valid
* for the vertical direction.
* @param x1 horizontal position of upper left corner of the rectangle
* @param y1 vertical position of upper left corner of the rectangle
* @param x2 horizontal position of lower right corner of the rectangle
* @param y2 vertical position of lower right corner of the rectangle
* @throws IllegalArgumentException if any of the arguments is negative or x1 larger than x2 or y1 larger than y2
*/
public void setBounds(int x1, int y1, int x2, int y2) throws IllegalArgumentException
{
if (x1 < 0)
{
throw new IllegalArgumentException("x1 must not be negative.");
}
if (y1 < 0)
{
throw new IllegalArgumentException("y1 must not be negative.");
}
if (x2 < 0)
{
throw new IllegalArgumentException("x2 must not be negative.");
}
if (y2 < 0)
{
throw new IllegalArgumentException("y2 must not be negative.");
}
if (x1 > x2)
{
throw new IllegalArgumentException("x1 must not be larger than x2.");
}
if (y1 > y2)
{
throw new IllegalArgumentException("y1 must not be larger than y2.");
}
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/geometry/Rotate180.java 0000664 0000000 0000000 00000003775 07741250133 024231 0 ustar /*
* Rotate180
*
* Copyright (c) 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.geometry;
import net.sourceforge.jiu.data.PixelImage;
import net.sourceforge.jiu.data.IntegerImage;
import net.sourceforge.jiu.ops.ImageToImageOperation;
import net.sourceforge.jiu.ops.MissingParameterException;
import net.sourceforge.jiu.ops.WrongParameterException;
/**
* Rotates images by 180 degrees.
* The result is the same as a a {@link Flip} operation followed by a {@link Mirror} operation (or vice versa).
* Input image must implement {@link net.sourceforge.jiu.data.IntegerImage}.
*
Operations to change the geometry of an image, mirroring it horizontally and vertically,
shearing, scaling and rotating it.
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/geometry/Lanczos3Filter.java 0000664 0000000 0000000 00000001525 07741250133 025373 0 ustar /*
* Lanczos3Filter
*
* Copyright (c) 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.geometry;
/**
* The Lanczos 3 resample filter.
* @author Marco Schmidt
* @since 0.10.0
* @see Resample
* @see ResampleFilter
*/
public class Lanczos3Filter extends ResampleFilter
{
private double sinc(double value)
{
if (value != 0.0f)
{
value = value * Math.PI;
return Math.sin(value) / value;
}
else
{
return 1.0;
}
}
public float apply(float value)
{
if (value < 0.0f)
{
value = -value;
}
if (value < 3.0f)
{
return (float)(sinc(value) * sinc(value / 3.0));
}
else
{
return 0.0f;
}
}
public String getName()
{
return "Lanczos3";
}
public float getRecommendedSamplingRadius()
{
return 3.0f;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/geometry/Shear.java 0000664 0000000 0000000 00000010667 10324333614 023577 0 ustar /*
* Shear
*
* Copyright (c) 2001, 2002, 2003, 2004, 2005 Marco Schmidt
* All rights reserved.
*/
package net.sourceforge.jiu.geometry;
import net.sourceforge.jiu.data.PixelImage;
import net.sourceforge.jiu.data.IntegerImage;
import net.sourceforge.jiu.ops.ImageToImageOperation;
import net.sourceforge.jiu.ops.MissingParameterException;
import net.sourceforge.jiu.ops.WrongParameterException;
/**
* Shears an image by a given angle.
* The angle must be larger than -90 and smaller than 90 degrees.
* Shearing works with all image types that implement {@link net.sourceforge.jiu.data.IntegerImage}.
*
* This is an adjusted version of Jef Poskanzer's shearing code from his ACME
* package; see the
* API
* documentation page of ACME's Shear class.
*
* @author Jef Poskanzer
* @author Marco Schmidt
*/
public class Shear extends ImageToImageOperation
{
private double angle;
/**
* For a given image width and shearing angle this method
* computes the width of the resulting image.
* This method is static so that it can be called easily from a GUI dialog
* or other objects that want to present the width of a sheared image.
* @param oldImageWidth horizontal resolution of the image to be sheared
* @param height height of the image to be sheared
* @param angle the angle to be used in the shearing operation
* @return width of the sheared image
*/
public static int computeNewImageWidth(int oldImageWidth, int height, double angle)
{
double shearfac = Math.tan(angle * Math.PI / 180.0);
if (shearfac < 0.0)
{
shearfac = -shearfac;
}
return (int)(height * shearfac + oldImageWidth + 0.999999);
}
/**
* Returns the angle associated with this shearing operation object.
* @return shearing angle, between -90 and 90
* @see #setAngle
*/
public double getAngle()
{
return angle;
}
private void process(IntegerImage in, IntegerImage out)
{
final int WIDTH = in.getWidth();
final int HEIGHT = in.getHeight();
int totalItems = in.getNumChannels() * HEIGHT;
int processedItems = 0;
double angle = getAngle() * Math.PI / 180.0;
double shearfac = Math.tan(angle);
if (shearfac < 0.0)
{
shearfac = -shearfac;
}
int NEW_WIDTH = (int)(HEIGHT * shearfac + WIDTH + 0.999999);
if (out == null)
{
out = (IntegerImage)in.createCompatibleImage(NEW_WIDTH, HEIGHT);
setOutputImage(out);
}
for (int c = 0; c < in.getNumChannels(); c++)
{
for (int y = 0; y < HEIGHT; y++)
{
double new0;
if (angle > 0.0)
{
new0 = y * shearfac;
}
else
{
new0 = (HEIGHT - y) * shearfac;
}
int intnew0 = (int)new0;
double fracnew0 = new0 - intnew0;
double omfracnew0 = 1.0 - fracnew0;
int prev = 0;
for (int x = 0; x < WIDTH; x++)
{
int value = in.getSample(c, x, y);
out.putSample(c, intnew0 + x, y, (int)(fracnew0 * prev + omfracnew0 * value));
prev = value;
}
out.putSample(c, intnew0 + WIDTH, y, (int)(fracnew0 * prev));
setProgress(processedItems++, totalItems);
}
}
}
public void process() throws
MissingParameterException,
WrongParameterException
{
ensureInputImageIsAvailable();
PixelImage in = getInputImage();
ensureOutputImageResolution(computeNewImageWidth(in.getWidth(), in.getHeight(), getAngle()), in.getHeight());
if (in instanceof IntegerImage)
{
process((IntegerImage)in, (IntegerImage)getOutputImage());
}
else
{
throw new WrongParameterException("Input image must implement IntegerImage.");
}
}
/**
* Sets the angle to be used in the shearing operation to the argument value.
* The angle must be larger than -90.0 and smaller than 90.0.
* @param newAngle the angle to be used in this operation
* @throws IllegalArgumentException if the argument is not in the above mentioned interval
* @see #getAngle
*/
public void setAngle(double newAngle)
{
if (newAngle <= -90.0 || newAngle >= 90.0)
{
throw new IllegalArgumentException("Angle must be > -90 and < 90; got " + newAngle);
}
else
{
angle = newAngle;
}
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/geometry/Rotate90Left.java 0000664 0000000 0000000 00000003570 07741250133 024755 0 ustar /*
* Rotate90Left
*
* Copyright (c) 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.geometry;
import net.sourceforge.jiu.data.PixelImage;
import net.sourceforge.jiu.data.IntegerImage;
import net.sourceforge.jiu.ops.ImageToImageOperation;
import net.sourceforge.jiu.ops.MissingParameterException;
import net.sourceforge.jiu.ops.WrongParameterException;
/**
* Rotates images by 90 degrees counter-clockwise (to the left).
* Input image must implement {@link net.sourceforge.jiu.data.IntegerImage}.
*
* Note that there are
* @param resolution one of PCD_RESOLUTION_1, PCD_RESOLUTION_2 or PCD_RESOLUTION_3
* @throws an IOException if there were any reading errors
*/
private void loadUncompressedImage(int resolution)
throws IllegalArgumentException, IOException
{
if (resolution != PCD_RESOLUTION_1 &&
resolution != PCD_RESOLUTION_2 &&
resolution != PCD_RESOLUTION_3)
{
throw new IllegalArgumentException("Error loading " +
"PCD image, only the lowest three resolutions are " +
"uncompressed.");
}
in.seek(PCD_FILE_OFFSETS[resolution]);
int fullWidth = PCD_RESOLUTIONS[resolution][0];
int fullHeight = PCD_RESOLUTIONS[resolution][1];
int halfWidth = fullWidth / 2;
int halfHeight = fullHeight / 2;
int offset1 = 0;
int offset2 = 0;
for (int y = 0; y < halfHeight; y++)
{
// read two luminance rows
in.readFully(data[INDEX_Y], offset1, fullWidth * 2);
offset1 += (fullWidth * 2);
if (monochrome)
{
if (in.skipBytes(fullWidth) != fullWidth)
{
throw new IOException("Could not skip " + fullWidth +
" bytes.");
}
}
else
{
// read one row for each cb and cr
in.readFully(data[INDEX_CB], offset2, halfWidth);
in.readFully(data[INDEX_CR], offset2, halfWidth);
offset2 += halfWidth;
}
}
}
/**
* Checks the parameter and loads an image.
*/
public void process() throws
InvalidFileStructureException,
MissingParameterException,
OperationFailedException,
UnsupportedTypeException,
WrongFileFormatException
{
in = getRandomAccessFile();
if (in == null)
{
throw new MissingParameterException("RandomAccessFile object needed in PCDCodec.");
}
if (getMode() != CodecMode.LOAD)
{
throw new UnsupportedTypeException("PCDCodec can only load images.");
}
try
{
load();
}
catch (IOException ioe)
{
throw new OperationFailedException("I/O error: " + ioe.toString());
}
}
private void rotateArrays(int rotationAngle, int width, int height)
{
if (rotationAngle == NO_ROTATION)
{
return;
}
int numPixels = width * height;
for (int i = 0; i < numChannels; i++)
{
byte[] dest = new byte[numPixels];
switch(rotationAngle)
{
case(ROTATE_90_LEFT):
{
ArrayRotation.rotate90Left(width, height, data[i], 0, dest, 0);
break;
}
case(ROTATE_90_RIGHT):
{
ArrayRotation.rotate90Right(width, height, data[i], 0, dest, 0);
break;
}
case(ROTATE_180):
{
ArrayRotation.rotate180(width, height, data[i], 0, dest, 0);
break;
}
}
System.arraycopy(dest, 0, data[i], 0, numPixels);
}
}
/*private void scaleUp(int currentResolution)
{
int width = PCD_RESOLUTIONS[currentResolution][0];
int height = PCD_RESOLUTIONS[currentResolution][1];
ArrayScaling.scaleUp200Percent(data[INDEX_Y], width, height);
if (!monochrome)
{
ArrayScaling.scaleUp200Percent(data[INDEX_CB], width, height);
ArrayScaling.scaleUp200Percent(data[INDEX_CR], width, height);
}
}*/
/**
* Specify whether color is converted from PCD's YCbCr color space to
* RGB color space.
* The default is
* According to the PNG specs the reason for multiple IDAT chunks is as
* follows:
*
* If there is a more elegant approach to read multiple IDAT chunks, please
* let me know.
* However, reading everything into memory is not an option.
* @author Marco Schmidt
* @since 0.12.0
*/
class PngIdatInputStream extends InputStream
{
private static final int IDAT = 0x49444154;
private DataInputStream in;
private long bytesLeft;
public PngIdatInputStream(DataInputStream input, long bytes)
{
in = input;
bytesLeft = bytes;
}
public int read() throws IOException
{
if (bytesLeft == 0)
{
skipHeaders();
}
bytesLeft--;
return in.read();
}
private void skipHeaders() throws IOException
{
do
{
//int crc = in.readInt();
in.readInt(); // skip CRC
bytesLeft = in.readInt() & 0xffffffffL;
int type = in.readInt();
if (IDAT != type)
{
throw new IOException("Expected IDAT chunk type, got " +
Integer.toHexString(type));
}
}
while (bytesLeft == 0);
}
}
/**
* A codec for the Portable Network Graphics (PNG) format.
* Supports both loading and saving of images.
*
* Compressed image data is spread over several IDAT chunks by this codec.
* The length of the compressed data of a complete image is known only after the complete image
* has been encoded.
* With PNG, that length value has to be stored before the compressed data as a chunk size value.
* This codec is supposed to work with {@link java.io.OutputStream} objects,
* so seeking back to adjust the chunk size value of an IDAT chunk is not
* possible.
* That's why all data of a chunk is compressed into a memory buffer.
* Whenever the buffer gets full, it is written to output as an IDAT chunk.
*
* Note that the last IDAT chunk may be smaller than the size defined here.
* @param newSize size of encoding compressed data buffer
*/
public void setEncodingIdatSize(int newSize)
{
if (newSize < 1)
{
throw new IllegalArgumentException("Minimum IDAT chunk size must be 1 or larger.");
}
encodingMinIdatSize = newSize;
}
public void setFile(String fileName, CodecMode codecMode) throws IOException, UnsupportedCodecModeException
{
if (codecMode == CodecMode.LOAD)
{
setInputStream(new BufferedInputStream(new FileInputStream(fileName)));
}
else
{
super.setFile(fileName, codecMode);
}
}
/**
* Sets date and time of last modification of the image to be stored in a PNG stream
* when saving.
* Make sure the argument object has UTC as time zone
* (as
* demanded by the PNG specs).
* If you want the current time and date, use
*
* Only writing GIF files is supported right now.
* Reading GIF files with JIU can be done with the {@link net.sourceforge.jiu.gui.awt.ToolkitLoader}
* class which uses the image reader built into the Java runtime library ({@link java.awt.Toolkit} class).
* That reader has supported GIF since Java 1.0.
*
* Interlaced files store the image in four passes, progressively adding
* rows until the complete image is stored.
* When decoding, the progressive display of interlaced files makes it
* supposedly quicker to find out what's displayed in the image.
*
* On the other hand, transmission typically takes longer, because interlacing
* often leads to slightly larger files.
* When using interlaced mode, lines that get stored one after another
* have some room between them in the image, so there are less similarities
* between consecutive lines, which worsens compression ratio (compression
* works better with a lot of similarities in the data to be compressed).
*
* A Codec that cannot safely identify a file to be in the format that it supports must not be used with ImageLoader.
* The failure to identify typically comes from the lack of magic byte sequences defined for the format.
* In order to load such a file, use the codec manually.
* Example: {@link PalmCodec}.
*
* In order to load an image via {@link java.awt.Toolkit} (JPEG, PNG or GIF), use
* {@link net.sourceforge.jiu.gui.awt.ToolkitLoader}.
* It combines the loading features of java.awt.Toolkit and JIU's ImageLoader.
*
* Note that this filter does not include file formats supported by the AWT
* {@link java.awt.Toolkit} (GIF and JPEG, also PNG since Java 1.3).
* @return filter for image file names
*/
public static FilenameFilter createFilenameFilter()
{
return new FilenameFilter()
{
public boolean accept(File dir, String name)
{
if (name == null)
{
return false;
}
if (fileExtensions == null)
{
updateFileExtensions();
}
name = name.toLowerCase();
int index = 0;
while (index < fileExtensions.size())
{
String ext = (String)fileExtensions.elementAt(index++);
if (name.endsWith(ext))
{
return true;
}
}
return false;
}
};
}
/**
* Returns the number of codec classes currently known to ImageLoader.
* This number can be changed by registering additional codecs
* ({@link #registerCodecClass})
* or by removing codec classes ({@link #removeCodecClass}).
* @return number of known codec classes
*/
public static int getNumCodecs()
{
return imageCodecClasses.size();
}
/**
* Attempts to load an image from a file.
* @param file the file from which an image is to be loaded
* @return the image on success or
* Example: let's say you have written a new codec called ACMEImageCodec.
* Your codec supports loading images.
* Then you could register it like that:
*
* @param codec an instance of the codec class to be registered
*/
public static void registerCodecClass(ImageCodec codec)
{
if (codec == null)
{
return;
}
if (imageCodecClasses.contains(codec.getClass()))
{
return;
}
if (!codec.isLoadingSupported())
{
throw new IllegalArgumentException("Codec does not support loading.");
}
imageCodecClasses.addElement(codec.getClass());
updateFileExtensions();
}
/**
* Removes all codec classes from the internal list of codec classes.
* After a call to this method, ImageLoader will not load anything unless
* new codecs get registered.
*/
public static void removeAllCodecClasses()
{
imageCodecClasses = new Vector();
updateFileExtensions();
}
/**
* Removes a codec class from the internal list of codec classes.
* @param codec an instance of the codec class to be removed
*/
public static void removeCodecClass(ImageCodec codec)
{
if (codec == null)
{
return;
}
int index = imageCodecClasses.indexOf(codec.getClass());
if (index != -1)
{
imageCodecClasses.remove(index);
updateFileExtensions();
}
else
{
throw new IllegalArgumentException("The argument codec's class " +
"could not be found in the internal list of codec classes.");
}
}
private static void updateFileExtensions()
{
fileExtensions = new Vector();
int index = 0;
while (index < getNumCodecs())
{
try
{
ImageCodec codec = createCodec(index++);
String[] extArray = codec.getFileExtensions();
if (extArray != null && extArray.length > 0)
{
for (int i = 0; i < extArray.length; i++)
{
fileExtensions.addElement(extArray[i].toLowerCase());
}
}
}
catch (Exception e)
{
}
}
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/UnsupportedTypeException.java 0000664 0000000 0000000 00000001770 07741250131 027207 0 ustar /*
* UnsupportedTypeException
*
* Copyright (c) 2000, 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.codecs;
import net.sourceforge.jiu.ops.OperationFailedException;
/**
* This exception is thrown during image loading.
* If a codec recognizes the file format but does not support the
* exact subtype it encounters (the compression type is unknown or
* the color depth unsupported), an instance of this exception class is
* created.
*
* If the format is not recognized at all, a {@link WrongFileFormatException}
* should be thrown.
*
* If there were errors during loading because of file corruption, an
* {@link InvalidFileStructureException} must be thrown.
*
* @see InvalidFileStructureException
* @see WrongFileFormatException
*
* @author Marco Schmidt
*/
public class UnsupportedTypeException extends OperationFailedException
{
public UnsupportedTypeException(String message)
{
super(message);
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/InvalidImageIndexException.java 0000664 0000000 0000000 00000001572 07741250131 027336 0 ustar /*
* InvalidImageIndexException
*
* Copyright (c) 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.codecs;
import net.sourceforge.jiu.ops.OperationFailedException;
/**
* This exception is thrown when the caller has defined an image
* index that specifies the image to be loaded in a multiple-image
* file and that index is unavailable.
* Example: user has specified an image index of 5, which is the
* sixth image in the file (counting starts at 0),
* but only three images are available.
* @author Marco Schmidt
*/
public class InvalidImageIndexException extends OperationFailedException
{
/**
* Creates new exception object with a given error message.
* @param message String with text describing the exact problem
*/
public InvalidImageIndexException(String message)
{
super(message);
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/PNMCodec.java 0000664 0000000 0000000 00000075412 10523756512 023540 0 ustar /*
* PNMCodec
*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.codecs;
import java.io.DataOutput;
import java.io.InputStream;
import java.io.IOException;
import java.io.PushbackInputStream;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import net.sourceforge.jiu.data.BilevelImage;
import net.sourceforge.jiu.data.GrayImage;
import net.sourceforge.jiu.data.Gray16Image;
import net.sourceforge.jiu.data.Gray8Image;
import net.sourceforge.jiu.data.GrayIntegerImage;
import net.sourceforge.jiu.data.IntegerImage;
import net.sourceforge.jiu.data.MemoryBilevelImage;
import net.sourceforge.jiu.data.MemoryGray16Image;
import net.sourceforge.jiu.data.MemoryGray8Image;
import net.sourceforge.jiu.data.MemoryRGB24Image;
import net.sourceforge.jiu.data.MemoryRGB48Image;
import net.sourceforge.jiu.data.PixelImage;
import net.sourceforge.jiu.data.RGB24Image;
import net.sourceforge.jiu.data.RGB48Image;
import net.sourceforge.jiu.data.RGBIndex;
import net.sourceforge.jiu.data.RGBIntegerImage;
import net.sourceforge.jiu.ops.MissingParameterException;
import net.sourceforge.jiu.ops.OperationFailedException;
import net.sourceforge.jiu.ops.WrongParameterException;
/**
* A codec to read and write Portable Anymap (PNM) image files.
* This format includes three file types well-known in the Unix world:
*
*
*
* The header of a PGM and PPM file stores a maximum sample value
* (such a value is not stored for PBM, where the maximum value is always 1).
* When in binary mode, PGM and PPM typically have a maximum sample value of 255,
* which makes PGM 8 bits per pixel and PPM 24 bits per pixel large.
* One sample will be stored as a single byte.
* However, there also exist binary PGM files with a maximum sample value larger than
* 255 and smaller than 65536.
* These files use two bytes per sample, in network byte order (big endian).
* I have yet to see PPM files with that property, but they are of course imagineable.
* 16 bpp
*
* Codecs have different requirements concerning I/O objects.
* If an image is to be loaded, it's enough for some formats to linearly read
* from an {@link java.io.InputStream} to load the image.
* However, some formats (like TIFF) require random access.
*
* When implementing a codec, take care that as many I/O classes as possible can be used.
* If possible, call {@link #getInputAsDataInput} when loading and {@link #getOutputAsDataOutput}
* when saving.
* That way, input / output streams, RandomAccessFiles and arbitrary DataInput / DataOutput objects
* can be used.
*
*
* Bounds; to load or save only part of an image.
* Defining bounds is optional; by default, the complete image is loaded
* or saved (no bounds).
* Using {@link #setBounds(int, int, int, int)}, one can specify the
* rectangle which will be loaded or saved.
*
* PixelImage object; get and set methods for the image which is to be
* loaded or saved.
* If an image is to be loaded, a PixelImage object can optionally be specified so that the image will
* be written to that object; image type and resolution must of course match the image
* from input.
* Normally, the codec will create the appropriate image object
* itself.
* If an image is to be saved, an image object must be provided, otherwise there
* is nothing to do.
*
* Image index; the index of the image that is to be loaded (int value, default
* is 0). For image formats that support more than one image in one stream, the index of the
* image to be loaded (zero-based) can be specified using {@link #setImageIndex(int)}.
*
*
* Each file format must be able to return its name ({@link #getFormatName()}) and
* file extensions that are typical for it ({@link #getFileExtensions()}).
*
* A related method suggests a file extension for a given PixelImage object ({@link #suggestFileExtension(PixelImage)}).
* That method need not be implemented, the default version returns simply
* @author Marco Schmidt
*/
public abstract class ImageCodec extends Operation
{
private int boundsX1;
private int boundsY1;
private int boundsX2;
private int boundsY2;
private boolean boundsAvail;
private int boundsWidth;
private int boundsHeight;
private Vector comments;
private int dpiX;
private int dpiY;
private DataInput din;
private DataOutput dout;
private PixelImage image;
private int imageIndex;
private InputStream in;
private CodecMode mode;
private OutputStream out;
private RandomAccessFile raf;
/**
* This constructor will be called by descendants.
* The bounds state is initialized to no bounds.
*/
public ImageCodec()
{
super();
comments = new Vector();
removeBounds();
}
/**
* Appends a comment to the internal list of comments.
* If the argument comment is non-null, it will be added to the internal
* list of comment strings.
* @param comment the comment to be added
*/
public void appendComment(String comment)
{
if (comment != null)
{
comments.addElement(comment);
}
}
/**
* If bounds were defined for this codec, this method tests if the
* bounds rectangle fits into the rectangle
* Example: if vertical bounds have been set to 34 and 37, image rows 34 to
* 37 as arguments to this method would result in
Provides classes to read images from JPEG bitstreams.
Provides classes to read images from and save them to files (or streams) in various file formats.
In some cases, it will be sufficient for codecs to use
{@link java.io.InputStream} and {@link java.io.OutputStream}.
This approach should be picked when possible, as it allows for maximum
flexibility--input and output streams can be files, network streams,
standard input / output (so that data can be piped on the command line)
and more.
However, in some cases, it will be necessary for codecs to use
{@link java.io.RandomAccessFile} in order to seek to various places in
the file.
Note that the codecs are (sometimes more, sometimes less) far from being
finished or even stable.
Please do not rely on them for important data.
Treat the codecs (and the rest of JIU) as beta software.
All image codecs must extend the {@link net.sourceforge.jiu.codecs.ImageCodec} class.
They may support only a subset of all possible flavors of an image file format.
As an example, they may choose to support only reading or only writing.
As {@link net.sourceforge.jiu.codecs.ImageCodec} extends {@link net.sourceforge.jiu.ops.Operation},
the progress notification system can (and should) be used.
If the codecs are used
in GUI (graphical user interface) applications, users could be shown a
progress bar--loading and saving can be time-consuming.
{@link net.sourceforge.jiu.codecs.ImageCodec} provides methods to specify
a rectangular part of an image.
The information should be used by the codec to read or write only that part of the image.
That way, loading only a part of a huge image is typically faster and consumes less
memory.
When saving a part of a huge image, an additional crop operation becomes unncessary this way.
Obviously, JIU can only benefit from supporting more file formats.
If you want to contribute codecs to JIU (remember that you must provide your
code under the GNU General Public License), please contact the maintainer
at the JIU website.
However, note that no code will be integrated that uses patented algorithms.
For better or worse, algorithms like LZW compression (used optionally in TIFF
and mandatory in GIF) or arithmetic entropy coding (used in some parts of JPEG)
are patented in several countries.
In order to use these algorithms, one has to pay license fees.
This is not acceptable for JIU and therefore no code will be integrated
that uses such algorithms.
In cases like GIF or TIFF/LZW that is very unfortunate because these formats
a certain popularity that would make them interesting to support.
Read the GIF
section of the Open Directory, it contains several links to sites that
explain the situation (from different points of view).
File format specifications can be found at the following resources:
* If there were errors during loading because of file corruption, an
* {@link InvalidFileStructureException} should be thrown.
*
* If the format is recognized but cannot be loaded because the codec
* does not fully support the file format, a {@link UnsupportedTypeException}
* should be thrown.
*
* @author Marco Schmidt
* @see InvalidFileStructureException
* @see UnsupportedTypeException
*/
public class WrongFileFormatException extends OperationFailedException
{
public WrongFileFormatException(String message)
{
super(message);
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/UnsupportedCodecModeException.java 0000664 0000000 0000000 00000001237 07741250131 030106 0 ustar /*
* UnsupportedCodecModeException
*
* Copyright (c) 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.codecs;
import net.sourceforge.jiu.ops.OperationFailedException;
/**
* This exception is thrown when a codec does not support the
* codec mode wanted by the user.
* Example: A user gives an OutputStream to a codec, indicating that an
* image is to be saved, but the codec only supports loading.
* @author Marco Schmidt
* @since 0.10.0
*/
public class UnsupportedCodecModeException extends OperationFailedException
{
public UnsupportedCodecModeException(String message)
{
super(message);
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/BMPCodec.java 0000664 0000000 0000000 00000063305 10377274012 023517 0 ustar /*
* BMPCodec
*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.codecs;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import net.sourceforge.jiu.codecs.ImageCodec;
import net.sourceforge.jiu.codecs.InvalidFileStructureException;
import net.sourceforge.jiu.codecs.UnsupportedTypeException;
import net.sourceforge.jiu.codecs.WrongFileFormatException;
import net.sourceforge.jiu.data.BilevelImage;
import net.sourceforge.jiu.data.ByteChannelImage;
import net.sourceforge.jiu.data.Gray8Image;
import net.sourceforge.jiu.data.MemoryBilevelImage;
import net.sourceforge.jiu.data.MemoryPaletted8Image;
import net.sourceforge.jiu.data.MemoryRGB24Image;
import net.sourceforge.jiu.data.Paletted8Image;
import net.sourceforge.jiu.data.PixelImage;
import net.sourceforge.jiu.data.Palette;
import net.sourceforge.jiu.data.RGB24Image;
import net.sourceforge.jiu.data.RGBIndex;
import net.sourceforge.jiu.ops.MissingParameterException;
import net.sourceforge.jiu.ops.OperationFailedException;
import net.sourceforge.jiu.util.ArrayConverter;
/**
* A codec to read and write Windows BMP image files.
*
* Typical file extensions are
* This codec supports the bounds concept for loading and saving.
*
*
* The RLE-compressed BMP files that I could test this codec on seem to
* have an end-of-line code at the end of every line instead of relying
* on the decoder to know when it has unpacked enough bytes for a line.
* Whenever this codec encounters an EOL symbol and has a current column
* value of
* This implementation is based on the file
* Learn more about the color type and its encoding on Greg's page
* LogLuv
* Encoding for TIFF Images.
* You will also find numerous sample image files there.
* @author Marco Schmidt
* @since 0.10.0
*/
public class TIFFDecoderLogLuv extends TIFFDecoder
{
private DataInput in;
private int compressedSize;
private int tileWidth;
private boolean rle;
public void decode() throws
InvalidFileStructureException,
IOException
{
byte[] row = new byte[getBytesPerRow()];
rle = getImageFileDirectory().getCompression() == TIFFConstants.COMPRESSION_SGI_LOG_RLE;
for (int y = getY1(); y <= getY2(); y++)
{
decodeRow(row);
putBytes(row, 0, row.length);
}
}
private void decodeRow(byte[] row) throws
InvalidFileStructureException,
IOException
{
if (rle)
{
decodeRowRLE(row);
}
else
{
decodeRowPacked24(row);
}
}
private void decodeRowPacked24(byte[] row) throws
InvalidFileStructureException,
IOException
{
int num = getImageFileDirectory().getTileWidth() * 3;
in.readFully(row, 0, num);
}
private void decodeRowRLE(byte[] row) throws
InvalidFileStructureException,
IOException
{
final int BYTES_PER_PIXEL;
if (getImageFileDirectory().getPhotometricInterpretation() == TIFFConstants.PHOTOMETRIC_LOGL)
{
BYTES_PER_PIXEL = 2; // LogL
}
else
{
BYTES_PER_PIXEL = 4; // LogLuv
}
for (int initialOffset = 0; initialOffset < BYTES_PER_PIXEL; initialOffset++)
{
int offset = initialOffset;
int numPixels = tileWidth;
do
{
int v1 = in.readUnsignedByte();
if ((v1 & 128) != 0)
{
// run
int runCount = v1 + (2 - 128);
numPixels -= runCount;
compressedSize -= 2;
byte v2 = in.readByte();
while (runCount-- != 0)
{
row[offset] = v2;
offset += BYTES_PER_PIXEL;
}
}
else
{
// non-run, copy data
int runCount = v1;
numPixels -= runCount;
compressedSize = compressedSize - runCount - 1;
while (runCount-- != 0)
{
row[offset] = in.readByte();
offset += BYTES_PER_PIXEL;
}
}
if (compressedSize < 0)
{
throw new InvalidFileStructureException("Ran out of compressed input bytes before completing the decoding process.");
}
}
while (numPixels > 0);
}
}
public Integer[] getCompressionTypes()
{
return new Integer[] {new Integer(TIFFConstants.COMPRESSION_SGI_LOG_RLE), new Integer(TIFFConstants.COMPRESSION_SGI_LOG_24_PACKED)};
}
public void initialize() throws
IOException,
MissingParameterException
{
super.initialize();
in = getInput();
compressedSize = getImageFileDirectory().getByteCount(getTileIndex());
tileWidth = getImageFileDirectory().getTileWidth();
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/tiff/TIFFImageFileDirectory.java 0000664 0000000 0000000 00000065032 10541055055 027247 0 ustar /*
* TIFFImageFileDirectory
*
* Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.codecs.tiff;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.TimeZone;
import java.util.Vector;
import net.sourceforge.jiu.codecs.InvalidFileStructureException;
import net.sourceforge.jiu.codecs.UnsupportedTypeException;
import net.sourceforge.jiu.codecs.tiff.TIFFConstants;
import net.sourceforge.jiu.codecs.tiff.TIFFTag;
import net.sourceforge.jiu.data.Palette;
import net.sourceforge.jiu.data.RGBIndex;
/**
* This class encapsulates all data of a TIFF image file directory (IFD).
* @author Marco Schmidt
*/
public class TIFFImageFileDirectory implements TIFFConstants
{
public static final int TYPE_BILEVEL_PACKED = 0;
public static final int TYPE_GRAY4 = 1;
public static final int TYPE_GRAY8 = 2;
public static final int TYPE_GRAY16 = 3;
public static final int TYPE_PALETTED4 = 4;
public static final int TYPE_PALETTED8 = 5;
public static final int TYPE_RGB24_INTERLEAVED = 6;
public static final int TYPE_RGB48_INTERLEAVED = 7;
public static final int TYPE_BILEVEL_BYTE = 8;
public static final int TYPE_CMYK32_INTERLEAVED = 9;
public static final int TYPE_CMYK32_PLANAR = 10;
public static final int TYPE_LOGLUV32_INTERLEAVED = 11;
public static final int TYPE_LOGL = 12;
private String artist;
private int[] bitsPerSample;
private int bitsPerPixel;
private int bitsPerRow;
private int bytesBetweenSamples;
private int[] bytesPerSample;
private int bytesPerRow;
private int compression;
private String copyright;
private Date date;
private String dateTime;
private int dpiX;
private int dpiY;
private int[] extraSamples;
private int height;
private int horizontalTiles;
private String hostComputer;
private String imageDescription;
private int imageType;
private boolean invertGraySamples;
private String make;
private String model;
private int numStrips;
private int numTiles;
private int orientation;
private Palette palette;
private int pixelsPerRow;
private int planarConfiguration;
private int photometricInterpretation;
private int predictor;
private int[] sampleTypes;
private int resolutionUnit;
private double resolutionX;
private double resolutionY;
private int rowsPerStrip;
private int samplesPerPixel;
private String software;
private Vector stripByteCounts;
private Vector stripOffsets;
private int t4Options;
private int t6Options;
private Vector tags;
private Vector tileByteCounts;
private Vector tileOffsets;
private TimeZone timeZone;
private int tileWidth;
private int tileHeight;
private int verticalTiles;
private int width;
/**
* Initializes all members to null or -1 and creates an internal list for
* the tags that will be make up this directory.
*/
public TIFFImageFileDirectory()
{
initMembers();
tags = new Vector();
}
/**
* Adds a tag to the end of the internal list of tags.
* @param tag the TIFFTag instance to be appended
*/
public void append(TIFFTag tag)
{
tags.addElement(tag);
}
private void checkContent() throws
InvalidFileStructureException,
UnsupportedTypeException
{
if (width < 1)
{
throw new InvalidFileStructureException("No valid width available.");
}
if (height < 1)
{
throw new InvalidFileStructureException("No valid width available.");
}
if (stripOffsets != null)
{
pixelsPerRow = width;
}
else
if (tileOffsets != null)
{
pixelsPerRow = tileWidth;
}
if (rowsPerStrip == -1 && stripOffsets != null && stripOffsets.size() == 1)
{
rowsPerStrip = height;
}
// do more checks based on color type
switch (photometricInterpretation)
{
case(PHOTOMETRIC_BLACK_IS_ZERO):
case(PHOTOMETRIC_WHITE_IS_ZERO):
{
if (bitsPerSample[0] == 1)
{
imageType = TYPE_BILEVEL_PACKED;
}
else
{
if (bitsPerSample[0] == 4)
{
imageType = TYPE_GRAY4;
}
else
if (bitsPerSample[0] == 8)
{
imageType = TYPE_GRAY8;
}
else
{
throw new UnsupportedTypeException("Only bit depths 1, 4 and 8 are supported for bilevel and grayscale images.");
}
}
break;
}
case(PHOTOMETRIC_PALETTED):
{
if (getPalette() == null)
{
throw new InvalidFileStructureException("No palette found in paletted image.");
}
break;
}
case(PHOTOMETRIC_TRUECOLOR_RGB):
{
if (planarConfiguration != PLANAR_CONFIGURATION_CHUNKY)
{
throw new UnsupportedTypeException("Cannot handle planar configuration other than chunky for RGB images.");
}
if (bitsPerSample.length != 3)
{
throw new UnsupportedTypeException("Found RGB truecolor image, but instead of three " + bitsPerSample.length + " component(s).");
}
if (bitsPerPixel == 24)
{
imageType = TYPE_RGB24_INTERLEAVED;
}
else
if (bitsPerPixel == 48)
{
imageType = TYPE_RGB48_INTERLEAVED;
}
else
{
throw new UnsupportedTypeException("Unsupported RGB truecolor image color depth: " + bitsPerPixel + ".");
}
break;
}
case(PHOTOMETRIC_TRUECOLOR_LOGLUV):
{
if (planarConfiguration == PLANAR_CONFIGURATION_CHUNKY)
{
imageType = TYPE_LOGLUV32_INTERLEAVED;
}
else
{
throw new UnsupportedTypeException("Cannot handle planar configuration other than chunky for RGB images.");
}
break;
}
case(PHOTOMETRIC_LOGL):
{
imageType = TYPE_LOGL;
break;
}
case(PHOTOMETRIC_TRUECOLOR_CMYK):
{
if (planarConfiguration == PLANAR_CONFIGURATION_CHUNKY)
{
imageType = TYPE_CMYK32_INTERLEAVED;
}
/*else
if (planarConfiguration == PLANAR_CONFIGURATION_PLANAR)
{
imageType = TYPE_CMYK32_PLANAR;
}*/
else
{
throw new UnsupportedTypeException("Cannot handle planar configuration other than chunky for CMYK images.");
}
break;
}
default:
{
throw new UnsupportedTypeException("Unsupported color type: " + photometricInterpretation + ".");
}
}
if (compression == COMPRESSION_CCITT_GROUP3_1D_MODIFIED_HUFFMAN)
{
if (bitsPerPixel != 1)
{
throw new UnsupportedTypeException("Number of bits per pixel must be 1 for " +
"compression type: " + getCompressionName(compression) + ".");
}
imageType = TYPE_BILEVEL_BYTE;
}
// TODO more validity checks
}
/**
* TODO: regard extra samples
*/
public int computeNumBytes(int numPixels)
{
if (bitsPerPixel == 1)
{
if (imageType == TYPE_BILEVEL_BYTE)
{
return numPixels;
}
else
{
return (numPixels + 7) / 8;
}
}
else
if (bitsPerPixel <= 4)
{
return (numPixels + 1) / 2;
}
else
if (bitsPerPixel <= 8)
{
return numPixels;
}
else
if (bitsPerPixel == 16)
{
return numPixels * 2;
}
else
if (bitsPerPixel == 24)
{
return numPixels * 3;
}
else
if (bitsPerPixel == 32)
{
return numPixels * 4;
}
else
if (bitsPerPixel == 48)
{
return numPixels * 6;
}
else
{
return -1;
}
}
/**
* Returns information on the person who created the image
* (as stored in tag {@link TIFFConstants#TAG_ARTIST}).
*/
public String getArtist()
{
return artist;
}
/**
* Returns the number of bits per pixel (not including transparency information).
*/
public int getBitsPerPixel()
{
return bitsPerPixel;
}
/**
* Returns the number of compressed byte for a given tile.
* Tile index must not be negative and must be smaller than the number of tiles.
* @param tileIndex zero-based index of tile or strip for which the number of compressed bytes is to be returned
*/
public int getByteCount(int tileIndex)
{
if (stripByteCounts != null)
{
return ((Number)stripByteCounts.elementAt(tileIndex)).intValue();
}
else
if (tileByteCounts != null)
{
return ((Number)tileByteCounts.elementAt(tileIndex)).intValue();
}
else
{
return 0;
}
}
public int getBytesPerRow()
{
return computeNumBytes(getTileWidth());
}
/**
* Returns the compression method, encoded as a number as found in
* {@link TIFFConstants} (more specifically, the COMPRESSION_xyz constants).
* Use {@link #getCompressionName(int)} to get the English name
* of this compression method.
* @return compression method
*/
public int getCompression()
{
return compression;
}
/**
* Returns the name of a TIFF compression method.
* If the name is unknown, Unknown method plus
* the method number is returned.
* This static method can be used in combination with the value from
* {@link #getCompression}.
* @param method the compression method number
* @return the compression method name
*/
public static String getCompressionName(int method)
{
switch(method)
{
case(COMPRESSION_CCITT_GROUP3_1D_MODIFIED_HUFFMAN): return "CCITT Group 3 1D Modified Huffman";
case(COMPRESSION_CCITT_T4): return "CCITT T.4";
case(COMPRESSION_CCITT_T6): return "CCITT T.6";
case(COMPRESSION_DEFLATED_INOFFICIAL): return "Deflated (inofficial, 32496)";
case(COMPRESSION_DEFLATED_OFFICIAL): return "Deflated (official, 8)";
case(COMPRESSION_LZW): return "LZW";
case(COMPRESSION_NONE): return "Uncompressed";
case(COMPRESSION_PACKBITS): return "Packbits";
case(6): return "JPEG (old style)";
case(7):return "JPEG (new style)";
case(103): return "Pegasus IMJ";
case(32766): return "NeXT 2-bit RLE";
case(32771): return "Uncompressed, word-aligned";
case(32809): return "Thunderscan RLE";
case(32895): return "IT8 CT with padding";
case(32896): return "IT8 Linework RLE";
case(32897): return "IT8 Monochrome picture";
case(32898): return "IT8 Binary line art";
case(32908): return "Pixar 10 bit LZW";
case(32909): return "Pixar 11 bit ZIP";
case(32947): return "Kodak DCS";
case(34661): return "ISO JBIG";
case(34676): return "SGI Log Luminance RLE";
case(34677): return "SGI Log 24-bit packed";
default: return "Unknown method (" + method + ")";
}
}
public String getCopyright()
{
return copyright;
}
/**
* If a date / time tag was found in this image file directory and
* {@link #initFromTags} was called already, it was attempted to
* create a {@link java.util.Date} object from it.
* This object (or
* This decoder makes use of the package java.util.zip which comes with an Inflater
* class that does most of the work.
* All the decoder has to do is feed the Inflater object with compressed data from
* the input file and give decompressed data received from the Inflater to the
* putBytes method.
* @author Marco Schmidt
* @since 0.9.0
*/
public class TIFFDecoderDeflated extends TIFFDecoder
{
private DataInput in;
private int compressedSize;
public void decode() throws
InvalidFileStructureException,
IOException
{
Inflater inflater = new Inflater();
byte[] ioBuffer = new byte[20000];
byte[] data = new byte[getBytesPerRow()];
// determine how many bytes have to be read from inflater
int numRows = getY2();
TIFFImageFileDirectory ifd = getImageFileDirectory();
if (numRows > ifd.getHeight() - 1)
{
numRows = ifd.getHeight() - 1;
}
numRows -= getY1();
int remainingBytes = numRows * data.length;
// now read and decompress as long as there is data left to decompress
while (compressedSize > 0 || remainingBytes > 0)
{
if (inflater.needsInput())
{
// read compressed data from input
int numBytes;
if (compressedSize > ioBuffer.length)
{
numBytes = ioBuffer.length;
}
else
{
numBytes = compressedSize;
}
in.readFully(ioBuffer, 0, numBytes);
// give data to inflater
inflater.setInput(ioBuffer, 0, numBytes);
compressedSize -= numBytes;
}
else
{
// determine how many bytes to decompress in this loop iteration
int numBytes;
if (remainingBytes > data.length)
{
numBytes = data.length;
}
else
{
numBytes = remainingBytes;
}
int numInflated;
// do the decompression
try
{
numInflated = inflater.inflate(data, 0, numBytes);
}
catch (DataFormatException dfe)
{
throw new InvalidFileStructureException("Error in compressed input data: " + dfe.toString());
}
// store decompressed data and update number of bytes left to decompress
if (numInflated > 0)
{
putBytes(data, 0, numInflated);
remainingBytes -= numInflated;
}
}
}
}
public Integer[] getCompressionTypes()
{
return new Integer[]
{
new Integer(TIFFConstants.COMPRESSION_DEFLATED_INOFFICIAL),
new Integer(TIFFConstants.COMPRESSION_DEFLATED_OFFICIAL)
};
}
public void initialize() throws
IOException,
MissingParameterException
{
super.initialize();
in = getInput();
compressedSize = getImageFileDirectory().getByteCount(getTileIndex());
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/tiff/TIFFDecoderUncompressed.java 0000664 0000000 0000000 00000001426 07741250131 027472 0 ustar /*
* TIFFDecoderUncompressed
*
* Copyright (c) 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.codecs.tiff;
import java.io.DataInput;
import java.io.IOException;
import net.sourceforge.jiu.codecs.tiff.TIFFDecoder;
/**
* A TIFF decoder for uncompressed TIFF files.
* @author Marco Schmidt
* @since 0.9.0
*/
public class TIFFDecoderUncompressed extends TIFFDecoder
{
public void decode() throws IOException
{
DataInput in = getInput();
byte[] row = new byte[getBytesPerRow()];
for (int y = getY1(); y <= getY2(); y++)
{
in.readFully(row);
putBytes(row, 0, row.length);
}
}
public Integer[] getCompressionTypes()
{
return new Integer[] {new Integer(TIFFConstants.COMPRESSION_NONE)};
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/tiff/package.html 0000664 0000000 0000000 00000002613 07741250131 024501 0 ustar
Classes to handle the Tagged Image File Format (TIFF).
See the TIFFCodec documentation for the
amount of support that is built into this package.
The most important class is TIFFCodec, extending the base class for image codecs, ImageCodec.
TIFFCodec reads the TIFF header, then the image file directory of the image to be loaded
(TIFF can store more than one image in a file).
The information of an image file directory is put into an object of class
TIFFImageFileDirectory.
It contains the tags of that directory (each tag is of type TIFFTag),
and the most important information of a directory can also be retrieved from the
various get methods (e.g. getCompression).
TIFF files can be stored using all kinds of compression methods.
When reading TIFFs, each supported compression method gets its own
class extending TIFFDecoder, which provides basic methods required by all
decoders (like storing decompressed data).
A TIFFCodec object that is supposed to read an image creates an appropriate TIFFDecoder
(e.g. TIFFDecoderUncompressed for compression type
* This class does all the work of storing decompressed data (given as a byte array)
* in the image object.
* Given the many variants (sample order, color depth, color space etc.) this is
* a larger portion of code.
* @author Marco Schmidt
* @since 0.7.0
*/
public abstract class TIFFDecoder
{
private TIFFCodec codec;
private TIFFImageFileDirectory ifd;
private int currentRow;
private int leftColumn;
private int rightColumn;
private int topRow;
private int bottomRow;
private byte[] rowBuffer;
private int bufferIndex;
private int tileIndex;
private int processedTileRows;
private int totalTileRows;
public TIFFDecoder()
{
tileIndex = -1;
}
/**
* Decode data from input and write the decompressed pixel data to
* the image associated with this decoder.
* Child classes must override this method to implement the decoding
* for a particular compression type.
*/
public abstract void decode() throws
InvalidFileStructureException,
IOException;
/**
* Returns the number of bytes per row for the strip or tile
* that this decoder deals with.
* So with a tiled TIFF and an image width of 500 and a tile width of 100,
* for an eight bit grayscale image this would return 100 (not 500).
* @return number of bytes per row
*/
public int getBytesPerRow()
{
return ifd.getBytesPerRow();
}
/**
* Returns the codec from which this decoder is used.
* @return TIFFCodec object using this decoder
*/
public TIFFCodec getCodec()
{
return codec;
}
/**
* Returns an array with Integer values of all compression types supported by
* this decoder (see the COMPRESSION_xyz constants in {@link TIFFConstants}.
* Normally, this is only one value, but some compression types got assigned more than one constant
* (e.g. deflated).
* Also, a decoder could be capable of dealing with more than one type of compression
* if the compression types are similar enough to justify that.
* However, typically a decoder can only deal with one type of compression.
* @return array with Integer objects of all TIFF compression constants supported by this decoder
*/
public abstract Integer[] getCompressionTypes();
/**
* Returns the IFD for the image this decoder is supposed to uncompress
* (partially).
* @return IFD object
*/
public TIFFImageFileDirectory getImageFileDirectory()
{
return ifd;
}
/**
* Returns the input stream from which this decoder is supposed
* to read data.
*/
public DataInput getInput()
{
return codec.getRandomAccessFile();
}
/**
* Returns the zero-based index of the tile or strip this decoder
* is supposed to be decompressing.
* @return tile index
*/
public int getTileIndex()
{
return tileIndex;
}
/**
* Returns the leftmost column of the image strip / tile to be read
* by this decoder.
*/
public int getX1()
{
return leftColumn;
}
/**
* Returns the rightmost column of the image strip / tile to be read
* by this decoder.
*/
public int getX2()
{
return rightColumn;
}
/**
* Returns the top row of the image strip / tile to be read
* by this decoder.
*/
public int getY1()
{
return topRow;
}
/**
* Returns the bottom row of the image strip / tile to be read
* by this decoder.
*/
public int getY2()
{
return bottomRow;
}
/**
* Check if all necessary parameters have been given to this decoder
* and initialize several internal fields from them.
* Required parameters are a TIFFCodec object, a TIFFImageFileDirectory object and
* a tile index.
*/
public void initialize() throws
IOException,
MissingParameterException
{
if (tileIndex < 0)
{
throw new MissingParameterException("Tile index was not initialized.");
}
if (codec == null)
{
throw new MissingParameterException("No TIFFCodec object was given to this decoder.");
}
if (ifd == null)
{
throw new MissingParameterException("No TIFFImageFileDirectory object was given to this decoder.");
}
RandomAccessFile raf = codec.getRandomAccessFile();
long offset = ifd.getTileOffset(tileIndex) & 0x00000000ffffffffL;
raf.seek(offset);
leftColumn = ifd.getTileX1(tileIndex);
rightColumn = ifd.getTileX2(tileIndex);
topRow = ifd.getTileY1(tileIndex);
bottomRow = ifd.getTileY2(tileIndex);
currentRow = topRow;
processedTileRows = tileIndex * ifd.getTileHeight();
totalTileRows = ifd.getTileHeight() * ifd.getNumTiles();
rowBuffer = new byte[ifd.getBytesPerRow()];
}
/**
* Adds a number of bytes to the internal row buffer.
* If the row buffer gets full (a complete line is available)
* that data will be copied to the image.
* Note that more than one line, exactly one line or only part
* of a line can be stored in the
* Note that you can write your own decoder (extending {@link TIFFDecoder}) for any compression type
* you want.
*
* Note that you can write your own decoder (extending {@link TIFFDecoder}) for any compression type
* you want.
* Writing TIFFs is not supported.
* I don't know if or when it will be supported.
* Later, the concept of tiles was added to the TIFF specs.
* Tiled TIFFs are separated into rectangles that not only had a defineable
* height but also a defineable width (tile width and tile height are also stored in
* corresponding tags).
*
* Obviously, strips are just a special case of tiles, with the tile width being equal
* to image width.
* That is why JIU internally only deals with tiles.
* The only difference: No row padding takes place for strips.
* In a tiled image with a tile height of 10 and an image height of 14,
* the image is two tiles high.
*
*
* TIFF was created by Aldus and now belongs to Adobe, who offer a specification document:
* TIFF
* (Tagged Image File Format) 6.0 Specification (updated on Web September, 20 1995,
* document dated June, 3 1992) (PDF: 385 KB / 121 pages).
*
* Other good references include the homepage
* of libtiff, a free C library to read and write TIFF files and
* The Unofficial TIFF
* homepage by Niles Ritter.
* Also see the TIFF section
* of the Open Directory.
*
* TIFF is used for various specialized tasks.
* As an example, see GeoTIFF (geographical
* data) or EXIF
* (digital camera metadata; this is actually a TIFF directory embedded in a JPEG header).
*
* Here's a list of features that make TIFF quite complex:
*
* Why this is necessary remains a mystery to me. Marco
*
* @param value the int value which may have to be adjusted
* @return the value parameter which may have been modified
*/
private int adjustInt(int value, int type)
{
if (getByteOrder() == BYTE_ORDER_MOTOROLA)
{
if (type == TAG_TYPE_BYTE)
{
return ((value >> 24) & 0xff);
}
else
if (type == TAG_TYPE_SHORT)
{
return ((value >> 16) & 0xff) | (((value >> 24) & 0xff) << 8);
}
else
{
return value;
}
}
else
{
return value;
}
}
private static TIFFDecoder createDecoder(TIFFCodec codec, TIFFImageFileDirectory ifd, int tileIndex) throws
IOException,
UnsupportedTypeException
{
Integer compression = new Integer(ifd.getCompression());
Class decoderClass = (Class)decoders.get(compression);
if (decoderClass == null)
{
throw new UnsupportedTypeException("Could not create decoder for this compression type: " +
compression.intValue());
}
Object instance;
try
{
instance = decoderClass.newInstance();
}
catch (Exception e)
{
throw new UnsupportedTypeException("Could not create decoder for this compression type.");
}
if (instance instanceof TIFFDecoder)
{
TIFFDecoder decoder = (TIFFDecoder)instance;
decoder.setCodec(codec);
decoder.setTileIndex(tileIndex);
decoder.setImageFileDirectory(ifd);
try
{
decoder.initialize();
}
catch (MissingParameterException mpe)
{
throw new UnsupportedTypeException("Unable to initialize decoder: " + mpe.toString());
}
return decoder;
}
else
{
throw new UnsupportedTypeException("Could not create decoder for this compression type.");
}
}
/**
* Returns the current byte order, either
* {@link #BYTE_ORDER_INTEL} or
* {@link #BYTE_ORDER_MOTOROLA}.
* @return current byte order
*/
public int getByteOrder()
{
return byteOrder;
}
public String getFormatName()
{
return "Tagged Image File Format (TIFF)";
}
public String[] getMimeTypes()
{
return new String[] {"image/tiff", "image/tif"};
}
/**
* Returns the name of a tag in English.
* @param id of the tag for which a name is to be returned
* @return tag name as String or a question mark
* If the format is not recognized at all, a {@link WrongFileFormatException}
* should be thrown.
*
* If the format is recognized but cannot be loaded because the codec
* does not fully support the file format, a {@link UnsupportedTypeException}
* should be thrown.
* @author Marco Schmidt
* @see UnsupportedTypeException
* @see WrongFileFormatException
*/
public class InvalidFileStructureException extends OperationFailedException
{
public InvalidFileStructureException(String message)
{
super(message);
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/PSDCodec.java 0000664 0000000 0000000 00000024626 10572432420 023526 0 ustar /*
* PSDCodec
*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.codecs;
import java.io.DataInput;
import java.io.IOException;
import net.sourceforge.jiu.codecs.ImageCodec;
import net.sourceforge.jiu.codecs.InvalidFileStructureException;
import net.sourceforge.jiu.codecs.UnsupportedTypeException;
import net.sourceforge.jiu.codecs.WrongFileFormatException;
import net.sourceforge.jiu.data.MemoryGray8Image;
import net.sourceforge.jiu.data.MemoryPaletted8Image;
import net.sourceforge.jiu.data.MemoryRGB24Image;
import net.sourceforge.jiu.data.Gray8Image;
import net.sourceforge.jiu.data.Palette;
import net.sourceforge.jiu.data.Paletted8Image;
import net.sourceforge.jiu.data.RGB24Image;
import net.sourceforge.jiu.ops.MissingParameterException;
import net.sourceforge.jiu.ops.OperationFailedException;
/**
* A codec to read images from Photoshop PSD files.
* PSD was created by Adobe for their
* Photoshop
* image editing software.
* Note that only a small subset of valid PSD files is supported by this codec.
* Typical file extension is
* Normally, an operation creates the output image itself.
* However, an output image can be specified by the user with
* {@link #setOutputImage}.
* This could be done when existing image objects are to be reused.
*
* An operation extending ImageToImageOperation must check if
* (1) a user-defined output image is available and
* (2) whether that image matches the required criteria.
* The criteria depend on the operation - example: for an operation that
* rotates an image by 180 degrees, an output image must have the same resolution
* as the input image and be of the same type.
*
* If an output image is not available (case #1), the operation must create
* the matching output image itself.
* It should know best what is required.
* Very generic methods (like rotation of images by 90 degrees) must know
* relatively little about the image.
* They can make use of PixelImage.createCompatibleImage(int, int) and provide
* width and height.
* That way, the operation works for all kinds of images, like BilevelImage,
* Paletted8Image, Gray8Image, RGB24Image etc.
*
* If a user-provided image does not match the required criteria, an appropriate
* exception (most of the time {@link WrongParameterException} will do) with a
* descriptive error message must be thrown.
* In the example of the 90-degree rotation, the width of the output image must
* be equal to the height of the input image and vice versa.
* The types of input and output must be equal.
*
* However, there are limits to the checks on user-provided output images.
* As an example, a generic test could not check if a paletted output image
* has the same palette as the input counterpart because it treats all images
* based on IntegerImage the same.
*
* When performing an image-to-image-operation, the input image can possibly be
* used as the output image.
* This can be done
*
* Mirroring the image horizontally is an example of an operation that can be
* implemented that way - the operation starts at the top left and at the bottom
* right pixel, swaps them and proceeds one pixel to the right of the top left
* pixel (and one to the left of the bottom right pixel).
*
* @author Marco Schmidt
* @since 0.6.0
*/
public abstract class ImageToImageOperation extends Operation
{
private PixelImage inputImage;
private PixelImage outputImage;
private boolean canInAndOutBeEqual;
/**
* Creates an object of this class and sets input image
* and output image to the argument values.
*/
public ImageToImageOperation(PixelImage in, PixelImage out)
{
super();
setInputImage(in);
setOutputImage(out);
canInAndOutBeEqual = false;
}
/**
* Creates an object of this class and sets the input image
* to the argument value, output image to
* Example: if there are three steps and the first one is done, the parameters
* must be 0 and 3, which will indicated 33% completion.
* Parameters 1 and 3 mean 66%, 2 and 3 100%.
* If you use 3 and 3, an IllegalArgumentException will be thrown.
*
* Computes
The operation package, with basic functionality for all JIU classes
that actually process images.
Includes the base class Operation and some extensions,
various exception types and classes for
progress notification.
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/ops/WrongParameterException.java 0000664 0000000 0000000 00000001106 10324334157 026306 0 ustar /*
* WrongParameterException
*
* Copyright (c) 2001, 2002, 2003, 2004, 2005 Marco Schmidt
* All rights reserved.
*/
package net.sourceforge.jiu.ops;
import net.sourceforge.jiu.ops.OperationFailedException;
/**
* Exception class to indicate that an operation's parameter is of the wrong
* type, does not fall into a valid interval or a similar mistake.
*
* @author Marco Schmidt
* @since 0.6.0
*/
public class WrongParameterException extends OperationFailedException
{
public WrongParameterException(String message)
{
super(message);
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/ops/Operation.java 0000664 0000000 0000000 00000014201 10500554243 023426 0 ustar /*
* Operation
*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006 Marco Schmidt
* All rights reserved.
*/
package net.sourceforge.jiu.ops;
import java.util.Vector;
import net.sourceforge.jiu.ops.MissingParameterException;
import net.sourceforge.jiu.ops.OperationFailedException;
import net.sourceforge.jiu.ops.ProgressListener;
import net.sourceforge.jiu.ops.WrongParameterException;
/**
*
* Base class for all operations.
*
* It supports progress notification.
* All classes that want to be notified by a new progress level of the operation
* (defined as value between 0.0f (nothing has been done so far) to 1.0f
* (operation finished)) must implement the {@link ProgressListener} interface.
*
* An abortion state is stored in each Operation object.
* It should be queried by a running operation from time to time
* (via {@link #getAbort()} - if it returns
* This class class contains a generic system to add parameters to an operation.
* Whether an item becomes a parameter is often unclear and must be decided by
* the operation implementor.
* As an example: one could create an image rotation class with a numerical parameter
* for the degrees of rotation.
* One could also define a class of its own for each 90, 180 and 270 degrees
* (excluding other values).
*
* The generic parameter system is insufficient in some situations.
* Example: A parameter can be defined to be of class Integer or Long, but it cannot
* be forced to be in a certain interval.
* Even if such a case could be solved by a specially-designed class, checking
* of parameters (and maybe their relations among each other) can be done by
* overriding the {@link #checkParams()} method.
* clear(0, newValue);
:
*/
void clear(int newValue);
/**
* Sets all samples of the channelIndex
'th channel to newValue
.
*/
void clear(int channelIndex, int newValue);
/**
* Returns the maximum value for one of the image's channels.
* The minimum value is always 0
.
* @param channel zero-based index of the channel, from 0
to {@link #getNumChannels()} - 1
* @return maximum allowed sample value
*/
int getMaxSample(int channel);
/**
* Returns one sample of the first channel (index 0).
* A call to this method must have the same result as the call getSample(0, x, y);
.
* @param x the horizontal position of the sample, from 0
to {@link #getWidth} - 1
* @param y the vertical position of the sample, from 0
to {@link #getHeight} - 1
* @return the desired sample
*/
int getSample(int x, int y);
/**
* Returns one sample, specified by its channel index and location.
* @param channel the number of the channel, from 0
to {@link #getNumChannels} - 1
* @param x the horizontal position of the sample, from 0
to {@link #getWidth} - 1
* @param y the vertical position of the sample, from 0
to {@link #getHeight} - 1
* @return the desired sample
*/
int getSample(int channel, int x, int y);
/**
* Copies a number of samples from this image to an int[]
object.
* A rectangular part of one channel is copied.
* The channel index is given by - the upper left corner of
* that rectangle is given by the point x / y.
* Width and height of that rectangle are given by w and h.
* Each sample will be stored as one int
value dest,
* starting at index destOffs.
* @param channelIndex zero-based index of the channel from which data is to be copied (valid values: 0 to {@link #getNumChannels()} - 1)
* @param x horizontal position of upper left corner of the rectangle to be copied
* @param y vertical position of upper left corner of the rectangle to be copied
* @param w width of rectangle to be copied
* @param h height of rectangle to be copied
* @param dest int array to which the samples will be copied
* @param destOffs int index into the dest array for the position to which the samples will be copied
*/
void getSamples(int channelIndex, int x, int y, int w, int h, int[] dest, int destOffs);
/**
* This method sets one sample of the first channel (index 0) to a new value.
* This call must have the same result as the call putSample(0, x, y)
.
* The sample location is given by the spatial coordinates, x and y.
* @param x the horizontal position of the sample, from 0
to {@link #getWidth} - 1
* @param y the vertical position of the sample, from 0
to {@link #getHeight} - 1
* @param newValue the new value of the sample
*/
void putSample(int x, int y, int newValue);
/**
* This method sets one sample to a new value.
* The sample location is given by the channel index and the spatial coordinates, x and y.
* @param channel the number of the channel, from 0
to {@link #getNumChannels} - 1
* @param x the horizontal position of the sample, from 0
to {@link #getWidth} - 1
* @param y the vertical position of the sample, from 0
to {@link #getHeight} - 1
* @param newValue the new value of the sample
*/
void putSample(int channel, int x, int y, int newValue);
/**
* Copies a number of samples from an int[]
array to this image.
* A rectangular part of one channel is copied - the upper left corner of
* that rectangle is given by the point x / y.
* Width and height of that rectangle are given by w and h.
* Each sample will be stored as one int
value src,
* starting at index srcOffset.
* @param channel int (from 0 to getNumChannels() - 1) to indicate the channel to which data is copied
* @param x horizontal position of upper left corner of the rectangle to be copied
* @param y vertical position of upper left corner of the rectangle to be copied
* @param w width of rectangle to be copied
* @param h height of rectangle to be copied
* @param src int array from which the samples will be copied
* @param srcOffset int index into the src array for the position from which the samples will be copied
*/
void putSamples(int channel, int x, int y, int w, int h, int[] src, int srcOffset);
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/data/MemoryRGB24Image.java 0000664 0000000 0000000 00000001723 07741250133 024523 0 ustar /*
* MemoryRGB24Image
*
* Copyright (c) 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.data;
import net.sourceforge.jiu.data.MemoryByteChannelImage;
import net.sourceforge.jiu.data.RGB24Image;
/**
* A class to store 24 bit RGB truecolor images in memory.
* @author Marco Schmidt
* @see RGB24Image
*/
public class MemoryRGB24Image extends MemoryByteChannelImage implements RGB24Image
{
/**
* Creates a new object of this class, with width and height as
* specified by the arguments.
* @param width the horizontal resolution of the new image in pixels
* @param height the vertical resolution of the new image in pixels
*/
public MemoryRGB24Image(int width, int height)
{
super(3, width, height);
}
public PixelImage createCompatibleImage(int width, int height)
{
return new MemoryRGB24Image(width, height);
}
public Class getImageType()
{
return RGB24Image.class;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/data/MemoryGray16Image.java 0000664 0000000 0000000 00000003204 07741250133 025010 0 ustar /*
* MemoryGray16Image
*
* Copyright (c) 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.data;
import net.sourceforge.jiu.data.Gray16Image;
import net.sourceforge.jiu.data.MemoryShortChannelImage;
import net.sourceforge.jiu.data.PixelImage;
/**
* An implementation of {@link Gray16Image} that keeps the complete image in memory.
* This class inherits most of its functionality from its parent class
* {@link MemoryShortChannelImage}, using one short
channel.
* @since 0.11.0
* @author Marco Schmidt
*/
public class MemoryGray16Image extends MemoryShortChannelImage implements Gray16Image
{
/**
* Creates a new MemoryGray16Image object with the specified resolution.
* Simply gives 1
(for one channel) and the two resolution arguments
* to the super constructor (of the parent class {@link MemoryShortChannelImage}).
* @param width the horizontal resolution, must be larger than zero
* @param height the vertical resolution, must be larger than zero
*/
public MemoryGray16Image(int width, int height)
{
super(1, width, height);
}
public PixelImage createCompatibleImage(int width, int height)
{
return new MemoryGray16Image(width, height);
}
public Class getImageType()
{
return Gray16Image.class;
}
public boolean isBlack(int x, int y)
{
return getShortSample(x, y) == 0;
}
public boolean isWhite(int x, int y)
{
return getShortSample(x, y) == (short)65535;
}
public void putBlack(int x, int y)
{
putSample(x, y, 0);
}
public void putWhite(int x, int y)
{
putSample(x, y, 65535);
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/geometry/ 0000775 0000000 0000000 00000000000 10607465453 021673 5 ustar java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/geometry/TriangleFilter.java 0000664 0000000 0000000 00000001201 07741250134 025434 0 ustar /*
* TriangleFilter
*
* Copyright (c) 2002 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.geometry;
/**
* A triangle filter (also known as linear or bilinear filter).
* @author Marco Schmidt
* @since 0.10.0
*/
public class TriangleFilter extends ResampleFilter
{
public float apply(float value)
{
if (value < 0.0f)
{
value = -value;
}
if (value < 1.0f)
{
return 1.0f - value;
}
else
{
return 0.0f;
}
}
public String getName()
{
return "Triangle (bilinear)";
}
public float getRecommendedSamplingRadius()
{
return 1.0f;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/geometry/Resample.java.old 0000664 0000000 0000000 00000052252 10332232063 025051 0 ustar /*
* Resample
*
* Copyright (c) 2001, 2002, 2003, 2004, 2005 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.geometry;
import net.sourceforge.jiu.data.PixelImage;
import net.sourceforge.jiu.data.IntegerImage;
import net.sourceforge.jiu.ops.ImageToImageOperation;
import net.sourceforge.jiu.ops.MissingParameterException;
import net.sourceforge.jiu.ops.WrongParameterException;
/* This is the beginning of resample.pas, the Unit on which this class is based:
// -----------------------------------------------------------------------------
// Project: bitmap resampler
// Module: resample
// Description: Interpolated Bitmap Resampling using filters.
// Version: 01.03
// Release: 4
// Date: 29-JUN-1999
// Target: Win32, Delphi 2, 3 & 4
// Author(s): anme: Anders Melander, anders@melander.dk
// Copyright (c) 1997-99 by Anders Melander
// Formatting: 2 space indent, 8 space tabs, 80 columns.
// -----------------------------------------------------------------------------
// This software is copyrighted as noted above. It may be freely copied,
// modified, and redistributed, provided that the copyright notice(s) is
// preserved on all copies.
//
// There is no warranty or other guarantee of fitness for this software,
// it is provided solely "as is". Bug reports or fixes may be sent
// to the author, who may or may not act on them as he desires.
//
// You may not include this software in a program or other software product
// without supplying the source, or without informing the end-user that the
// source is available for no extra charge.
//
// If you modify this software, you should include a notice in the "Revision
// history" section giving the name of the person performing the modification,
// the date of modification, and the reason for such modification.
// -----------------------------------------------------------------------------
// Here's some additional copyrights for you:
//
// From filter.c:
// The authors and the publisher hold no copyright restrictions
// on any of these files; this source code is public domain, and
// is freely available to the entire computer graphics community
// for study, use, and modification. We do request that the
// comment at the top of each file, identifying the original
// author and its original publication in the book Graphics
// Gems, be retained in all programs that use these files.
//
// -----------------------------------------------------------------------------
// Revision history:
//
// 0100 110997 anme - Adapted from Dale Schumacher's fzoom v0.20.
//
// 0101 110198 anme - Added Lanczos3 and Mitchell filters.
// - Fixed range bug.
// Min value was not checked on conversion from Single to
// byte.
// - Numerous optimizations.
// - Added TImage stretch on form resize.
// - Added support for Delphi 2 via TCanvas.Pixels.
// - Renamed module from stretch to resample.
// - Moved demo code to separate module.
//
// 0102 150398 anme - Fixed a problem that caused all pixels to be shifted
// 1/2 pixel down and to the right (in source
// coordinates). Thanks to David Ullrich for the
// solution.
//
// 0103 170898 anme - Fixed typo: Renamed Strecth function to Stretch.
// Thanks to Graham Stratford for spotting it.
// Sorry about that.
// 081298 anme - Added check for too small destination bitmap.
// Thanks to Jeppe Oland for bringing this problem to my
// attention.
// 260399 anme - Fixed a problem with resampling of very narrow
// bitmaps. Thanks to Holger Dors for bringing the
// problem to my attention.
// - Removed dependency of math unit.
// 290699 jobe - Subsampling improvements by Josha Beukema.
//
// -----------------------------------------------------------------------------
// Credits:
// The algorithms and methods used in this library are based on the article
// "General Filtered Image Rescaling" by Dale Schumacher which appeared in the
// book Graphics Gems III, published by Academic Press, Inc.
//
// The edge offset problem was fixed by:
// * David Ullrich Usage example
* This will scale image
to 150 percent of its original size
* in both directions, using the Lanczos3 filter type:
*
* Resample resample = new Resample();
* resample.setInputImage(image);
* resample.setSize(image.getWidth() * 3 / 2, image.getHeight() * 3 / 2);
* resample.setFilter(Resample.FILTER_TYPE_LANCZOS3);
* resample.process();
* PixelImage scaledImage = resample.getOutputImage();
*
*
* Known problems
*
*
*
* Origin
* This code is a port of Anders Melander's
* Object Pascal (Delphi) unit resample.pas to Java.
* The Delphi code is an adaptation (with some improvements) of
* Dale Schumacher's fzoom C code.
* Check out the homepage for the Delphi resample code, a demo application
* to compare the different filtering algorithms is also provided:
* http://www.melander.dk/delphi/resampler/index.html.
* You will also find the original C code there.
* The site seems to have gone for good.
*
* Theory
* The theoretical background for all implementations is Dale Schumacher's article
* General Filtered Image Rescaling
* in Graphics Gems III, editor David Kirk, Academic Press, pages 8-16, 1994.
* null
if none was defined yet
*/
public ResampleFilter getFilter()
{
return filter;
}
/**
* Returns the names of all predefined filters.
* Each FILTER_TYPE_xyz constant can be used as an index into the array that is returned.
* Names are retrieved by creating an object of each predefined filter class and calling its
* getName method.
* @return String array with filter names
*/
public static String[] getFilterNames()
{
String[] result = new String[getNumFilters()];
for (int i = 0; i < getNumFilters(); i++)
{
ResampleFilter filter = createFilter(i);
result[i] = filter.getName();
}
return result;
}
/**
* Returns the number of predefined filters.
* @return number of filters
*/
public static int getNumFilters()
{
return 7;
}
/**
* This method does the actual work of rescaling an image.
*/
private void process(IntegerImage in, IntegerImage out)
{
if (out == null)
{
out = (IntegerImage)in.createCompatibleImage(outWidth.intValue(), outHeight.intValue());
setOutputImage(out);
}
if (filter == null)
{
filter = new TriangleFilter();
}
float fwidth = filter.getSamplingRadius();
final int dstWidth = outWidth.intValue();
final int dstHeight = outHeight.intValue();
final int srcWidth = in.getWidth();
final int srcHeight = in.getHeight();
/* if (SrcWidth < 1) or (SrcHeight < 1) then
raise Exception.Create('Source bitmap too small');*/
// Create intermediate image to hold horizontal zoom
IntegerImage work = (IntegerImage)in.createCompatibleImage(dstWidth, srcHeight);
float xscale;
float yscale;
if (srcWidth == 1)
{
xscale = (float)dstWidth / (float)srcWidth;
}
else
{
xscale = (float)(dstWidth - 1) / (float)(srcWidth - 1);
}
if (srcHeight == 1)
{
yscale = (float)dstHeight / (float)srcHeight;
}
else
{
yscale = (float)(dstHeight - 1) / (float)(srcHeight - 1);
}
/* Marco: the following two variables are used for progress notification */
int processedItems = 0;
int totalItems = /*dstWidth +*/ srcHeight + /*dstHeight +*/ dstWidth;
// --------------------------------------------
// Pre-calculate filter contributions for a row
// -----------------------------------------------
CList[] contrib = new CList[dstWidth];
for (int i = 0; i < contrib.length; i++)
{
contrib[i] = new CList();
}
// Horizontal sub-sampling
// Scales from bigger to smaller width
if (xscale < 1.0f)
{
float width = fwidth / xscale;
float fscale = 1.0f / xscale;
int numPixels = (int)(width * 2.0f + 1);
for (int i = 0; i < dstWidth; i++)
{
contrib[i].n = 0;
contrib[i].p = new Contributor[numPixels];
for (int j = 0; j < contrib[i].p.length; j++)
{
contrib[i].p[j] = new Contributor();
}
float center = i / xscale;
int left = (int)Math.floor(center - width);
int right = (int)Math.ceil(center + width);
for (int j = left; j <= right; j++)
{
float weight = filter.apply((center - j) / fscale) / fscale;
if (weight == 0.0f)
{
continue;
}
int n;
if (j < 0)
{
n = -j;
}
else
if (j >= srcWidth)
{
n = srcWidth - j + srcWidth - 1;
}
else
{
n = j;
}
int k = contrib[i].n;
contrib[i].n = contrib[i].n + 1;
contrib[i].p[k].pixel = n;
contrib[i].p[k].weight = weight;
}
//setProgress(processedItems++, totalItems);
}
}
else
// Horizontal super-sampling
// Scales from smaller to bigger width
{
int numPixels = (int)(fwidth * 2.0f + 1);
for (int i = 0; i < dstWidth; i++)
{
contrib[i].n = 0;
contrib[i].p = new Contributor[numPixels];
for (int j = 0; j < contrib[i].p.length; j++)
{
contrib[i].p[j] = new Contributor();
}
float center = i / xscale;
int left = (int)Math.floor(center - fwidth);
int right = (int)Math.ceil(center + fwidth);
for (int j = left; j <= right; j++)
{
float weight = filter.apply(center - j);
if (weight == 0.0f)
{
continue;
}
int n;
if (j < 0)
{
n = -j;
}
else
if (j >= srcWidth)
{
n = srcWidth - j + srcWidth - 1;
}
else
{
n = j;
}
int k = contrib[i].n;
if (n < 0 || n >= srcWidth)
{
weight = 0.0f;
}
contrib[i].n = contrib[i].n + 1;
contrib[i].p[k].pixel = n;
contrib[i].p[k].weight = weight;
}
//setProgress(processedItems++, totalItems);
}
}
// ----------------------------------------------------
// Apply filter to sample horizontally from Src to Work
// ----------------------------------------------------
// start of Java-specific code
// Marco: adjusted code to work with multi-channel images
// where each channel can have a different maximum sample value (not only 255)
final int NUM_CHANNELS = work.getNumChannels();
final int[] MAX = new int[NUM_CHANNELS];
for (int k = 0; k < NUM_CHANNELS; k++)
{
MAX[k] = work.getMaxSample(k);
}
// end of Java-specific code
for (int k = 0; k < srcHeight; k++)
{
for (int i = 0; i < dstWidth; i++)
{
for (int channel = 0; channel < NUM_CHANNELS; channel++)
{
float sample = 0.0f;
for (int j = 0; j < contrib[i].n; j++)
{
float weight = contrib[i].p[j].weight;
if (weight == 0.0f)
{
continue;
}
int color = in.getSample(channel, contrib[i].p[j].pixel, k);
sample = sample + color * weight;
}
// Marco: procedure BoundRound included directly
int result = (int)sample;
if (result < 0)
{
result = 0;
}
else
if (result > MAX[channel])
{
result = MAX[channel];
}
work.putSample(channel, i, k, result);
}
}
setProgress(processedItems++, totalItems);
}
/* Marco: no need for "free memory" code as Java has garbage collection:
// Free the memory allocated for horizontal filter weights
for i := 0 to DstWidth-1 do
FreeMem(contrib^[i].p);
FreeMem(contrib);
*/
// -----------------------------------------------
// Pre-calculate filter contributions for a column
// -----------------------------------------------
/*GetMem(contrib, DstHeight* sizeof(TCList));*/
contrib = new CList[dstHeight];
for (int i = 0; i < contrib.length; i++)
{
contrib[i] = new CList();
}
// Vertical sub-sampling
// Scales from bigger to smaller height
if (yscale < 1.0f)
{
float width = fwidth / yscale;
float fscale = 1.0f / yscale;
int numContributors = (int)(width * 2.0f + 1);
for (int i = 0; i < dstHeight; i++)
{
contrib[i].n = 0;
contrib[i].p = new Contributor[numContributors];
for (int j = 0; j < contrib[i].p.length; j++)
{
contrib[i].p[j] = new Contributor();
}
float center = i / yscale;
int left = (int)Math.floor(center - width);
int right = (int)Math.ceil(center + width);
for (int j = left; j <= right; j++)
{
float weight = filter.apply((center - j) / fscale) / fscale;
// change suggested by Mike Dillon; not thoroughly tested;
// old version:
// float weight = filter.apply(center - j);
if (weight == 0.0f)
{
continue;
}
int n;
if (j < 0)
{
n = -j;
}
else
if (j >= srcHeight)
{
n = srcHeight - j + srcHeight - 1;
}
else
{
n = j;
}
int k = contrib[i].n;
contrib[i].n = contrib[i].n + 1;
if (n < 0 || n >= srcHeight)
{
weight = 0.0f;// Flag that cell should not be used
}
contrib[i].p[k].pixel = n;
contrib[i].p[k].weight = weight;
}
//setProgress(processedItems++, totalItems);
}
}
else
// Vertical super-sampling
// Scales from smaller to bigger height
{
int numContributors = (int)(fwidth * 2.0f + 1);
for (int i = 0; i < dstHeight; i++)
{
contrib[i].n = 0;
contrib[i].p = new Contributor[numContributors];
for (int j = 0; j < contrib[i].p.length; j++)
{
contrib[i].p[j] = new Contributor();
}
float center = i / yscale;
int left = (int)Math.floor(center - fwidth);
int right = (int)Math.ceil(center + fwidth);
for (int j = left; j <= right; j++)
{
float weight = filter.apply(center - j);
if (weight == 0.0f)
{
continue;
}
int n;
if (j < 0)
{
n = -j;
}
else
if (j >= srcHeight)
{
n = srcHeight - j + srcHeight - 1;
}
else
{
n = j;
}
int k = contrib[i].n;
contrib[i].n = contrib[i].n + 1;
if (n < 0 || n >= srcHeight)
{
weight = 0.0f;// Flag that cell should not be used
}
contrib[i].p[k].pixel = n;
contrib[i].p[k].weight = weight;
}
//setProgress(processedItems++, totalItems);
}
}
// --------------------------------------------------
// Apply filter to sample vertically from Work to Dst
// --------------------------------------------------
for (int k = 0; k < dstWidth; k++)
{
for (int i = 0; i < dstHeight; i++)
{
for (int channel = 0; channel < NUM_CHANNELS; channel++)
{
float sample = 0.0f;
for (int j = 0; j < contrib[i].n; j++)
{
float weight = contrib[i].p[j].weight;
if (weight == 0.0f)
{
continue;
}
float color = work.getSample(channel, k, contrib[i].p[j].pixel);
sample = sample + color * weight;
int result = (int)sample;
if (result < 0)
{
result = 0;
}
else
if (result > MAX[channel])
{
result = MAX[channel];
}
out.putSample(channel, k, i, result);
}
}
}
setProgress(processedItems++, totalItems);
}
}
public void process() throws
MissingParameterException,
WrongParameterException
{
ensureInputImageIsAvailable();
if (outWidth == null && outHeight == null && getOutputImage() != null)
{
PixelImage out = getOutputImage();
outWidth = new Integer(out.getWidth());
outHeight = new Integer(out.getHeight());
}
if (outWidth == null)
{
throw new MissingParameterException("Output width has not been initialized");
}
if (outHeight == null)
{
throw new MissingParameterException("Output height has not been initialized");
}
PixelImage image = getInputImage();
if (image.getWidth() == outWidth.intValue() &&
image.getHeight() == outHeight.intValue())
{
throw new WrongParameterException("Input image already has the size specified by setSize.");
}
ensureOutputImageResolution(outWidth.intValue(), outHeight.intValue());
if (image instanceof IntegerImage)
{
process((IntegerImage)image, (IntegerImage)getOutputImage());
}
else
{
throw new WrongParameterException("Input image must implement IntegerImage.");
}
}
/**
* Set the pixel resolution of the output image.
* @param width the horizontal resolution of the output image
* @param height the vertical resolution of the output image
*/
public void setSize(int width, int height)
{
outWidth = new Integer(width);
outHeight = new Integer(height);
}
/**
* Set a new filter object to be used with this operation.
* @param newFilter a resample filter to be used for scaling
*/
public void setFilter(ResampleFilter newFilter)
{
filter = newFilter;
}
/**
* Sets a new filter type, using the default sampling radius of that filter.
* @param filterType the new filter type, one of the FILTER_TYPE_xyz constants of this class
*/
public void setFilter(int filterType)
{
setFilter(createFilter(filterType));
}
/**
* Sets a new filter type with a user-defined sampling radius.
* @param filterType the new filter type, one of the FILTER_TYPE_xyz constants of this class
* @param samplingRadius the sampling radius to be used with that filter, must be larger than 0.0f
*/
public void setFilter(int filterType, float samplingRadius)
{
ResampleFilter newFilter = createFilter(filterType);
newFilter.setSamplingRadius(samplingRadius);
setFilter(newFilter);
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/geometry/BellFilter.java 0000664 0000000 0000000 00000001337 07741250133 024556 0 ustar /*
* BellFilter
*
* Copyright (c) 2002 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.geometry;
/**
* A Bell resample filter.
* @author Marco Schmidt
* @since 0.10.0
* @see Resample
* @see ResampleFilter
*/
public class BellFilter extends ResampleFilter
{
public float apply(float value)
{
if (value < 0.0f)
{
value = - value;
}
if (value < 0.5f)
{
return 0.75f - (value * value);
}
else
if (value < 1.5f)
{
value = value - 1.5f;
return 0.5f * (value * value);
}
else
{
return 0.0f;
}
}
public String getName()
{
return "Bell";
}
public float getRecommendedSamplingRadius()
{
return 1.5f;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/geometry/Mirror.java 0000664 0000000 0000000 00000003631 07741250133 024003 0 ustar /*
* Mirror
*
* Copyright (c) 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.geometry;
import net.sourceforge.jiu.data.IntegerImage;
import net.sourceforge.jiu.data.PixelImage;
import net.sourceforge.jiu.ops.ImageToImageOperation;
import net.sourceforge.jiu.ops.MissingParameterException;
import net.sourceforge.jiu.ops.WrongParameterException;
/**
* Mirrors images (leftmost column becomes rightmost column and vice versa, and so on).
* Usage example
*
* PixelImage image = ...; // something implementing IntegerImage
* Mirror mirror = new Mirror();
* mirror.setInputImage(image);
* mirror.process();
* PixelImage mirroredImage = mirror.getOutputImage();
*
* @author Marco Schmidt
*/
public class Mirror extends ImageToImageOperation
{
private void process(IntegerImage in, IntegerImage out)
{
final int WIDTH = in.getWidth();
final int HEIGHT = in.getHeight();
if (out == null)
{
out = (IntegerImage)in.createCompatibleImage(WIDTH, HEIGHT);
setOutputImage(out);
}
int totalItems = in.getNumChannels() * WIDTH;
int processedItems = 0;
for (int c = 0; c < in.getNumChannels(); c++)
{
for (int x1 = 0, x2 = WIDTH - 1; x1 < WIDTH; x1++, x2--)
{
for (int y = 0; y < HEIGHT; y++)
{
out.putSample(c, x2, y, in.getSample(c, x1, y));
}
setProgress(processedItems++, totalItems);
}
}
}
public void process() throws
MissingParameterException,
WrongParameterException
{
ensureInputImageIsAvailable();
ensureImagesHaveSameResolution();
PixelImage in = getInputImage();
if (in instanceof IntegerImage)
{
process((IntegerImage)in, (IntegerImage)getOutputImage());
}
else
{
throw new WrongParameterException("Input image must be of type IntegerImage.");
}
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/geometry/ResampleFilter.java 0000664 0000000 0000000 00000003740 07741250133 025450 0 ustar /*
* ResampleFilter
*
* Copyright (c) 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.geometry;
/**
* Abstract base class for filters to be used with
* the {@link Resample} operation.
* @author Marco Schmidt
* @since 0.10.0
*/
public abstract class ResampleFilter
{
private float samplingRadius;
/**
* This empty constructor sets the sampling radius to the
* recommended sampling radius as provided by
* {@link #getRecommendedSamplingRadius()}.
*/
public ResampleFilter()
{
setSamplingRadius(getRecommendedSamplingRadius());
}
/**
* Returns the weight of the sample at the distance given
* by the argument value.
*/
public abstract float apply(float value);
/**
* Return the name of this filter.
* Should avoid natural language words if possible.
* @return String with filter name
*/
public abstract String getName();
/**
* Returns a recommendation for the sampling radius to
* be used with this filter.
* This recommendation value will be the default value
* for the sampling radius of objects of this class.
* You can modify it with a call to {@link #setSamplingRadius}.
* @return the recommended sampling radius to be used with this filter
*/
public abstract float getRecommendedSamplingRadius();
/**
* Returns the sampling radius of this object.
* @see #getRecommendedSamplingRadius
* @see #setSamplingRadius
*/
public float getSamplingRadius()
{
return samplingRadius;
}
/**
* Sets the sampling radius to a new value.
* Call this method if you do not want to use the default
* radius as provided by {@link #getRecommendedSamplingRadius}.
* @param newValue new sampling radius to be used with this object
*/
public void setSamplingRadius(float newValue)
{
if (newValue <= 0.0f)
{
throw new IllegalArgumentException("Sampling radius must be larger than 0.0f.");
}
samplingRadius = newValue;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/geometry/Resample.java 0000664 0000000 0000000 00000052772 10611670474 024317 0 ustar /*
* Resample
*
* Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.geometry;
import net.sourceforge.jiu.data.PixelImage;
import net.sourceforge.jiu.data.IntegerImage;
import net.sourceforge.jiu.ops.ImageToImageOperation;
import net.sourceforge.jiu.ops.MissingParameterException;
import net.sourceforge.jiu.ops.WrongParameterException;
// 2007-04-19 optimization results
//* 10393 original speed in ms
//* 6053 innerloop fix
//* 5688 if .. continue loop break
//* 5485 replaced contrib[] array access by variable
//* 5173 doing the same on first pass (except innerloop fix which was ok there)
// global gain is 2x faster
/* This is the beginning of resample.pas, the Unit on which this class is based:
// -----------------------------------------------------------------------------
// Project: bitmap resampler
// Module: resample
// Description: Interpolated Bitmap Resampling using filters.
// Version: 01.03
// Release: 4
// Date: 29-JUN-1999
// Target: Win32, Delphi 2, 3 & 4
// Author(s): anme: Anders Melander, anders@melander.dk
// Copyright (c) 1997-99 by Anders Melander
// Formatting: 2 space indent, 8 space tabs, 80 columns.
// -----------------------------------------------------------------------------
// This software is copyrighted as noted above. It may be freely copied,
// modified, and redistributed, provided that the copyright notice(s) is
// preserved on all copies.
//
// There is no warranty or other guarantee of fitness for this software,
// it is provided solely "as is". Bug reports or fixes may be sent
// to the author, who may or may not act on them as he desires.
//
// You may not include this software in a program or other software product
// without supplying the source, or without informing the end-user that the
// source is available for no extra charge.
//
// If you modify this software, you should include a notice in the "Revision
// history" section giving the name of the person performing the modification,
// the date of modification, and the reason for such modification.
// -----------------------------------------------------------------------------
// Here's some additional copyrights for you:
//
// From filter.c:
// The authors and the publisher hold no copyright restrictions
// on any of these files; this source code is public domain, and
// is freely available to the entire computer graphics community
// for study, use, and modification. We do request that the
// comment at the top of each file, identifying the original
// author and its original publication in the book Graphics
// Gems, be retained in all programs that use these files.
//
// -----------------------------------------------------------------------------
// Revision history:
//
// 0100 110997 anme - Adapted from Dale Schumacher's fzoom v0.20.
//
// 0101 110198 anme - Added Lanczos3 and Mitchell filters.
// - Fixed range bug.
// Min value was not checked on conversion from Single to
// byte.
// - Numerous optimizations.
// - Added TImage stretch on form resize.
// - Added support for Delphi 2 via TCanvas.Pixels.
// - Renamed module from stretch to resample.
// - Moved demo code to separate module.
//
// 0102 150398 anme - Fixed a problem that caused all pixels to be shifted
// 1/2 pixel down and to the right (in source
// coordinates). Thanks to David Ullrich for the
// solution.
//
// 0103 170898 anme - Fixed typo: Renamed Strecth function to Stretch.
// Thanks to Graham Stratford for spotting it.
// Sorry about that.
// 081298 anme - Added check for too small destination bitmap.
// Thanks to Jeppe Oland for bringing this problem to my
// attention.
// 260399 anme - Fixed a problem with resampling of very narrow
// bitmaps. Thanks to Holger Dors for bringing the
// problem to my attention.
// - Removed dependency of math unit.
// 290699 jobe - Subsampling improvements by Josha Beukema.
//
// -----------------------------------------------------------------------------
// Credits:
// The algorithms and methods used in this library are based on the article
// "General Filtered Image Rescaling" by Dale Schumacher which appeared in the
// book Graphics Gems III, published by Academic Press, Inc.
//
// The edge offset problem was fixed by:
// * David Ullrich Usage example
* This will scale image
to 150 percent of its original size
* in both directions, using the Lanczos3 filter type:
*
* Resample resample = new Resample();
* resample.setInputImage(image);
* resample.setSize(image.getWidth() * 3 / 2, image.getHeight() * 3 / 2);
* resample.setFilter(Resample.FILTER_TYPE_LANCZOS3);
* resample.process();
* PixelImage scaledImage = resample.getOutputImage();
*
*
* Known problems
*
*
*
* Origin
* This code is a port of Anders Melander's
* Object Pascal (Delphi) unit resample.pas to Java.
* The Delphi code is an adaptation (with some improvements) of
* Dale Schumacher's fzoom C code.
* Check out the homepage for the Delphi resample code, a demo application
* to compare the different filtering algorithms is also provided:
* http://www.melander.dk/delphi/resampler/index.html.
* You will also find the original C code there.
* The site seems to have gone for good.
*
* Theory
* The theoretical background for all implementations is Dale Schumacher's article
* General Filtered Image Rescaling
* in Graphics Gems III, editor David Kirk, Academic Press, pages 8-16, 1994.
* null
if none was defined yet
*/
public ResampleFilter getFilter()
{
return filter;
}
/**
* Returns the names of all predefined filters.
* Each FILTER_TYPE_xyz constant can be used as an index into the array that is returned.
* Names are retrieved by creating an object of each predefined filter class and calling its
* getName method.
* @return String array with filter names
*/
public static String[] getFilterNames()
{
String[] result = new String[getNumFilters()];
for (int i = 0; i < getNumFilters(); i++)
{
ResampleFilter filter = createFilter(i);
result[i] = filter.getName();
}
return result;
}
/**
* Returns the number of predefined filters.
* @return number of filters
*/
public static int getNumFilters()
{
return 7;
}
/**
* This method does the actual work of rescaling an image.
*/
private void process(IntegerImage in, IntegerImage out)
{
if (out == null)
{
out = (IntegerImage)in.createCompatibleImage(outWidth.intValue(), outHeight.intValue());
setOutputImage(out);
}
if (filter == null)
{
filter = new TriangleFilter();
}
float fwidth = filter.getSamplingRadius();
final int dstWidth = outWidth.intValue();
final int dstHeight = outHeight.intValue();
final int srcWidth = in.getWidth();
final int srcHeight = in.getHeight();
/* if (SrcWidth < 1) or (SrcHeight < 1) then
raise Exception.Create('Source bitmap too small');*/
// Create intermediate image to hold horizontal zoom
IntegerImage work = (IntegerImage)in.createCompatibleImage(dstWidth, srcHeight);
float xscale;
float yscale;
if (srcWidth == 1)
{
xscale = (float)dstWidth / (float)srcWidth;
}
else
{
xscale = (float)(dstWidth - 1) / (float)(srcWidth - 1);
}
if (srcHeight == 1)
{
yscale = (float)dstHeight / (float)srcHeight;
}
else
{
yscale = (float)(dstHeight - 1) / (float)(srcHeight - 1);
}
/* Marco: the following two variables are used for progress notification */
int processedItems = 0;
int totalItems = /*dstWidth +*/ srcHeight + /*dstHeight +*/ dstWidth;
// --------------------------------------------
// Pre-calculate filter contributions for a row
// -----------------------------------------------
CList[] contrib = new CList[dstWidth];
for (int i = 0; i < contrib.length; i++)
{
contrib[i] = new CList();
}
// Horizontal sub-sampling
// Scales from bigger to smaller width
if (xscale < 1.0f)
{
float width = fwidth / xscale;
float fscale = 1.0f / xscale;
int numPixels = (int)(width * 2.0f + 1);
for (int i = 0; i < dstWidth; i++)
{
contrib[i].n = 0;
contrib[i].p = new Contributor[numPixels];
for (int j = 0; j < contrib[i].p.length; j++)
{
contrib[i].p[j] = new Contributor();
}
float center = i / xscale;
int left = (int)Math.floor(center - width);
int right = (int)Math.ceil(center + width);
for (int j = left; j <= right; j++)
{
float weight = filter.apply((center - j) / fscale) / fscale;
if (weight == 0.0f)
{
continue;
}
int n;
if (j < 0)
{
n = -j;
}
else
if (j >= srcWidth)
{
n = srcWidth - j + srcWidth - 1;
}
else
{
n = j;
}
int k = contrib[i].n;
contrib[i].n = contrib[i].n + 1;
contrib[i].p[k].pixel = n;
contrib[i].p[k].weight = weight;
}
//setProgress(processedItems++, totalItems);
}
}
else
// Horizontal super-sampling
// Scales from smaller to bigger width
{
int numPixels = (int)(fwidth * 2.0f + 1);
for (int i = 0; i < dstWidth; i++)
{
contrib[i].n = 0;
contrib[i].p = new Contributor[numPixels];
for (int j = 0; j < contrib[i].p.length; j++)
{
contrib[i].p[j] = new Contributor();
}
float center = i / xscale;
int left = (int)Math.floor(center - fwidth);
int right = (int)Math.ceil(center + fwidth);
for (int j = left; j <= right; j++)
{
float weight = filter.apply(center - j);
if (weight == 0.0f)
{
continue;
}
int n;
if (j < 0)
{
n = -j;
}
else
if (j >= srcWidth)
{
n = srcWidth - j + srcWidth - 1;
}
else
{
n = j;
}
int k = contrib[i].n;
if (n < 0 || n >= srcWidth)
{
weight = 0.0f;
}
contrib[i].n = contrib[i].n + 1;
contrib[i].p[k].pixel = n;
contrib[i].p[k].weight = weight;
}
//setProgress(processedItems++, totalItems);
}
}
// ----------------------------------------------------
// Apply filter to sample horizontally from Src to Work
// ----------------------------------------------------
// start of Java-specific code
// Marco: adjusted code to work with multi-channel images
// where each channel can have a different maximum sample value (not only 255)
final int NUM_CHANNELS = work.getNumChannels();
final int[] MAX = new int[NUM_CHANNELS];
for (int k = 0; k < NUM_CHANNELS; k++)
{
MAX[k] = work.getMaxSample(k);
}
// end of Java-specific code
for (int k = 0; k < srcHeight; k++)
{
for (int i = 0; i < dstWidth; i++)
{
for (int channel = 0; channel < NUM_CHANNELS; channel++)
{
CList c=contrib[i];
float sample = 0.0f;
int max=c.n;
for (int j = 0; j < max; j++)
{
sample+=in.getSample(channel, c.p[j].pixel, k) * c.p[j].weight;
}
// Marco: procedure BoundRound included directly
int result = (int)sample;
if (result < 0)
{
result = 0;
}
else
if (result > MAX[channel])
{
result = MAX[channel];
}
work.putSample(channel, i, k, result);
}
}
setProgress(processedItems++, totalItems);
}
/* Marco: no need for "free memory" code as Java has garbage collection:
// Free the memory allocated for horizontal filter weights
for i := 0 to DstWidth-1 do
FreeMem(contrib^[i].p);
FreeMem(contrib);
*/
// -----------------------------------------------
// Pre-calculate filter contributions for a column
// -----------------------------------------------
/*GetMem(contrib, DstHeight* sizeof(TCList));*/
contrib = new CList[dstHeight];
for (int i = 0; i < contrib.length; i++)
{
contrib[i] = new CList();
}
// Vertical sub-sampling
// Scales from bigger to smaller height
if (yscale < 1.0f)
{
float width = fwidth / yscale;
float fscale = 1.0f / yscale;
int numContributors = (int)(width * 2.0f + 1);
for (int i = 0; i < dstHeight; i++)
{
contrib[i].n = 0;
contrib[i].p = new Contributor[numContributors];
for (int j = 0; j < contrib[i].p.length; j++)
{
contrib[i].p[j] = new Contributor();
}
float center = i / yscale;
int left = (int)Math.floor(center - width);
int right = (int)Math.ceil(center + width);
for (int j = left; j <= right; j++)
{
float weight = filter.apply((center - j) / fscale) / fscale;
// change suggested by Mike Dillon; not thoroughly tested;
// old version:
// float weight = filter.apply(center - j);
if (weight == 0.0f)
{
continue;
}
int n;
if (j < 0)
{
n = -j;
}
else
if (j >= srcHeight)
{
n = srcHeight - j + srcHeight - 1;
}
else
{
n = j;
}
int k = contrib[i].n;
contrib[i].n = contrib[i].n + 1;
if (n < 0 || n >= srcHeight)
{
weight = 0.0f;// Flag that cell should not be used
}
contrib[i].p[k].pixel = n;
contrib[i].p[k].weight = weight;
}
//setProgress(processedItems++, totalItems);
}
}
else
// Vertical super-sampling
// Scales from smaller to bigger height
{
int numContributors = (int)(fwidth * 2.0f + 1);
for (int i = 0; i < dstHeight; i++)
{
contrib[i].n = 0;
contrib[i].p = new Contributor[numContributors];
for (int j = 0; j < contrib[i].p.length; j++)
{
contrib[i].p[j] = new Contributor();
}
float center = i / yscale;
int left = (int)Math.floor(center - fwidth);
int right = (int)Math.ceil(center + fwidth);
for (int j = left; j <= right; j++)
{
float weight = filter.apply(center - j);
if (weight == 0.0f)
{
continue;
}
int n;
if (j < 0)
{
n = -j;
}
else
if (j >= srcHeight)
{
n = srcHeight - j + srcHeight - 1;
}
else
{
n = j;
}
int k = contrib[i].n;
contrib[i].n = contrib[i].n + 1;
if (n < 0 || n >= srcHeight)
{
weight = 0.0f;// Flag that cell should not be used
}
contrib[i].p[k].pixel = n;
contrib[i].p[k].weight = weight;
}
//setProgress(processedItems++, totalItems);
}
}
// --------------------------------------------------
// Apply filter to sample vertically from Work to Dst
// --------------------------------------------------
for (int k = 0; k < dstWidth; k++)
{
for (int i = 0; i < dstHeight; i++)
{
for (int channel = 0; channel < NUM_CHANNELS; channel++)
{
float sample = 0.0f;
CList c=contrib[i];
int max=c.n;
for (int j = 0; j < max; j++)
{
sample += work.getSample(channel, k, c.p[j].pixel) * c.p[j].weight;
}
int result = (int)sample;
if (result < 0)
{
result = 0;
}
else
if (result > MAX[channel])
{
result = MAX[channel];
}
out.putSample(channel, k, i, result);
}
}
setProgress(processedItems++, totalItems);
}
}
public void process() throws
MissingParameterException,
WrongParameterException
{
ensureInputImageIsAvailable();
if (outWidth == null && outHeight == null && getOutputImage() != null)
{
PixelImage out = getOutputImage();
outWidth = new Integer(out.getWidth());
outHeight = new Integer(out.getHeight());
}
if (outWidth == null)
{
throw new MissingParameterException("Output width has not been initialized");
}
if (outHeight == null)
{
throw new MissingParameterException("Output height has not been initialized");
}
PixelImage image = getInputImage();
if (image.getWidth() == outWidth.intValue() &&
image.getHeight() == outHeight.intValue())
{
throw new WrongParameterException("Input image already has the size specified by setSize.");
}
ensureOutputImageResolution(outWidth.intValue(), outHeight.intValue());
if (image instanceof IntegerImage)
{
process((IntegerImage)image, (IntegerImage)getOutputImage());
}
else
{
throw new WrongParameterException("Input image must implement IntegerImage.");
}
}
/**
* Set the pixel resolution of the output image.
* @param width the horizontal resolution of the output image
* @param height the vertical resolution of the output image
*/
public void setSize(int width, int height)
{
outWidth = new Integer(width);
outHeight = new Integer(height);
}
/**
* Set a new filter object to be used with this operation.
* @param newFilter a resample filter to be used for scaling
*/
public void setFilter(ResampleFilter newFilter)
{
filter = newFilter;
}
/**
* Sets a new filter type, using the default sampling radius of that filter.
* @param filterType the new filter type, one of the FILTER_TYPE_xyz constants of this class
*/
public void setFilter(int filterType)
{
setFilter(createFilter(filterType));
}
/**
* Sets a new filter type with a user-defined sampling radius.
* @param filterType the new filter type, one of the FILTER_TYPE_xyz constants of this class
* @param samplingRadius the sampling radius to be used with that filter, must be larger than 0.0f
*/
public void setFilter(int filterType, float samplingRadius)
{
ResampleFilter newFilter = createFilter(filterType);
newFilter.setSamplingRadius(samplingRadius);
setFilter(newFilter);
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/geometry/BoxFilter.java 0000664 0000000 0000000 00000001132 07741250133 024421 0 ustar /*
* BoxFilter
*
* Copyright (c) 2002 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.geometry;
/**
* A box filter (also known as nearest neighbor).
* @author Marco Schmidt
* @since 0.10.0
* @see Resample
* @see ResampleFilter
*/
public class BoxFilter extends ResampleFilter
{
public float apply(float value)
{
if (value > -0.5f && value <= 0.5f)
{
return 1.0f;
}
else
{
return 0.0f;
}
}
public String getName()
{
return "Box";
}
public float getRecommendedSamplingRadius()
{
return 0.5f;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/geometry/HermiteFilter.java 0000664 0000000 0000000 00000001236 07741250133 025273 0 ustar /*
* HermiteFilter
*
* Copyright (c) 2002 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.geometry;
/**
* A Hermite resampling filter.
* @author Marco Schmidt
* @since 0.10.0
* @see Resample
* @see ResampleFilter
*/
public class HermiteFilter extends ResampleFilter
{
public float apply(float value)
{
if (value < 0.0f)
{
value = - value;
}
if (value < 1.0f)
{
return (2.0f * value - 3.0f) * value * value + 1.0f;
}
else
{
return 0.0f;
}
}
public String getName()
{
return "Hermite";
}
public float getRecommendedSamplingRadius()
{
return 1.0f;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/geometry/ScaleReplication.java 0000664 0000000 0000000 00000006471 10377272144 025764 0 ustar /*
* ScaleReplication
*
* Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.geometry;
import net.sourceforge.jiu.data.PixelImage;
import net.sourceforge.jiu.data.IntegerImage;
import net.sourceforge.jiu.ops.ImageToImageOperation;
import net.sourceforge.jiu.ops.MissingParameterException;
import net.sourceforge.jiu.ops.WrongParameterException;
/**
* Changes the pixel resolution of an image by replicating (or dropping) pixels.
* A fast but low quality scaling algorithm that works with all kinds
* of image types.
* {@link Resample} provides better quality, but is slower and works with
* intensity-based image data types only.
*
* Usage example
*
* The input image will be scaled to an image that is twice as wide as
* itself and three times as high.
*
*
* ScaleReplication scale = new ScaleReplication();
* scale.setInputImage(image); // something implementing IntegerImage
* scale.setSize(image.getWidth() * 2, image.getHeight() * 2);
* scale.process();
* PixelImage scaledImage = scale.getOutputImage();
*
* @author Marco Schmidt
*/
public class ScaleReplication extends ImageToImageOperation
{
private Integer outWidth;
private Integer outHeight;
private void process(IntegerImage in, IntegerImage out)
{
if (out == null)
{
out = (IntegerImage)in.createCompatibleImage(outWidth.intValue(), outHeight.intValue());
setOutputImage(out);
}
int IN_MAX_X = in.getWidth() - 1;
int IN_MAX_Y = in.getHeight() - 1;
int OUT_WIDTH = outWidth.intValue();
int OUT_HEIGHT = outHeight.intValue();
for (int y = 0; y < OUT_HEIGHT; y++)
{
final int SRC_Y = (int)(IN_MAX_Y * (y + 1) / OUT_HEIGHT);
for (int x = 0; x < OUT_WIDTH; x++)
{
final int SRC_X = (int)(IN_MAX_X * (x + 1) / OUT_WIDTH);
for (int c = 0; c < in.getNumChannels(); c++)
{
out.putSample(c, x, y, in.getSample(c, SRC_X, SRC_Y));
}
}
setProgress(y, OUT_HEIGHT);
}
}
public void process() throws
MissingParameterException,
WrongParameterException
{
PixelImage pin = getInputImage();
if (pin == null)
{
throw new MissingParameterException("Input image object missing.");
}
if (!(pin instanceof IntegerImage))
{
throw new WrongParameterException("ScaleReplication only works on IntegerImage objects.");
}
if (outWidth == null)
{
throw new MissingParameterException("Output width value missing.");
}
if (outHeight == null)
{
throw new MissingParameterException("Output height value missing.");
}
ensureImagesHaveSameResolution();
process((IntegerImage)pin, (IntegerImage)getOutputImage());
}
/**
* Specify the resolution to be used for the image to be created.
* @param width horizontal resolution of the new image
* @param height vertical resolution of the new image
* @throws IllegalArgumentException if any of the arguments is smaller than 1
*/
public void setSize(int width, int height)
{
if (width < 1)
{
throw new IllegalArgumentException("Output width must be larger than 0.");
}
if (height < 1)
{
throw new IllegalArgumentException("Output height must be larger than 0.");
}
outWidth = new Integer(width);
outHeight = new Integer(height);
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/geometry/MitchellFilter.java 0000664 0000000 0000000 00000002123 07741250133 025433 0 ustar /*
* MitchellFilter
*
* Copyright (c) 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.geometry;
/**
* The Mitchell resample filter.
* @author Marco Schmidt
* @since 0.10.0
* @see Resample
* @see ResampleFilter
*/
public class MitchellFilter extends ResampleFilter
{
private final float B = 1.0f / 3.0f;
private final float C = 1.0f / 3.0f;
public float apply(float value)
{
if (value < 0.0f)
{
value = -value;
}
float tt = value * value;
if (value < 1.0f)
{
value = (((12.0f - 9.0f * B - 6.0f * C) * (value * tt))
+ ((-18.0f + 12.0f * B + 6.0f * C) * tt)
+ (6.0f - 2f * B));
return value / 6.0f;
}
else
if (value < 2.0f)
{
value = (((-1.0f * B - 6.0f * C) * (value * tt))
+ ((6.0f * B + 30.0f * C) * tt)
+ ((-12.0f * B - 48.0f * C) * value)
+ (8.0f * B + 24 * C));
return value / 6.0f;
}
else
{
return 0.0f;
}
}
public String getName()
{
return "Mitchell";
}
public float getRecommendedSamplingRadius()
{
return 2.0f;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/geometry/Flip.java 0000664 0000000 0000000 00000003544 07741250133 023426 0 ustar /*
* Flip
*
* Copyright (c) 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.geometry;
import net.sourceforge.jiu.data.PixelImage;
import net.sourceforge.jiu.data.IntegerImage;
import net.sourceforge.jiu.ops.ImageToImageOperation;
import net.sourceforge.jiu.ops.MissingParameterException;
import net.sourceforge.jiu.ops.WrongParameterException;
/**
* Flips images (top row becomes bottom row and vice versa, and so on).
*
* Flip flip = new Flip();
* flip.setInputImage(image); // image is some IntegerImage object
* flip.process();
* PixelImage flippedImage = flip.getOutputImage();
*
* @author Marco Schmidt
*/
public class Flip extends ImageToImageOperation
{
private void process(IntegerImage in, IntegerImage out)
{
final int WIDTH = in.getWidth();
final int HEIGHT = in.getHeight();
final int TOTAL_ITEMS = in.getNumChannels() * HEIGHT;
if (out == null)
{
out = (IntegerImage)in.createCompatibleImage(WIDTH, HEIGHT);
setOutputImage(out);
}
int processedItems = 0;
for (int c = 0; c < in.getNumChannels(); c++)
{
for (int y1 = 0, y2 = HEIGHT - 1; y1 < HEIGHT; y1++, y2--)
{
for (int x = 0; x < WIDTH; x++)
{
out.putSample(c, x, y2, in.getSample(c, x, y1));
}
setProgress(processedItems++, TOTAL_ITEMS);
}
}
}
public void process() throws
MissingParameterException,
WrongParameterException
{
ensureInputImageIsAvailable();
ensureImagesHaveSameResolution();
PixelImage in = getInputImage();
if (in instanceof IntegerImage)
{
process((IntegerImage)in, (IntegerImage)getOutputImage());
}
else
{
throw new WrongParameterException("Input image must be of type IntegerImage.");
}
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/geometry/Crop.java 0000664 0000000 0000000 00000012063 07741250133 023433 0 ustar /*
* Crop
*
* Copyright (c) 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.geometry;
import net.sourceforge.jiu.data.PixelImage;
import net.sourceforge.jiu.data.IntegerImage;
import net.sourceforge.jiu.ops.ImageToImageOperation;
import net.sourceforge.jiu.ops.MissingParameterException;
import net.sourceforge.jiu.ops.WrongParameterException;
/**
* Copies a rectangular area of one image to another image that is exactly as large
* as that rectangular area.
* Works with all image data classes implementing {@link net.sourceforge.jiu.data.IntegerImage}.
* Make sure to use zero-based parameters when defining the bounds with
* {@link #setBounds}!
* Usage example
* In this example we assume that the input image is larger than 20 pixels in both directions.
* Ten pixels will be removed from any of its four borders.
*
* PixelImage image = ...; // something implementing IntegerImage
* Crop crop = new Crop();
* crop.setInputImage(image);
* crop.setBounds(10, 10, image.getWidth() - 9, image.getHeight() - 9);
* crop.process();
* PixelImage croppedImage = crop.getOutputImage();
*
* @author Marco Schmidt
*/
public class Crop extends ImageToImageOperation
{
private int x1;
private int y1;
private int x2;
private int y2;
private void checkBounds() throws WrongParameterException
{
PixelImage in = getInputImage();
if (x1 >= in.getWidth())
{
throw new WrongParameterException("x1 must be smaller than input image width.");
}
if (x2 >= in.getWidth())
{
throw new WrongParameterException("x2 must be smaller than input image width.");
}
if (y1 >= in.getHeight())
{
throw new WrongParameterException("y1 must be smaller than input image height.");
}
if (y2 >= in.getHeight())
{
throw new WrongParameterException("y2 must be smaller than input image height.");
}
}
private void process(IntegerImage in, IntegerImage out)
{
final int OUT_WIDTH = x2 - x1 + 1;
final int OUT_HEIGHT = y2 - y1 + 1;
if (out == null)
{
out = (IntegerImage)in.createCompatibleImage(OUT_WIDTH, OUT_HEIGHT);
setOutputImage(out);
}
int totalItems = in.getNumChannels() * OUT_HEIGHT;
int processedItems = 0;
for (int c = 0; c < in.getNumChannels(); c++)
{
for (int yfrom = y1, yto = 0; yto < OUT_HEIGHT; yfrom++, yto++)
{
for (int xfrom = x1, xto = 0; xto < OUT_WIDTH; xfrom++, xto++)
{
out.putSample(c, xto, yto, in.getSample(c, xfrom, yfrom));
}
setProgress(processedItems++, totalItems);
}
}
}
public void process() throws
MissingParameterException,
WrongParameterException
{
ensureInputImageIsAvailable();
checkBounds();
ensureOutputImageResolution(x2 - x1 + 1, y2 - y1 + 1);
if (getInputImage() instanceof IntegerImage)
{
process((IntegerImage)getInputImage(), (IntegerImage)getOutputImage());
}
else
{
throw new WrongParameterException("Input image must implement IntegerImage.");
}
}
/**
* Specify the rectangular section of the original image that is to be
* copied to the output image by this operation.
* Note that the arguments are not checked directly against any input image that may have
* been provided to this Crop object, that checking is done later in {@link #process()}.
* If any of the arguments provided here are outside of the input image's resolution
* (e.g. x1 == 100 although the input image's width is only 60), a
* {@link net.sourceforge.jiu.ops.WrongParameterException} will be thrown from
* within {@link #process()}.
* Usage example
*
* Rotate180 rotate = new Rotate180();
* rotate.setInputImage(image); // something implementing IntegerImage
* rotate.process();
* PixelImage rotatedImage = rotate.getOutputImage();
*
* @author Marco Schmidt
*/
public class Rotate180 extends ImageToImageOperation
{
private void process(IntegerImage in, IntegerImage out)
{
final int WIDTH = in.getWidth();
final int HEIGHT = in.getHeight();
if (out == null)
{
out = (IntegerImage)in.createCompatibleImage(WIDTH, HEIGHT);
setOutputImage(out);
}
int totalItems = in.getNumChannels() * HEIGHT;
int processedItems = 0;
for (int c = 0; c < in.getNumChannels(); c++)
{
for (int y1 = 0, y2 = HEIGHT - 1; y1 < HEIGHT; y1++, y2--)
{
for (int x1 = 0, x2 = WIDTH - 1; x1 < WIDTH; x1++, x2--)
{
out.putSample(c, x2, y2, in.getSample(c, x1, y1));
}
setProgress(processedItems++, totalItems);
}
}
}
public void process() throws
MissingParameterException,
WrongParameterException
{
ensureInputImageIsAvailable();
ensureImagesHaveSameResolution();
PixelImage image = getInputImage();
if (image instanceof IntegerImage)
{
process((IntegerImage)image, (IntegerImage)getOutputImage());
}
else
{
throw new WrongParameterException("Input image must implement IntegerImage.");
}
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/geometry/BSplineFilter.java 0000664 0000000 0000000 00000001451 07741250133 025231 0 ustar /*
* BSplineFilter
*
* Copyright (c) 2002 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.geometry;
/**
* A B-spline resample filter.
* @author Marco Schmidt
* @since 0.10.0
* @see Resample
* @see ResampleFilter
*/
public class BSplineFilter extends ResampleFilter
{
public float apply(float value)
{
if (value < 0.0f)
{
value = - value;
}
if (value < 1.0f)
{
float tt = value * value;
return 0.5f * tt * value - tt + (2.0f / 3.0f);
}
else
if (value < 2.0f)
{
value = 2.0f - value;
return (1.0f / 6.0f) * value * value * value;
}
else
{
return 0.0f;
}
}
public String getName()
{
return "B-Spline";
}
public float getRecommendedSamplingRadius()
{
return 2.0f;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/geometry/package.html 0000664 0000000 0000000 00000000444 07741250133 024146 0 ustar
Usage example
*
* Shear shear = new Shear();
* shear.setInputImage(image); // some IntegerImage
* shear.setAngle(5.0);
* shear.process();
* PixelImage shearedImage = shear.getOutputImage();
*
* Usage example
*
* Rotate90Left rotate = new Rotate90Left();
* rotate.setInputImage(image);
* rotate.process();
* PixelImage rotatedImage = rotate.getOutputImage();
*
* @author Marco Schmidt
*/
public class Rotate90Left extends ImageToImageOperation
{
private void process(IntegerImage in, IntegerImage out)
{
final int WIDTH = in.getWidth();
final int HEIGHT = in.getHeight();
if (out == null)
{
out = (IntegerImage)in.createCompatibleImage(HEIGHT, WIDTH);
setOutputImage(out);
}
int totalItems = in.getNumChannels() * HEIGHT;
int processedItems = 0;
for (int c = 0; c < in.getNumChannels(); c++)
{
for (int y = 0; y < HEIGHT; y++)
{
for (int x = 0; x < WIDTH; x++)
{
out.putSample(c, y, (WIDTH - x - 1), in.getSample(c, x, y));
}
setProgress(processedItems++, totalItems);
}
}
}
public void process() throws
MissingParameterException,
WrongParameterException
{
ensureInputImageIsAvailable();
PixelImage in = getInputImage();
ensureOutputImageResolution(in.getHeight(), in.getWidth());
if (in instanceof IntegerImage)
{
process((IntegerImage)in, (IntegerImage)getOutputImage());
}
else
{
throw new WrongParameterException("Input image must implement IntegerImage.");
}
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/geometry/Rotate90Right.java 0000664 0000000 0000000 00000003566 07741250134 025146 0 ustar /*
* Rotate90Right
*
* Copyright (c) 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.geometry;
import net.sourceforge.jiu.data.PixelImage;
import net.sourceforge.jiu.data.IntegerImage;
import net.sourceforge.jiu.ops.ImageToImageOperation;
import net.sourceforge.jiu.ops.MissingParameterException;
import net.sourceforge.jiu.ops.WrongParameterException;
/**
* Rotates images by 90 degrees clockwise (to the right).
* Input image must implement {@link net.sourceforge.jiu.data.IntegerImage}.
* Usage example
*
* Rotate90Right rotate = new Rotate90Right();
* rotate.setInputImage(image);
* rotate.process();
* PixelImage rotatedImage = rotate.getOutputImage();
*
* @author Marco Schmidt
*/
public class Rotate90Right extends ImageToImageOperation
{
private void process(IntegerImage in, IntegerImage out)
{
final int WIDTH = in.getWidth();
final int HEIGHT = in.getHeight();
if (out == null)
{
out = (IntegerImage)in.createCompatibleImage(HEIGHT, WIDTH);
setOutputImage(out);
}
int totalItems = in.getNumChannels() * HEIGHT;
int processedItems = 0;
for (int c = 0; c < in.getNumChannels(); c++)
{
for (int y = 0; y < HEIGHT; y++)
{
for (int x = 0; x < WIDTH; x++)
{
out.putSample(c, (HEIGHT - y - 1), x, in.getSample(c, x, y));
}
setProgress(processedItems++, totalItems);
}
}
}
public void process() throws
MissingParameterException,
WrongParameterException
{
ensureInputImageIsAvailable();
PixelImage in = getInputImage();
ensureOutputImageResolution(in.getHeight(), in.getWidth());
if (in instanceof IntegerImage)
{
process((IntegerImage)in, (IntegerImage)getOutputImage());
}
else
{
throw new WrongParameterException("Input image must implement IntegerImage.");
}
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/ 0000775 0000000 0000000 00000000000 10546532076 021276 5 ustar java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/PCDCodec.java 0000664 0000000 0000000 00000040744 10523755460 023515 0 ustar /*
* PCDCodec
*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.codecs;
import java.io.IOException;
import java.io.RandomAccessFile;
import net.sourceforge.jiu.codecs.ImageCodec;
import net.sourceforge.jiu.codecs.InvalidFileStructureException;
import net.sourceforge.jiu.codecs.UnsupportedTypeException;
import net.sourceforge.jiu.codecs.WrongFileFormatException;
import net.sourceforge.jiu.color.YCbCrIndex;
import net.sourceforge.jiu.color.conversion.PCDYCbCrConversion;
import net.sourceforge.jiu.data.Gray8Image;
import net.sourceforge.jiu.data.IntegerImage;
import net.sourceforge.jiu.data.MemoryGray8Image;
import net.sourceforge.jiu.data.MemoryRGB24Image;
import net.sourceforge.jiu.data.RGB24Image;
import net.sourceforge.jiu.ops.MissingParameterException;
import net.sourceforge.jiu.ops.OperationFailedException;
import net.sourceforge.jiu.util.ArrayRotation;
import net.sourceforge.jiu.util.ArrayScaling;
/**
* A codec to read Kodak Photo-CD (image pac) image files.
* Typical file extension is .pcd
.
* PCD is designed to store the same image in several resolutions.
* Not all resolutions are always present in a file.
* Typically, the first five resolutions are available and the file size
* is between four and six megabytes.
* Lossless compression (Huffman encoding) is used to store the higher resolution images.
* All images are in 24 bit YCbCr colorspace, with a component subsampling of 4:1:1 (Y:Cb:Cr)
* in both horizontal and vertical direction.
* Limitations
* Only the lowest three resolutions are supported by this codec.
* Sample PCD files
* You can download sample PCD image files from
* Kodak's
* website.
*
* @author Marco Schmidt
*/
public class PCDCodec extends ImageCodec implements YCbCrIndex
{
/**
* Base/16, the minimum pixel resolution, 192 x 128 pixels.
*/
public static final int PCD_RESOLUTION_1 = 0;
/**
* Base/4, the second pixel resolution, 384 x 256 pixels.
*/
public static final int PCD_RESOLUTION_2 = 1;
/**
* Base, the third pixel resolution, 768 x 512 pixels.
*/
public static final int PCD_RESOLUTION_3 = 2;
/**
* Base*4, the fourth pixel resolution, 1536 x 1024 pixels. Unsupported
*/
public static final int PCD_RESOLUTION_4 = 3;
/**
* Base*16, the fifth pixel resolution, 3072 x 2048 pixels. Unsupported
*/
public static final int PCD_RESOLUTION_5 = 4;
/**
* Base*64, the sixth pixel resolution, 6144 x 4096 pixels. Unsupported
*/
public static final int PCD_RESOLUTION_6 = 5;
/**
* Index for the default resolution , Base ({@link #PCD_RESOLUTION_3}).
*/
public static final int PCD_RESOLUTION_DEFAULT = PCD_RESOLUTION_3;
/**
* This two-dimensional int array holds all possible pixel resolutions for
* a PCD file. Use one of the PCD resolution constants (e.g.
* {@link #PCD_RESOLUTION_3} as first index.
* The second index must be 0 or 1 and leads to either width or
* height.
* Example: PCD_RESOLUTION[PCD_RESOLUTION_3][1]
will evalute
* as 512, which can be width or height, depending on the image being
* in landscape or portrait mode.
* You may want to use these resolution values in your program
* to prompt the user which resolution to load from the file.
*/
public static final int[][] PCD_RESOLUTIONS =
{{192, 128}, {384, 256}, {768, 512},
{1536, 1024}, {3072, 2048}, {6144, 4096}};
// offsets into the file for the three uncompressed resolutions
private static final long[] PCD_FILE_OFFSETS =
{0x2000, 0xb800, 0x30000};
/*private static final long[] PCD_BASE_LENGTH =
{0x2000, 0xb800, 0x30000};*/
// some constants to understand the orientation of an image
private static final int NO_ROTATION = 0;
private static final int ROTATE_90_LEFT = 1;
private static final int ROTATE_180 = 2;
private static final int ROTATE_90_RIGHT = 3;
// 2048 bytes
private static final int SECTOR_SIZE = 0x800;
// "PCD_IPI"
private static final byte[] MAGIC =
{0x50, 0x43, 0x44, 0x5f, 0x49, 0x50, 0x49};
private boolean performColorConversion;
private boolean monochrome;
private int numChannels;
private int resolutionIndex;
private RandomAccessFile in;
private byte[][] data;
/**
* This constructor chooses the default settings for PCD image loading:
*
*
*/
public PCDCodec()
{
super();
setColorConversion(true);
setMonochrome(false);
setResolutionIndex(PCD_RESOLUTION_DEFAULT);
}
private byte[][] allocateMemory()
{
int numPixels = PCD_RESOLUTIONS[resolutionIndex][0] *
PCD_RESOLUTIONS[resolutionIndex][1];
byte[][] result = new byte[numChannels][];
for (int i = 0; i < numChannels; i++)
{
result[i] = new byte[numPixels];
}
return result;
}
/*private void checkByteArray(
byte[][] data,
int numPixels) throws IllegalArgumentException
{
// check if array is non-null
if (data == null)
{
throw new IllegalArgumentException("Error: Image channel array is not initialized.");
}
// check if array has enough entries
int channels;
if (monochrome)
{
channels = 1;
if (data.length < 1)
{
throw new IllegalArgumentException("Error: Image channel " +
"array must have at least one channel for monochrome " +
"images.");
}
}
else
{
channels = 3;
if (data.length < 3)
{
throw new IllegalArgumentException("Error: Image channel " +
"array must have at least three channels for color images.");
}
}
// check if each channel has enough entries for the samples
for (int i = 0; i < channels; i++)
{
if (data[i].length < numPixels)
{
throw new IllegalArgumentException("Error: Image channel #" + i +
" is not large enough (" + numPixels + " entries required, " +
data[i].length + " found).");
}
}
}*/
private void convertToRgb(int width, int height)
{
byte[] red = new byte[width];
byte[] green = new byte[width];
byte[] blue = new byte[width];
int offset = 0;
for (int y = 0; y < height; y++)
{
PCDYCbCrConversion.convertYccToRgb(
data[INDEX_Y],
data[INDEX_CB],
data[INDEX_CR],
offset,
red,
green,
blue,
0,
width);
System.arraycopy(red, 0, data[0], offset, width);
System.arraycopy(green, 0, data[1], offset, width);
System.arraycopy(blue, 0, data[2], offset, width);
offset += width;
}
}
private IntegerImage createImage(int width, int height)
{
if (monochrome)
{
Gray8Image image = new MemoryGray8Image(width, height);
int offset = 0;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
image.putByteSample(0, x, y, data[0][offset++]);
}
}
return image;
}
else
if (performColorConversion)
{
RGB24Image image = new MemoryRGB24Image(width, height);
int offset = 0;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
image.putByteSample(RGB24Image.INDEX_RED, x, y, data[0][offset]);
image.putByteSample(RGB24Image.INDEX_GREEN, x, y, data[1][offset]);
image.putByteSample(RGB24Image.INDEX_BLUE, x, y, data[2][offset]);
offset++;
}
}
return image;
}
else
{
return null;
}
}
public String[] getFileExtensions()
{
return new String[] {".pcd"};
}
public String getFormatName()
{
return "Kodak Photo-CD (PCD)";
}
public String[] getMimeTypes()
{
return new String[] {"image/x-pcd"};
}
public boolean isLoadingSupported()
{
return true;
}
public boolean isSavingSupported()
{
return false;
}
/**
* Attempts to load an image.
* The codec must have been given an input stream, all other
* parameters (do not convert color to RGB, load monochrome channel
* only, load other resolution than default) can optionally be
* chosen by calling the corresponding methods.
*
* @return loaded image
* @throws IOException if there were reading errors
* @throws OutOfMemoryException if there was not enough free memory
* available
* @throws InvalidFileStructureException if the file seems to be a PCD
* stream but has logical errors in it
* @throws WrongFileFormatException if this is not a PCD file
*/
private void load() throws
InvalidFileStructureException,
IOException,
UnsupportedTypeException,
WrongFileFormatException
{
if (resolutionIndex != PCD_RESOLUTION_1 &&
resolutionIndex != PCD_RESOLUTION_2 &&
resolutionIndex != PCD_RESOLUTION_3)
{
throw new UnsupportedTypeException("Error reading PCD input " +
"stream. Only the three lowest resolutions are supported.");
}
if (in == null)
{
throw new IllegalArgumentException("Input file is missing " +
"(use PCDCodec.setInput(RandomAccessFile).");
}
if (in.length() < 16 * 1024)
{
throw new WrongFileFormatException("Not a PCD file.");
}
byte[] sector = new byte[SECTOR_SIZE];
// read first sector; first 7 bytes must be 0xff
in.readFully(sector);
for (int i = 0; i < 7; i++)
{
if (sector[i] != -1)
{
throw new WrongFileFormatException("Input is not a valid PCD " +
"file (wrong magic byte sequence).");
}
}
// read second sector and check more magic bytes
in.readFully(sector);
for (int i = 0; i < MAGIC.length; i++)
{
if (sector[i] != MAGIC[i])
{
throw new WrongFileFormatException("Input is not a valid PCD " +
"file (wrong magic byte sequence).");
}
}
// get image orientation and resolution
int rotationAngle = sector[0x602] & 0x03;
int width = PCD_RESOLUTIONS[resolutionIndex][0];
int height = PCD_RESOLUTIONS[resolutionIndex][1];
int realWidth = width;
int realHeight = height;
if (rotationAngle == ROTATE_90_LEFT || rotationAngle == ROTATE_90_RIGHT)
{
realWidth = height;
realHeight = width;
}
if (!hasBounds())
{
setBounds(0, 0, realWidth - 1, realHeight - 1);
}
// determine which uncompressed image will be loaded
int uncompressedResolution = resolutionIndex;
if (resolutionIndex > PCD_RESOLUTION_3)
{
uncompressedResolution = PCD_RESOLUTION_3;
}
// load uncompressed image
data = allocateMemory();
loadUncompressedImage(uncompressedResolution);
// reverse color subsampling if necessary
if (!monochrome)
{
ArrayScaling.scaleUp200Percent(data[INDEX_CB],
PCD_RESOLUTIONS[uncompressedResolution][0] / 2,
PCD_RESOLUTIONS[uncompressedResolution][1] / 2);
ArrayScaling.scaleUp200Percent(data[INDEX_CR],
PCD_RESOLUTIONS[uncompressedResolution][0] / 2,
PCD_RESOLUTIONS[uncompressedResolution][1] / 2);
}
// TODO load higher resolution by decoding differences to uncompressed image
// ...
// convert to RGB color space if possible and desired
if ((!monochrome) && performColorConversion)
{
convertToRgb(width, height);
}
// rotate the image if necessary
rotateArrays(rotationAngle, width, height);
// adjust width and height
if (rotationAngle == ROTATE_90_LEFT || rotationAngle == ROTATE_90_RIGHT)
{
int temp = width;
width = height;
height = temp;
}
setImage(createImage(width, height));
}
/**
* Loads one of the three lowest resolution images from the file.
* First skips as many bytes as there are between the current
* stream offset and the offset of the image in the PCD file
* (first three images are at fixed positions).
* Then reads the pixels from in to data.
* width
times height
* samples for Y, but only one fourth that many samples for each Cb and Cr
* (because of the 4:1:1 subsampling of the two chroma components).
* true
, and you should only change this
* if you really know what you are doing.
* If you simply want the luminance (gray) channel, use
* {@link #setMonochrome(boolean)} with true
as parameter.
* @param performColorConversion boolean that determines whether color conversion is applied
*/
public void setColorConversion(boolean performColorConversion)
{
this.performColorConversion = performColorConversion;
}
public void setFile(String fileName, CodecMode codecMode) throws
IOException,
UnsupportedCodecModeException
{
if (codecMode == CodecMode.LOAD)
{
setRandomAccessFile(new RandomAccessFile(fileName, "r"), CodecMode.LOAD);
}
else
{
throw new UnsupportedCodecModeException("This PCD codec can only load images.");
}
}
/**
* Specifies whether the image is to be loaded as gray or color image.
* If argument is true, only the gray channel is loaded.
*/
public void setMonochrome(boolean monochrome)
{
this.monochrome = monochrome;
if (monochrome)
{
numChannels = 1;
}
else
{
numChannels = 3;
}
}
public void setResolutionIndex(int resolutionIndex)
{
this.resolutionIndex = resolutionIndex;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/PNGCodec.java 0000664 0000000 0000000 00000161277 10523756402 023535 0 ustar /*
* PNGCodec
*
* Copyright (c) 2003, 2004, 2005, 2006 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.codecs;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.SimpleTimeZone;
import java.util.zip.CheckedInputStream;
import java.util.zip.Deflater;
import java.util.zip.InflaterInputStream;
import java.util.zip.CRC32;
import net.sourceforge.jiu.data.BilevelImage;
import net.sourceforge.jiu.data.Gray16Image;
import net.sourceforge.jiu.data.Gray8Image;
import net.sourceforge.jiu.data.IntegerImage;
import net.sourceforge.jiu.data.MemoryBilevelImage;
import net.sourceforge.jiu.data.MemoryGray16Image;
import net.sourceforge.jiu.data.MemoryGray8Image;
import net.sourceforge.jiu.data.MemoryPaletted8Image;
import net.sourceforge.jiu.data.MemoryRGB24Image;
import net.sourceforge.jiu.data.MemoryRGB48Image;
import net.sourceforge.jiu.data.Palette;
import net.sourceforge.jiu.data.Paletted8Image;
import net.sourceforge.jiu.data.PixelImage;
import net.sourceforge.jiu.data.RGB24Image;
import net.sourceforge.jiu.data.RGB48Image;
import net.sourceforge.jiu.data.RGBIndex;
import net.sourceforge.jiu.ops.MissingParameterException;
import net.sourceforge.jiu.ops.OperationFailedException;
import net.sourceforge.jiu.util.ArrayConverter;
/**
* An input stream that reads from an underlying stream of PNG
* IDAT chunks and skips all header information.
* PNG uses one or more IDAT chunks to store image data.
* The resulting stream looks like that:
* IDAT [chunk size] [compressed data] [checksum]
* IDAT [chunk size] [compressed data] [checksum] ...
* This stream class expects an input stream where the first IDAT chunk name and chunk
* size have been read already, the stream is thus pointing to the
* first byte of the first [compressed data] section.
* The size of that section is given to the constructor.
* This class then returns calls to read(), counts the bytes it has given
* away and, whenever a compressed data section has been consumed, it reads
* the IDAT chunk and stores its size, using it to determine when the
* next compressed data section will end.
* That way, for the caller the stream appears to be one large compressed
* section.
*
* (Multiple IDAT chunks are allowed so that encoders can work in a fixed
* amount of memory; typically the chunk size will correspond to the encoder's
* buffer size.)
*
* 4.1.3. IDAT Image data
* Usage examples
* Load an image
* The following example code loads an image from a PNG file.
* Note that you could also use {@link ImageLoader} or {@link net.sourceforge.jiu.gui.awt.ToolkitLoader}
* which require only a single line of code and can load all formats
* supported by JIU, including PNG.
* PNGCodec codec = new PNGCodec();
* codec.setFile("image.png", CodecMode.LOAD);
* codec.process();
* PixelImage image = codec.getImage();
* Save an image
* PNGCodec codec = new PNGCodec();
* codec.setFile("out.png", CodecMode.SAVE);
* codec.setImage(image);
* codec.setCompressionLevel(Deflater.BEST_COMPRESSION);
* codec.appendComment("Copyright (c) 1992 John Doe");
* // sets last modification time to current time
* codec.setModification(new GregorianCalendar(
* new SimpleTimeZone(0, "UTC")));
* codec.process();
* Supported storage order types
* Loading
* This codec reads both non-interlaced and Adam7 interlaced PNG files.
* Saving
* This codec only writes non-interlaced PNG files.
* Supported color types
* Loading
*
*
* Saving
*
*
* Transparency information
* PNG allows to store different types of transparency information.
* Full alpha channels, transparent index values, and more.
* Right now, this JIU codec does not make use of this information and simply
* skips over it when encountered.
* Bounds
* This codec regards the bounds concept.
* If bounds are specified with {@link #setBounds}, the codec will only load or save
* part of an image.
* Metadata
* Loading
*
*
* pHYs
chunks.
* Use {@link #getDpiX} and {@link #getDpiY} to retrieve that information.
* after the call to {@link #process}.tEXt
chunks and can be retrieved
* with {@link #getComment} after the call to {@link #process}.Saving
*
*
* pHYs
chunk.tEXt
chunks.
* The keyword used is Comment
.
* Each of the {@link #getNumComments} is stored in a chunk of its own.tIME
chunk.
* Use {@link #setModification(Calendar)} to give a point in time to this codec.Implementation details
* This class relies heavily on the Java runtime library for decompression and
* checksum creation.
* Background
* To learn more about the PNG file format, visit its
* official homepage.
* There you can find a detailed specification,
* test images and existing PNG libraries and PNG-aware applications.
* The book PNG - The Definitive Guide by Greg Roelofs, published by O'Reilly, 1999,
* ISBN 1-56592-542-4 is a valuable source of information on PNG.
* It is out of print, but it can be viewed online and downloaded for offline reading
* in its entirety from the site.
* @author Marco Schmidt
* @since 0.12.0
*/
public class PNGCodec extends ImageCodec
{
private final int CHUNK_CRC32_IEND = 0xae426082;
private final int CHUNK_SIZE_IHDR = 0x0000000d;
private final int CHUNK_TYPE_IDAT = 0x49444154;
private final int CHUNK_TYPE_IEND = 0x49454e44;
private final int CHUNK_TYPE_IHDR = 0x49484452;
private final int CHUNK_TYPE_PHYS = 0x70485973;
private final int CHUNK_TYPE_PLTE = 0x504c5445;
private final int CHUNK_TYPE_TEXT = 0x74455874;
private final int CHUNK_TYPE_TIME = 0x74494d45;
private final int COLOR_TYPE_GRAY = 0;
private final int COLOR_TYPE_GRAY_ALPHA = 4;
private final int COLOR_TYPE_INDEXED = 3;
private final int COLOR_TYPE_RGB = 2;
private final int COLOR_TYPE_RGB_ALPHA = 6;
private final int COLOR_TYPE_ALPHA = 4;
private final int FILTER_TYPE_NONE = 0;
private final int FILTER_TYPE_SUB = 1;
private final int FILTER_TYPE_UP = 2;
private final int FILTER_TYPE_AVERAGE = 3;
private final int FILTER_TYPE_PAETH = 4;
private final int COMPRESSION_DEFLATE = 0;
private final int INTERLACING_NONE = 0;
private final int INTERLACING_ADAM7 = 1;
private final int FILTERING_ADAPTIVE = 0;
private final int MAX_TEXT_SIZE = 512;
private final int ADAM7_NUM_PASSES = 7;
private final int DEFAULT_ENCODING_MIN_IDAT_SIZE = 32 * 1024;
private final int[] ADAM7_COLUMN_INCREMENT = {8, 8, 4, 4, 2, 2, 1};
private final int[] ADAM7_FIRST_COLUMN = {0, 4, 0, 2, 0, 1, 0};
private final int[] ADAM7_FIRST_ROW = {0, 0, 4, 0, 2, 0, 1};
private final int[] ADAM7_ROW_INCREMENT = {8, 8, 8, 4, 4, 2, 2};
private final byte[] MAGIC_BYTES =
{(byte)0x89, (byte)0x50, (byte)0x4e, (byte)0x47,
(byte)0x0d, (byte)0x0a, (byte)0x1a, (byte)0x0a};
private boolean alpha;
private byte[][] buffers;
private int bpp;
private CRC32 checksum;
private CheckedInputStream checkedIn;
private int chunkCounter;
private int colorType;
private int compressionType;
private int currentBufferIndex;
private int deflateLevel = Deflater.DEFAULT_COMPRESSION;
private int deflateStrategy = Deflater.DEFAULT_STRATEGY;
private int encodingMinIdatSize = DEFAULT_ENCODING_MIN_IDAT_SIZE;
private int filterType;
private boolean hasIhdr;
private int height;
private IntegerImage image;
private DataInputStream in;
private InflaterInputStream infl;
private int interlaceType;
private Calendar modification;
private int numChannels;
private DataOutput out;
private Palette palette;
private int precision;
private int previousBufferIndex;
private int width;
/**
* Allocates the right image to private field image
,
* taking into consideration the fields width, height, precision and colorType.
* Assumes that an IHDR chunk has been read and the above mentioned
* fields have been initialized and checked for their validity.
*/
private void allocateImage() throws InvalidFileStructureException, UnsupportedTypeException
{
setBoundsIfNecessary(width, height);
int w = getBoundsWidth();
int h = getBoundsHeight();
if (colorType == COLOR_TYPE_GRAY || colorType == COLOR_TYPE_GRAY_ALPHA)
{
if (precision == 1)
{
image = new MemoryBilevelImage(w, h);
}
else
if (precision <= 8)
{
image = new MemoryGray8Image(w, h);
}
else
if (precision == 16)
{
image = new MemoryGray16Image(w, h);
}
}
else
if (colorType == COLOR_TYPE_INDEXED)
{
if (palette == null)
{
throw new InvalidFileStructureException("No palette found when trying to load indexed image.");
}
image = new MemoryPaletted8Image(w, h, palette);
}
else
if (colorType == COLOR_TYPE_RGB || colorType == COLOR_TYPE_RGB_ALPHA)
{
if (precision == 8)
{
image = new MemoryRGB24Image(w, h);
}
else
{
image = new MemoryRGB48Image(w, h);
}
}
else
{
throw new UnsupportedTypeException("Unsupported image type encountered");
}
}
/**
* Checks values {@link #precision} and {@link #colorType}.
* A lot of combinations possibly found in an IHDR chunk
* are invalid.
* Also initializes {@link #alpha} and {@link #numChannels}.
* @throws UnsupportedTypeException if an invalid combination
* of precision and colorType is found
*/
private void checkColorTypeAndPrecision() throws UnsupportedTypeException
{
if (colorType != COLOR_TYPE_GRAY &&
colorType != COLOR_TYPE_RGB &&
colorType != COLOR_TYPE_INDEXED &&
colorType != COLOR_TYPE_GRAY_ALPHA &&
colorType != COLOR_TYPE_RGB_ALPHA)
{
throw new UnsupportedTypeException("Not a valid color type: " + colorType);
}
if (precision != 1 && precision != 2 && precision != 4 && precision != 8 && precision != 16)
{
throw new UnsupportedTypeException("Invalid precision value: " + precision);
}
if (colorType == COLOR_TYPE_INDEXED && precision > 8)
{
throw new UnsupportedTypeException("More than eight bits of precision are not allowed for indexed images.");
}
if (colorType == COLOR_TYPE_RGB && precision < 8)
{
throw new UnsupportedTypeException("Less than eight bits of precision are not allowed for RGB images.");
}
alpha = (colorType & COLOR_TYPE_ALPHA) != 0;
if (colorType == COLOR_TYPE_RGB ||
colorType == COLOR_TYPE_RGB_ALPHA)
{
numChannels = 3;
}
else
{
numChannels = 1;
}
bpp = computeBytesPerRow(1);
}
/**
* Computes a number of bytes for a given number of pixels,
* regarding precision and availability of an alpha channel.
* @param numPixels the number of pixels for which the number
* of bytes necessary to store them is to be computed
* @return number of bytes
*/
private int computeBytesPerRow(int numPixels)
{
if (precision < 8)
{
return (numPixels + ((8 / precision) - 1)) / (8 / precision);
}
else
{
return (numChannels + (alpha ? 1 : 0)) * (precision / 8) * numPixels;
}
}
private int computeColumnsAdam7(int pass)
{
switch(pass)
{
case(0): return (width + 7) / 8;
case(1): return (width + 3) / 8;
case(2): return (width + 3) / 4;
case(3): return (width + 1) / 4;
case(4): return (width + 1) / 2;
case(5): return width / 2;
case(6): return width;
default: throw new IllegalArgumentException("Not a valid pass index: " + pass);
}
}
private void fillRowBuffer(int y, byte[] row, int offs)
{
PixelImage image = getImage();
int x1 = getBoundsX1();
int w = getBoundsWidth();
if (image instanceof BilevelImage)
{
BilevelImage bilevelImage = (BilevelImage)image;
bilevelImage.getPackedBytes(x1, y, w, row, offs, 0);
}
else
if (image instanceof Gray16Image)
{
Gray16Image grayImage = (Gray16Image)image;
while (w-- > 0)
{
short sample = grayImage.getShortSample(x1++, y);
ArrayConverter.setShortBE(row, offs, sample);
offs += 2;
}
}
else
if (image instanceof Gray8Image)
{
Gray8Image grayImage = (Gray8Image)image;
grayImage.getByteSamples(0, getBoundsX1(), y, getBoundsWidth(), 1, row, offs);
}
else
if (image instanceof Paletted8Image)
{
Paletted8Image palImage = (Paletted8Image)image;
palImage.getByteSamples(0, getBoundsX1(), y, getBoundsWidth(), 1, row, offs);
}
else
if (image instanceof RGB24Image)
{
RGB24Image rgbImage = (RGB24Image)image;
while (w-- > 0)
{
row[offs++] = rgbImage.getByteSample(RGBIndex.INDEX_RED, x1, y);
row[offs++] = rgbImage.getByteSample(RGBIndex.INDEX_GREEN, x1, y);
row[offs++] = rgbImage.getByteSample(RGBIndex.INDEX_BLUE, x1, y);
x1++;
}
}
else
if (image instanceof RGB48Image)
{
RGB48Image rgbImage = (RGB48Image)image;
while (w-- > 0)
{
short sample = rgbImage.getShortSample(RGBIndex.INDEX_RED, x1, y);
ArrayConverter.setShortBE(row, offs, sample);
offs += 2;
sample = rgbImage.getShortSample(RGBIndex.INDEX_GREEN, x1, y);
ArrayConverter.setShortBE(row, offs, sample);
offs += 2;
sample = rgbImage.getShortSample(RGBIndex.INDEX_BLUE, x1, y);
ArrayConverter.setShortBE(row, offs, sample);
offs += 2;
x1++;
}
}
}
/**
* Creates a four-letter String from the parameter, an int
* value, supposed to be storing a chunk name.
* @return the chunk name
*/
private static String getChunkName(int chunk)
{
StringBuffer result = new StringBuffer(4);
for (int i = 24; i >= 0; i -= 8)
{
result.append((char)((chunk >> i) & 0xff));
}
return result.toString();
}
public String getFormatName()
{
return "Portable Network Graphics (PNG)";
}
public String[] getMimeTypes()
{
return new String[] {"image/png"};
}
private static int getPaeth(byte l, byte u, byte nw)
{
int a = l & 0xff;
int b = u & 0xff;
int c = nw & 0xff;
int p = a + b - c;
int pa = p - a;
if (pa < 0)
{
pa = -pa;
}
int pb = p - b;
if (pb < 0)
{
pb = -pb;
}
int pc = p - c;
if (pc < 0)
{
pc = -pc;
}
if (pa <= pb && pa <= pc)
{
return a;
}
if (pb <= pc)
{
return b;
}
return c;
}
private void inflateBytes(byte[] buffer, int numBytes) throws InvalidFileStructureException, IOException
{
int offset = 0;
do
{
try
{
int toRead = numBytes - offset;
int numRead = infl.read(buffer, offset, toRead);
if (numRead < 0)
{
throw new InvalidFileStructureException("Cannot fill buffer");
}
offset += numRead;
}
catch (IOException ioe)
{
throw new InvalidFileStructureException("Stopped decompressing " + ioe.toString());
}
}
while (offset != numBytes);
}
public boolean isLoadingSupported()
{
return true;
}
public boolean isSavingSupported()
{
return true;
}
private void load() throws
InvalidFileStructureException,
IOException,
UnsupportedTypeException,
WrongFileFormatException
{
byte[] magic = new byte[MAGIC_BYTES.length];
in.readFully(magic);
for (int i = 0; i < MAGIC_BYTES.length; i++)
{
if (magic[i] != MAGIC_BYTES[i])
{
throw new WrongFileFormatException("Not a valid PNG input " +
"stream, wrong magic byte sequence.");
}
}
chunkCounter = 0;
do
{
loadChunk();
chunkCounter++;
}
while (image == null);
close();
setImage(image);
}
private void loadChunk() throws InvalidFileStructureException, IOException, UnsupportedTypeException
{
/*
* read chunk size; according to the PNG specs, the size value must not be larger
* than 2^31 - 1; to be safe, we treat the value as an unsigned
* 32 bit value anyway
*/
long chunkSize = in.readInt() & 0xffffffffL;
checksum.reset();
int chunkName = in.readInt();
// first chunk must be IHDR
if (chunkCounter == 0 && chunkName != CHUNK_TYPE_IHDR)
{
throw new InvalidFileStructureException("First chunk was not IHDR but " + getChunkName(chunkName));
}
switch (chunkName)
{
// image data chunk
case(CHUNK_TYPE_IDAT):
{
loadImage(chunkSize);
break;
}
// end of image chunk
case(CHUNK_TYPE_IEND):
{
throw new InvalidFileStructureException("Reached IEND chunk but could not load image.");
}
case(CHUNK_TYPE_IHDR):
{
if (hasIhdr)
{
throw new InvalidFileStructureException("More than one IHDR chunk found.");
}
if (chunkCounter != 0)
{
throw new InvalidFileStructureException("IHDR chunk must be first; found to be chunk #" + (chunkCounter + 1));
}
if (chunkSize != CHUNK_SIZE_IHDR)
{
throw new InvalidFileStructureException("Expected PNG " +
"IHDR chunk length to be " + CHUNK_SIZE_IHDR + ", got " +
chunkSize + ".");
}
hasIhdr = true;
loadImageHeader();
break;
}
case(CHUNK_TYPE_PHYS):
{
if (chunkSize == 9)
{
byte[] phys = new byte[9];
in.readFully(phys);
int x = ArrayConverter.getIntBE(phys, 0);
int y = ArrayConverter.getIntBE(phys, 4);
if (phys[8] == 1)
{
// unit is meters
final double INCHES_PER_METER = 100 / 2.54;
setDpi((int)(x / INCHES_PER_METER), (int)(y / INCHES_PER_METER));
}
}
else
{
skip(chunkSize);
}
break;
}
case(CHUNK_TYPE_PLTE):
{
if ((chunkSize % 3) != 0)
{
throw new InvalidFileStructureException("Not a valid palette chunk size: " + chunkSize);
}
loadPalette(chunkSize / 3);
break;
}
case(CHUNK_TYPE_TEXT):
{
if (chunkSize == 0)
{
}
else
if (chunkSize > MAX_TEXT_SIZE)
{
skip(chunkSize);
}
else
{
StringBuffer text = new StringBuffer((int)chunkSize);
int i = 0;
char c;
do
{
c = (char)in.read();
if (c == 0)
{
skip(chunkSize - i - 1);
break;
}
text.append(c);
i++;
}
while (i < chunkSize);
//System.out.println("text=\"" + text.toString() + "\"");
}
break;
}
default:
{
skip(chunkSize);
}
}
int createdChecksum = (int)checksum.getValue();
if (image == null)
{
// this code doesn't work anymore if we have just read an image
int chunkChecksum = in.readInt();
if (createdChecksum != chunkChecksum)
{
throw new InvalidFileStructureException("Checksum created on chunk " +
getChunkName(chunkName) + " " + Integer.toHexString(createdChecksum) +
" is not equal to checksum read from stream " +
Integer.toHexString(chunkChecksum) +
"; file is corrupted.");
}
}
}
/**
* Load an image from the current position in the file.
* Assumes the last things read from input are an IDAT chunk type and
* its size, which is the sole argument of this method.
* @param chunkSize size of the IDAT chunk that was just read
* @throws InvalidFileStructureException if there are values in the PNG stream that make it invalid
* @throws IOException if there were I/O errors when reading
* @throws UnsupportedTypeException if something was encountered in the stream that is valid but not supported by this codec
*/
private void loadImage(long chunkSize) throws InvalidFileStructureException, IOException, UnsupportedTypeException
{
// allocate two byte buffers for current and previous row
buffers = new byte[2][];
int numBytes = computeBytesPerRow(width);
currentBufferIndex = 0;
previousBufferIndex = 1;
buffers[currentBufferIndex] = new byte[numBytes];
buffers[previousBufferIndex] = new byte[numBytes];
for (int i = 0; i < buffers[previousBufferIndex].length; i++)
{
buffers[previousBufferIndex][i] = (byte)0;
}
// allocate the correct type of image object for the image type read in the IHDR chunk
allocateImage();
// create a PngIdatInputStream which will skip header information when
// multiple IDAT chunks are in the input stream
infl = new InflaterInputStream(new PngIdatInputStream(in, chunkSize));
switch(interlaceType)
{
case(INTERLACING_NONE):
{
loadImageNonInterlaced();
break;
}
case(INTERLACING_ADAM7):
{
loadImageInterlacedAdam7();
break;
}
}
}
/**
* Reads data from an IHDR chunk and initializes private fields with it.
* Does a lot of checking if read values are valid and supported by this class.
* @throws IOException
* @throws InvalidFileStructureException
* @throws UnsupportedTypeException
*/
private void loadImageHeader() throws IOException, InvalidFileStructureException, UnsupportedTypeException
{
// WIDTH -- horizontal resolution
width = in.readInt();
if (width < 1)
{
throw new InvalidFileStructureException("Width must be larger than 0; got " + width);
}
// HEIGHT -- vertical resolution
height = in.readInt();
if (height < 1)
{
throw new InvalidFileStructureException("Height must be larger than 0; got " + height);
}
// PRECISION -- bits per sample
precision = in.read();
// COLOR TYPE -- indexed, paletted, grayscale, optionally alpha
colorType = in.read();
// check for invalid combinations of color type and precision
// and initialize alpha and numChannels
checkColorTypeAndPrecision();
// COMPRESSION TYPE -- only Deflate is defined
compressionType = in.read();
if (compressionType != COMPRESSION_DEFLATE)
{
throw new UnsupportedTypeException("Unsupported compression type: " +
compressionType + ".");
}
// FILTER TYPE -- only Adaptive is defined
filterType = in.read();
if (filterType != FILTERING_ADAPTIVE)
{
throw new UnsupportedTypeException("Only 'adaptive filtering' is supported right now; got " + filterType);
}
// INTERLACE TYPE -- order of storage of image data
interlaceType = in.read();
if (interlaceType != INTERLACING_NONE &&
interlaceType != INTERLACING_ADAM7)
{
throw new UnsupportedTypeException("Only 'no interlacing' and 'Adam7 interlacing' are supported; got " + interlaceType);
}
}
private void loadImageInterlacedAdam7() throws InvalidFileStructureException, IOException, UnsupportedTypeException
{
final int TOTAL_LINES = ADAM7_NUM_PASSES * height;
for (int pass = 0; pass < ADAM7_NUM_PASSES; pass++)
{
currentBufferIndex = 0;
previousBufferIndex = 1;
byte[] previousBuffer = buffers[previousBufferIndex];
for (int x = 0; x < previousBuffer.length; x++)
{
previousBuffer[x] = 0;
}
int y = ADAM7_FIRST_ROW[pass];
int destY = y - getBoundsY1();
int numColumns = computeColumnsAdam7(pass);
if (numColumns == 0)
{
// this pass contains no data; skip to next pass
setProgress((pass + 1) * height, TOTAL_LINES);
continue;
}
int numBytes = computeBytesPerRow(numColumns);
while (y < height)
{
previousBuffer = buffers[previousBufferIndex];
byte[] currentBuffer = buffers[currentBufferIndex];
int rowFilterType = readFilterType();
inflateBytes(currentBuffer, numBytes);
reverseFilter(rowFilterType, currentBuffer, previousBuffer, numBytes);
if (isRowRequired(y))
{
storeInterlacedAdam7(pass, destY, currentBuffer);
}
int progressY = y;
if (pass > 0)
{
progressY += pass * height;
}
setProgress(progressY, TOTAL_LINES);
y += ADAM7_ROW_INCREMENT[pass];
destY += ADAM7_ROW_INCREMENT[pass];
currentBufferIndex = 1 - currentBufferIndex;
previousBufferIndex = 1 - previousBufferIndex;
}
}
}
private void loadImageNonInterlaced() throws InvalidFileStructureException, IOException, UnsupportedTypeException
{
int linesToRead = getBoundsY2() + 1;
int rowLength = computeBytesPerRow(width);
for (int y = 0, destY = - getBoundsY1(); y <= getBoundsY2(); y++, destY++)
{
byte[] currentBuffer = buffers[currentBufferIndex];
byte[] previousBuffer = buffers[previousBufferIndex];
int rowFilterType = readFilterType();
inflateBytes(currentBuffer, rowLength);
reverseFilter(rowFilterType, currentBuffer, previousBuffer, rowLength);
if (isRowRequired(y))
{
storeNonInterlaced(destY, currentBuffer);
}
setProgress(y, linesToRead);
previousBufferIndex = 1 - previousBufferIndex;
currentBufferIndex = 1 - currentBufferIndex;
}
}
private void loadPalette(long numEntries) throws InvalidFileStructureException, IOException
{
if (palette != null)
{
throw new InvalidFileStructureException("More than one palette in input stream.");
}
if (numEntries < 1)
{
throw new InvalidFileStructureException("Number of palette entries must be at least 1.");
}
if (numEntries > 256)
{
throw new InvalidFileStructureException("Number of palette entries larger than 256: " + numEntries);
}
palette = new Palette((int)numEntries);
int index = 0;
do
{
palette.putSample(Palette.INDEX_RED, index, in.read() & 0xff);
palette.putSample(Palette.INDEX_GREEN, index, in.read() & 0xff);
palette.putSample(Palette.INDEX_BLUE, index, in.read() & 0xff);
index++;
}
while (index != numEntries);
}
public static void main(String[] args) throws Exception
{
PNGCodec codec = new PNGCodec();
codec.setFile(args[0], CodecMode.LOAD);
codec.process();
codec.close();
PixelImage image = codec.getImage();
codec = new PNGCodec();
codec.setFile(args[1], CodecMode.SAVE);
codec.setImage(image);
codec.setDpi(300, 300);
codec.appendComment("Test comment #1.");
codec.appendComment("And test comment #2.");
codec.setModification(new GregorianCalendar(new SimpleTimeZone(0, "UTC")));
codec.process();
codec.close();
}
public void process() throws
InvalidFileStructureException,
MissingParameterException,
OperationFailedException,
UnsupportedTypeException,
WrongFileFormatException
{
initModeFromIOObjects();
if (getMode() == CodecMode.LOAD)
{
try
{
if (getImageIndex() != 0)
{
throw new InvalidImageIndexException("PNG streams can only store one image; " +
"index " + getImageIndex() + " is thus not valid.");
}
InputStream input = getInputStream();
if (input == null)
{
throw new MissingParameterException("InputStream object missing.");
}
checksum = new CRC32();
checkedIn = new CheckedInputStream(input, checksum);
in = new DataInputStream(checkedIn);
load();
}
catch (IOException ioe)
{
throw new OperationFailedException("I/O failure: " + ioe.toString());
}
}
else
if (getMode() == CodecMode.SAVE)
{
try
{
PixelImage image = getImage();
if (image == null)
{
throw new MissingParameterException("Need image for saving.");
}
out = getOutputAsDataOutput();
if (out == null)
{
throw new MissingParameterException("Could not retrieve non-null DataOutput object for saving.");
}
setBoundsIfNecessary(image.getWidth(), image.getHeight());
save();
}
catch (IOException ioe)
{
throw new OperationFailedException("I/O failure: " + ioe.toString());
}
}
else
{
throw new OperationFailedException("Unknown codec mode: " + getMode());
}
}
private int readFilterType() throws InvalidFileStructureException, IOException
{
int filterType = infl.read();
if (filterType >= 0 && filterType <= 4)
{
return filterType;
}
else
{
throw new InvalidFileStructureException("Valid filter types are from 0 to 4; got " + filterType);
}
}
private void reverseFilter(int rowFilterType, byte[] buffer, byte[] prev, int numBytes) throws UnsupportedTypeException
{
switch(rowFilterType)
{
case(FILTER_TYPE_NONE):
{
break;
}
case(FILTER_TYPE_SUB):
{
for (int x = 0, px = -bpp; x < numBytes; x++, px++)
{
byte currXMinusBpp;
if (px < 0)
{
currXMinusBpp = 0;
}
else
{
currXMinusBpp = buffer[px];
}
buffer[x] = (byte)(buffer[x] + currXMinusBpp);
}
break;
}
case(FILTER_TYPE_UP):
{
for (int x = 0; x < numBytes; x++)
{
buffer[x] = (byte)(buffer[x] + prev[x]);
}
break;
}
case(FILTER_TYPE_AVERAGE):
{
for (int x = 0, px = -bpp; x < numBytes; x++, px++)
{
int currX = buffer[x] & 0xff;
int currXMinus1;
if (px < 0)
{
currXMinus1 = 0;
}
else
{
currXMinus1 = buffer[px] & 0xff;
}
int prevX = prev[x] & 0xff;
int result = currX + ((currXMinus1 + prevX) / 2);
byte byteResult = (byte)result;
buffer[x] = byteResult;
}
break;
}
case(FILTER_TYPE_PAETH):
{
for (int x = 0, px = -bpp; x < numBytes; x++, px++)
{
byte currXMinusBpp;
byte prevXMinusBpp;
if (px < 0)
{
currXMinusBpp = 0;
prevXMinusBpp = 0;
}
else
{
currXMinusBpp = buffer[px];
prevXMinusBpp = prev[px];
}
buffer[x] = (byte)(buffer[x] + getPaeth(currXMinusBpp, prev[x], prevXMinusBpp));
}
break;
}
default:
{
throw new UnsupportedTypeException("Unknown filter type: " + rowFilterType);
}
}
}
private void save() throws IOException
{
// write 8 byte PNG signature
out.write(MAGIC_BYTES);
// write IHDR (image header) chunk
saveIhdrChunk();
// write pHYs chunk (physical resolution) if data is available
savePhysChunk();
// write tEXt chunks if comments are available
saveTextChunks();
// write tIME chunk if modification time was set
saveTimeChunk();
// write PLTE chunk if necessary
savePlteChunk();
// write IDAT chunk
saveImage();
// write IEND chunk
saveIendChunk();
close();
}
private void saveChunk(int chunkType, int chunkSize, byte[] data) throws IOException
{
// set up array with chunk size and type
byte[] intArray = new byte[8];
ArrayConverter.setIntBE(intArray, 0, chunkSize);
ArrayConverter.setIntBE(intArray, 4, chunkType);
// write chunk size, type and data
out.write(intArray, 0, 8);
out.write(data, 0, chunkSize);
// create checksum on type and data
CRC32 checksum = new CRC32();
checksum.reset();
checksum.update(intArray, 4, 4);
checksum.update(data, 0, chunkSize);
// put checksum into byte array
ArrayConverter.setIntBE(intArray, 0, (int)checksum.getValue());
// and write it to output
out.write(intArray, 0, 4);
}
private void saveIendChunk() throws IOException
{
out.writeInt(0);
out.writeInt(CHUNK_TYPE_IEND);
out.writeInt(CHUNK_CRC32_IEND);
}
private void saveIhdrChunk() throws IOException
{
byte[] buffer = new byte[CHUNK_SIZE_IHDR];
width = getBoundsWidth();
ArrayConverter.setIntBE(buffer, 0, width);
height = getBoundsHeight();
ArrayConverter.setIntBE(buffer, 4, height);
PixelImage image = getImage();
alpha = false;
numChannels = 1;
if (image instanceof BilevelImage)
{
precision = 1;
colorType = COLOR_TYPE_GRAY;
}
else
if (image instanceof Gray16Image)
{
precision = 16;
colorType = COLOR_TYPE_GRAY;
}
else
if (image instanceof Gray8Image)
{
precision = 8;
colorType = COLOR_TYPE_GRAY;
}
else
if (image instanceof Paletted8Image)
{
precision = 8;
colorType = COLOR_TYPE_INDEXED;
}
else
if (image instanceof RGB24Image)
{
numChannels = 3;
precision = 8;
colorType = COLOR_TYPE_RGB;
}
else
if (image instanceof RGB48Image)
{
numChannels = 3;
precision = 16;
colorType = COLOR_TYPE_RGB;
}
buffer[8] = (byte)precision;
buffer[9] = (byte)colorType;
compressionType = COMPRESSION_DEFLATE;
buffer[10] = (byte)compressionType;
filterType = FILTERING_ADAPTIVE;
buffer[11] = (byte)filterType;
interlaceType = INTERLACING_NONE;
buffer[12] = (byte)interlaceType;
saveChunk(CHUNK_TYPE_IHDR, CHUNK_SIZE_IHDR, buffer);
}
private void saveImage() throws IOException
{
switch(interlaceType)
{
case(INTERLACING_NONE):
{
saveImageNonInterlaced();
break;
}
}
}
private void saveImageNonInterlaced() throws IOException
{
int bytesPerRow = computeBytesPerRow(getBoundsWidth());
byte[] rowBuffer = new byte[bytesPerRow + 1];
byte[] outBuffer = new byte[Math.max(encodingMinIdatSize, bytesPerRow + 1)];
int outOffset = 0;
int numDeflated;
Deflater defl = new Deflater(deflateLevel);
defl.setStrategy(deflateStrategy);
for (int y = getBoundsY1(); y <= getBoundsY2(); y++)
{
// fill row buffer
rowBuffer[0] = (byte)FILTER_TYPE_NONE;
fillRowBuffer(y, rowBuffer, 1);
// give it to compressor
defl.setInput(rowBuffer);
// store compressed data in outBuffer
do
{
numDeflated = defl.deflate(outBuffer, outOffset, outBuffer.length - outOffset);
outOffset += numDeflated;
if (outOffset == outBuffer.length)
{
saveChunk(CHUNK_TYPE_IDAT, outOffset, outBuffer);
outOffset = 0;
}
}
while (numDeflated > 0);
setProgress(y - getBoundsY1(), getBoundsHeight());
}
// tell Deflater that it got all the input
defl.finish();
// retrieve remaining compressed data from defl to outBuffer
do
{
numDeflated = defl.deflate(outBuffer, outOffset, outBuffer.length - outOffset);
outOffset += numDeflated;
if (outOffset == outBuffer.length)
{
saveChunk(CHUNK_TYPE_IDAT, outOffset, outBuffer);
outOffset = 0;
}
}
while (numDeflated > 0);
// write final IDAT chunk if necessary
if (outOffset > 0)
{
saveChunk(CHUNK_TYPE_IDAT, outOffset, outBuffer);
}
}
private void savePhysChunk() throws IOException
{
int dpiX = getDpiX();
int dpiY = getDpiY();
if (dpiX < 1 || dpiY < 1)
{
return;
}
byte[] data = new byte[9];
int ppuX = (int)(dpiX * (100 / 2.54));
int ppuY = (int)(dpiY * (100 / 2.54));
ArrayConverter.setIntBE(data, 0, ppuX);
ArrayConverter.setIntBE(data, 4, ppuY);
data[8] = 1; // unit is the meter
saveChunk(CHUNK_TYPE_PHYS, data.length, data);
}
private void savePlteChunk() throws IOException
{
if (colorType != COLOR_TYPE_INDEXED)
{
return;
}
Paletted8Image image = (Paletted8Image)getImage();
Palette pal = image.getPalette();
int numEntries = pal.getNumEntries();
byte[] data = new byte[numEntries * 3];
for (int i = 0, j = 0; i < numEntries; i++, j += 3)
{
data[j] = (byte)pal.getSample(RGBIndex.INDEX_RED, i);
data[j + 1] = (byte)pal.getSample(RGBIndex.INDEX_GREEN, i);
data[j + 2] = (byte)pal.getSample(RGBIndex.INDEX_BLUE, i);
}
saveChunk(CHUNK_TYPE_PLTE, data.length, data);
}
private void saveTextChunks() throws IOException
{
int index = 0;
while (index < getNumComments())
{
String comment = getComment(index++);
comment = "Comment\000" + comment;
byte[] data = comment.getBytes("ISO-8859-1");
saveChunk(CHUNK_TYPE_TEXT, data.length, data);
}
}
private void saveTimeChunk() throws IOException
{
if (modification == null)
{
return;
}
byte[] data = new byte[7];
ArrayConverter.setShortBE(data, 0, (short)modification.get(Calendar.YEAR));
data[2] = (byte)(modification.get(Calendar.MONTH) + 1);
data[3] = (byte)modification.get(Calendar.DAY_OF_MONTH);
data[4] = (byte)modification.get(Calendar.HOUR_OF_DAY);
data[5] = (byte)modification.get(Calendar.MINUTE);
data[6] = (byte)modification.get(Calendar.SECOND);
saveChunk(CHUNK_TYPE_TIME, data.length, data);
}
/**
* Sets the compression level to be used with the underlying
* {@link java.util.zip.Deflater} object which does the compression.
* If no value is specified, {@link java.util.zip.Deflater#DEFAULT_COMPRESSION}
* is used.
* @param newLevel compression level, from 0 to 9, 0 being fastest
* and compressing worst and 9 offering highest compression and taking
* the most time
*/
public void setCompressionLevel(int newLevel)
{
if (newLevel >= 0 && newLevel <= 9)
{
deflateLevel = newLevel;
}
else
{
throw new IllegalArgumentException("Compression level must be from 0..9; got " + newLevel);
}
}
/**
* Sets the compression strategy to be used with the underlying
* {@link java.util.zip.Deflater} object which does the compression.
* If no value is specified, {@link java.util.zip.Deflater#DEFAULT_STRATEGY}
* is used.
* @param newStrategy one of Deflater's strategy values:
* {@link java.util.zip.Deflater#DEFAULT_STRATEGY},
* {@link java.util.zip.Deflater#FILTERED},
* {@link java.util.zip.Deflater#HUFFMAN_ONLY}
*/
public void setCompressionStrategy(int newStrategy)
{
if (newStrategy == Deflater.FILTERED ||
newStrategy == Deflater.DEFAULT_STRATEGY ||
newStrategy == Deflater.HUFFMAN_ONLY)
{
deflateStrategy = newStrategy;
}
else
{
throw new IllegalArgumentException("Unknown compression strategy: " + newStrategy);
}
}
/**
* Sets the size of IDAT chunks generated when encoding.
* If this method is never called, a default value of 32768 bytes (32 KB) is used.
* Note that a byte array of the size of the value you specify here is allocated,
* so make sure that you keep the value small enough to stay within a
* system's memory.
* new GregorianCalendar(new SimpleTimeZone(0, "UTC"))
* as parameter for this method.
* @param time time of last modification of the image
*/
public void setModification(Calendar time)
{
modification = time;
}
/**
* Skips a number of bytes in the input stream.
* @param num number of bytes to be skipped
* @throws IOException if there were I/O errors
*/
private void skip(long num) throws IOException
{
while (num > 0)
{
long numSkipped = in.skip(num);
if (numSkipped > 0)
{
num -= numSkipped;
}
}
}
private void storeInterlacedAdam7(int pass, int y, byte[] buffer)
{
switch(colorType)
{
case(COLOR_TYPE_GRAY):
{
storeInterlacedAdam7Gray(pass, y, buffer);
break;
}
case(COLOR_TYPE_RGB):
{
storeInterlacedAdam7Rgb(pass, y, buffer);
break;
}
case(COLOR_TYPE_RGB_ALPHA):
{
storeInterlacedAdam7RgbAlpha(pass, y, buffer);
break;
}
case(COLOR_TYPE_GRAY_ALPHA):
{
storeInterlacedAdam7GrayAlpha(pass, y, buffer);
break;
}
case(COLOR_TYPE_INDEXED):
{
storeInterlacedAdam7Indexed(pass, y, buffer);
break;
}
}
}
private void storeInterlacedAdam7Gray(int pass, int y, byte[] buffer)
{
int x = ADAM7_FIRST_COLUMN[pass];
final int incr = ADAM7_COLUMN_INCREMENT[pass];
final int x1 = getBoundsX1();
final int x2 = getBoundsX2();
int offset = 0;
int numColumns = computeColumnsAdam7(pass);
int numPackedBytes = computeBytesPerRow(numColumns);
byte[] dest = new byte[numColumns + 7];
switch(precision)
{
case(1):
{
BilevelImage bilevelImage = (BilevelImage)image;
ArrayConverter.decodePacked1Bit(buffer, 0, dest, 0, numPackedBytes);
while (x <= x2)
{
if (x >= x1)
{
if (dest[offset] == 0)
{
bilevelImage.putBlack(x - x1, y);
}
else
{
bilevelImage.putWhite(x - x1, y);
}
}
x += incr;
offset++;
}
break;
}
case(2):
{
Gray8Image grayImage = (Gray8Image)image;
ArrayConverter.convertPacked2BitIntensityTo8Bit(buffer, 0, dest, 0, numPackedBytes);
while (x <= x2)
{
if (x >= x1)
{
grayImage.putByteSample(x - x1, y, dest[offset]);
}
x += incr;
offset++;
}
break;
}
case(4):
{
Gray8Image grayImage = (Gray8Image)image;
ArrayConverter.convertPacked4BitIntensityTo8Bit(buffer, 0, dest, 0, numPackedBytes);
while (x <= x2)
{
if (x >= x1)
{
grayImage.putByteSample(x - x1, y, dest[offset]);
}
x += incr;
offset++;
}
break;
}
case(8):
{
Gray8Image grayImage = (Gray8Image)image;
while (x <= x2)
{
if (x >= x1)
{
grayImage.putSample(x - x1, y, buffer[offset]);
}
x += incr;
offset++;
}
break;
}
case(16):
{
Gray16Image grayImage = (Gray16Image)image;
while (x <= x2)
{
if (x >= x1)
{
int sample = (buffer[offset] & 0xff) << 8;
sample |= (buffer[offset + 1] & 0xff);
grayImage.putSample(x, y, sample);
}
x += incr;
offset += 2;
}
break;
}
}
}
private void storeInterlacedAdam7GrayAlpha(int pass, int y, byte[] buffer)
{
int x = ADAM7_FIRST_COLUMN[pass];
final int incr = ADAM7_COLUMN_INCREMENT[pass];
final int x1 = getBoundsX1();
final int x2 = getBoundsX2();
int offset = 0;
switch(precision)
{
case(8):
{
Gray8Image grayImage = (Gray8Image)image;
while (x <= x2)
{
if (x >= x1)
{
grayImage.putSample(x - x1, y, buffer[offset]);
// alpha
}
x += incr;
offset += 2;
}
break;
}
case(16):
{
Gray16Image grayImage = (Gray16Image)image;
while (x <= x2)
{
if (x >= x1)
{
int sample = (buffer[offset] & 0xff) << 8;
sample |= (buffer[offset + 1] & 0xff);
grayImage.putSample(x, y, sample);
// store alpha
}
x += incr;
offset += 4;
}
break;
}
}
}
private void storeInterlacedAdam7Indexed(int pass, int y, byte[] buffer)
{
Paletted8Image palImage = (Paletted8Image)image;
int x = ADAM7_FIRST_COLUMN[pass];
final int incr = ADAM7_COLUMN_INCREMENT[pass];
final int x1 = getBoundsX1();
final int x2 = getBoundsX2();
int offset = 0;
int numColumns = computeColumnsAdam7(pass);
int numPackedBytes = computeBytesPerRow(numColumns);
byte[] dest = new byte[numColumns + 7];
switch(precision)
{
case(1):
{
ArrayConverter.decodePacked1Bit(buffer, 0, dest, 0, numPackedBytes);
while (x <= x2)
{
if (x >= x1)
{
palImage.putByteSample(x - x1, y, dest[offset]);
}
x += incr;
offset++;
}
break;
}
case(2):
{
ArrayConverter.decodePacked2Bit(buffer, 0, dest, 0, numPackedBytes);
while (x <= x2)
{
if (x >= x1)
{
palImage.putByteSample(x - x1, y, dest[offset]);
}
x += incr;
offset++;
}
break;
}
case(4):
{
ArrayConverter.decodePacked4Bit(buffer, 0, dest, 0, numPackedBytes);
while (x <= x2)
{
if (x >= x1)
{
palImage.putByteSample(x - x1, y, dest[offset]);
}
x += incr;
offset++;
}
break;
}
case(8):
{
while (x <= x2)
{
if (x >= x1)
{
palImage.putSample(x - x1, y, buffer[offset]);
}
x += incr;
offset++;
}
break;
}
}
}
private void storeInterlacedAdam7Rgb(int pass, int y, byte[] buffer)
{
int x = ADAM7_FIRST_COLUMN[pass];
final int x1 = getBoundsX1();
final int x2 = getBoundsX2();
final int incr = ADAM7_COLUMN_INCREMENT[pass];
int offset = 0;
if (precision == 8)
{
RGB24Image rgbImage = (RGB24Image)image;
while (x <= x2)
{
if (x >= x1)
{
rgbImage.putSample(RGB24Image.INDEX_RED, x, y, buffer[offset]);
rgbImage.putSample(RGB24Image.INDEX_GREEN, x, y, buffer[offset + 1]);
rgbImage.putSample(RGB24Image.INDEX_BLUE, x, y, buffer[offset + 2]);
}
x += incr;
offset += 3;
}
}
else
if (precision == 16)
{
RGB48Image rgbImage = (RGB48Image)image;
while (x <= x2)
{
if (x >= x1)
{
int red = (buffer[offset] & 0xff) << 8;
red |= buffer[offset + 1] & 0xff;
rgbImage.putSample(RGB24Image.INDEX_RED, x, y, red);
int green = (buffer[offset + 2] & 0xff) << 8;
green |= buffer[offset + 3] & 0xff;
rgbImage.putSample(RGB24Image.INDEX_GREEN, x, y, green);
int blue = (buffer[offset + 4] & 0xff) << 8;
blue |= buffer[offset + 5] & 0xff;
rgbImage.putSample(RGB24Image.INDEX_BLUE, x, y, blue);
}
x += incr;
offset += 6;
}
}
}
private void storeInterlacedAdam7RgbAlpha(int pass, int y, byte[] buffer)
{
int x = ADAM7_FIRST_COLUMN[pass];
final int x1 = getBoundsX1();
final int x2 = getBoundsX2();
final int incr = ADAM7_COLUMN_INCREMENT[pass];
int offset = 0;
if (precision == 8)
{
RGB24Image rgbImage = (RGB24Image)image;
while (x <= x2)
{
if (x >= x1)
{
rgbImage.putSample(RGB24Image.INDEX_RED, x, y, buffer[offset]);
rgbImage.putSample(RGB24Image.INDEX_GREEN, x, y, buffer[offset + 1]);
rgbImage.putSample(RGB24Image.INDEX_BLUE, x, y, buffer[offset + 2]);
// store alpha
}
x += incr;
offset += 4;
}
}
else
if (precision == 16)
{
RGB48Image rgbImage = (RGB48Image)image;
while (x <= x2)
{
if (x >= x1)
{
int red = (buffer[offset] & 0xff) << 8;
red |= buffer[offset + 1] & 0xff;
rgbImage.putSample(RGB24Image.INDEX_RED, x, y, red);
int green = (buffer[offset + 2] & 0xff) << 8;
green |= buffer[offset + 3] & 0xff;
rgbImage.putSample(RGB24Image.INDEX_GREEN, x, y, green);
int blue = (buffer[offset + 4] & 0xff) << 8;
blue |= buffer[offset + 5] & 0xff;
rgbImage.putSample(RGB24Image.INDEX_BLUE, x, y, blue);
// store alpha
}
x += incr;
offset += 8;
}
}
}
private void storeNonInterlaced(int y, byte[] buffer)
{
switch(colorType)
{
case(COLOR_TYPE_GRAY):
{
storeNonInterlacedGray(y, buffer);
break;
}
case(COLOR_TYPE_GRAY_ALPHA):
{
storeNonInterlacedGrayAlpha(y, buffer);
break;
}
case(COLOR_TYPE_INDEXED):
{
storeNonInterlacedIndexed(y, buffer);
break;
}
case(COLOR_TYPE_RGB):
{
storeNonInterlacedRgb(y, buffer);
break;
}
case(COLOR_TYPE_RGB_ALPHA):
{
storeNonInterlacedRgbAlpha(y, buffer);
break;
}
}
}
private void storeNonInterlacedGray(int y, byte[] buffer)
{
switch(precision)
{
case(1):
{
BilevelImage bilevelImage = (BilevelImage)image;
int x1 = getBoundsX1();
bilevelImage.putPackedBytes(0, y, getBoundsWidth(), buffer, x1 / 8, x1 % 8);
break;
}
case(2):
{
Gray8Image grayImage = (Gray8Image)image;
byte[] dest = new byte[width + 3];
ArrayConverter.convertPacked2BitIntensityTo8Bit(buffer, 0, dest, 0, buffer.length);
grayImage.putByteSamples(0, 0, y, getBoundsWidth(), 1, dest, getBoundsX1());
break;
}
case(4):
{
Gray8Image grayImage = (Gray8Image)image;
byte[] dest = new byte[width + 1];
ArrayConverter.convertPacked4BitIntensityTo8Bit(buffer, 0, dest, 0, buffer.length);
grayImage.putByteSamples(0, 0, y, getBoundsWidth(), 1, dest, getBoundsX1());
break;
}
case(8):
{
Gray8Image grayImage = (Gray8Image)image;
int offset = getBoundsX1();
int x = 0;
int k = getBoundsWidth();
while (k > 0)
{
grayImage.putSample(0, x++, y, buffer[offset++]);
k--;
}
break;
}
case(16):
{
Gray16Image grayImage = (Gray16Image)image;
int offset = getBoundsX1();
int x = 0;
int k = getBoundsWidth();
while (k > 0)
{
int sample = (buffer[offset++] & 0xff) << 8;
sample |= (buffer[offset++] & 0xff);
grayImage.putSample(x++, y, sample);
k--;
}
break;
}
}
}
private void storeNonInterlacedGrayAlpha(int y, byte[] buffer)
{
switch(precision)
{
case(8):
{
Gray8Image grayImage = (Gray8Image)image;
int offset = getBoundsX1();
int x = 0;
int k = getBoundsWidth();
while (k > 0)
{
grayImage.putSample(0, x++, y, buffer[offset++]);
offset++; // skip alpha; should be stored in a TransparencyInformation object
k--;
}
break;
}
case(16):
{
Gray16Image grayImage = (Gray16Image)image;
int offset = getBoundsX1();
int x = 0;
int k = getBoundsWidth();
while (k > 0)
{
int sample = (buffer[offset++] & 0xff) << 8;
sample |= (buffer[offset++] & 0xff);
grayImage.putSample(x++, y, sample);
offset += 2; // skip alpha; TODO: store in TransparencyInformation object
k--;
}
break;
}
}
}
private void storeNonInterlacedIndexed(int y, byte[] buffer)
{
Paletted8Image palImage = (Paletted8Image)image;
switch(precision)
{
case(1):
{
byte[] dest = new byte[width + 7];
ArrayConverter.decodePacked1Bit(buffer, 0, dest, 0, buffer.length);
palImage.putByteSamples(0, 0, y, getBoundsWidth(), 1, dest, getBoundsX1());
break;
}
case(2):
{
byte[] dest = new byte[width + 3];
ArrayConverter.decodePacked2Bit(buffer, 0, dest, 0, buffer.length);
palImage.putByteSamples(0, 0, y, getBoundsWidth(), 1, dest, getBoundsX1());
break;
}
case(4):
{
byte[] dest = new byte[width + 1];
ArrayConverter.decodePacked4Bit(buffer, 0, dest, 0, buffer.length);
palImage.putByteSamples(0, 0, y, getBoundsWidth(), 1, dest, getBoundsX1());
break;
}
case(8):
{
int offset = getBoundsX1();
int x = 0;
int k = getBoundsWidth();
while (k > 0)
{
palImage.putSample(0, x++, y, buffer[offset++]);
k--;
}
break;
}
}
}
private void storeNonInterlacedRgb(int y, byte[] buffer)
{
if (precision == 8)
{
RGB24Image rgbImage = (RGB24Image)image;
int offset = getBoundsX1() * 3;
int x = 0;
int k = getBoundsWidth();
while (k > 0)
{
rgbImage.putSample(RGB24Image.INDEX_RED, x, y, buffer[offset++]);
rgbImage.putSample(RGB24Image.INDEX_GREEN, x, y, buffer[offset++]);
rgbImage.putSample(RGB24Image.INDEX_BLUE, x, y, buffer[offset++]);
x++;
k--;
}
}
else
if (precision == 16)
{
RGB48Image rgbImage = (RGB48Image)image;
int offset = getBoundsX1() * 6;
int x = 0;
int k = getBoundsWidth();
while (k > 0)
{
int red = (buffer[offset++] & 0xff) << 8;
red |= buffer[offset++] & 0xff;
rgbImage.putSample(RGB24Image.INDEX_RED, x, y, red);
int green = (buffer[offset++] & 0xff) << 8;
green |= buffer[offset++] & 0xff;
rgbImage.putSample(RGB24Image.INDEX_GREEN, x, y, green);
int blue = (buffer[offset++] & 0xff) << 8;
blue |= buffer[offset++] & 0xff;
rgbImage.putSample(RGB24Image.INDEX_BLUE, x, y, blue);
x++;
k--;
}
}
}
private void storeNonInterlacedRgbAlpha(int y, byte[] buffer)
{
switch(precision)
{
case(8):
{
RGB24Image rgbImage = (RGB24Image)image;
int offset = getBoundsX1() * 3;
int x = 0;
int k = getBoundsWidth();
while (k > 0)
{
rgbImage.putSample(RGB24Image.INDEX_RED, x, y, buffer[offset++]);
rgbImage.putSample(RGB24Image.INDEX_GREEN, x, y, buffer[offset++]);
rgbImage.putSample(RGB24Image.INDEX_BLUE, x, y, buffer[offset++]);
offset++; // skip alpha; TODO: store in TransparencyInformation object
x++;
k--;
}
break;
}
case(16):
{
RGB48Image rgbImage = (RGB48Image)image;
int offset = getBoundsX1() * 8;
int x = 0;
int k = getBoundsWidth();
while (k > 0)
{
int red = (buffer[offset++] & 0xff) << 8;
red |= buffer[offset++] & 0xff;
rgbImage.putSample(RGB24Image.INDEX_RED, x, y, red);
int green = (buffer[offset++] & 0xff) << 8;
green |= buffer[offset++] & 0xff;
rgbImage.putSample(RGB24Image.INDEX_GREEN, x, y, green);
int blue = (buffer[offset++] & 0xff) << 8;
blue |= buffer[offset++] & 0xff;
rgbImage.putSample(RGB24Image.INDEX_BLUE, x, y, blue);
offset += 2; // skip alpha; TODO: store in TransparencyInformation object
x++;
k--;
}
break;
}
}
}
public String suggestFileExtension(PixelImage image)
{
return ".png";
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/CodecMode.java 0000664 0000000 0000000 00000001647 07741250131 023763 0 ustar /*
* CodecMode
*
* Copyright (c) 2000, 2001 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.codecs;
/**
* This class is an enumeration type for the two modes that an image codec can be used in,
* {@link #LOAD} and {@link #SAVE}.
* These values are used as arguments in some of the methods of {@link ImageCodec}.
*
* @author Marco Schmidt
* @since 0.7.0
*/
public final class CodecMode
{
private CodecMode()
{
}
/**
* Codec mode load, one of the two possible values of CodecMode.
* To be used with a codec to indicate that an image is to be read from a stream.
*/
public static final CodecMode LOAD = new CodecMode();
/**
* Codec mode save, one of the two possible values of CodecMode.
* To be used with a codec to indicate that an image is to be written to a stream.
*/
public static final CodecMode SAVE = new CodecMode();
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/IFFCodec.java 0000664 0000000 0000000 00000051770 10377273050 023511 0 ustar /*
* IFFCodec
*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.codecs;
import java.io.DataInput;
import java.io.IOException;
import net.sourceforge.jiu.codecs.ImageCodec;
import net.sourceforge.jiu.codecs.InvalidFileStructureException;
import net.sourceforge.jiu.codecs.UnsupportedTypeException;
import net.sourceforge.jiu.codecs.WrongFileFormatException;
import net.sourceforge.jiu.data.MemoryPaletted8Image;
import net.sourceforge.jiu.data.MemoryRGB24Image;
import net.sourceforge.jiu.data.PixelImage;
import net.sourceforge.jiu.data.Palette;
import net.sourceforge.jiu.data.Paletted8Image;
import net.sourceforge.jiu.data.RGB24Image;
import net.sourceforge.jiu.ops.MissingParameterException;
import net.sourceforge.jiu.ops.OperationFailedException;
import net.sourceforge.jiu.ops.WrongParameterException;
/**
* A codec to read Amiga IFF image files.
* IFF (Interchange File Format) is an Amiga wrapper file format for texts, images, animations, sound and other kinds of data.
* This codec only deals with image IFF files.
* Typical file extensions for IFF image files are .lbm
and .iff
.
* Loading / saving
* Only loading is supported by this codec.
* Supported file types
* Both uncompressed and run-length encoded files are read.
*
*
* Usage example
*
* IFFCodec codec = new IFFCodec();
* codec.setFile("image.iff", CodecMode.LOAD);
* codec.process();
* PixelImage image = codec.getImage();
*
* @author Marco Schmidt
* @since 0.3.0
*/
public class IFFCodec extends ImageCodec
{
private final static int MAGIC_BMHD = 0x424d4844;
private final static int MAGIC_BODY = 0x424f4459;
private final static int MAGIC_CMAP = 0x434d4150;
private final static int MAGIC_CAMG = 0x43414d47;
private final static int MAGIC_FORM = 0x464f524d;
private final static int MAGIC_ILBM = 0x494c424d;
private final static int MAGIC_PBM = 0x50424d20;
private final static int SIZE_BMHD = 0x00000014;
private final static byte COMPRESSION_NONE = 0x00;
private final static byte COMPRESSION_RLE = 0x01;
private int camg;
private byte compression;
private boolean ehb;
private boolean ham;
private boolean ham6;
private boolean ham8;
private int height;
private int numPlanes;
private Palette palette;
private boolean rgb24;
private int type;
private int width;
private void checkAndLoad() throws
InvalidFileStructureException,
IOException,
MissingParameterException,
UnsupportedTypeException,
WrongFileFormatException,
WrongParameterException
{
DataInput in = getInputAsDataInput();
if (in == null)
{
throw new MissingParameterException("InputStream / DataInput object is missing.");
}
int formMagic = in.readInt();
if (formMagic != MAGIC_FORM)
{
throw new WrongFileFormatException("Cannot load image. The " +
"input stream is not a valid IFF file (wrong magic byte " +
"sequence).");
}
in.readInt(); // read and discard "file size" field
type = in.readInt();
if (type != MAGIC_ILBM && type != MAGIC_PBM)
{
throw new UnsupportedTypeException("Cannot load image. The " +
"input stream is an IFF file, but not of type ILBM or PBM" +
" (" + getChunkName(type) + ")");
}
PixelImage result = null;
boolean hasBMHD = false;
boolean hasCAMG = false;
do
{
int magic = in.readInt();
//System.out.println(chunkNameToString(magic));
int size = in.readInt();
// chunks must always have an even number of bytes
if ((size & 1) == 1)
{
size++;
}
//System.out.println("Chunk " + getChunkName(magic) + ", size=" + size);
switch(magic)
{
case(MAGIC_BMHD): // main header with width, height, bit depth
{
if (hasBMHD)
{
throw new InvalidFileStructureException("Error in " +
"IFF file: more than one BMHD chunk.");
}
if (size != SIZE_BMHD)
{
throw new InvalidFileStructureException("Cannot " +
"load image. The bitmap header chunk does not " +
"have the expected size.");
}
// image resolution in pixels
width = in.readShort();
height = in.readShort();
if (width < 1 || height < 1)
{
throw new InvalidFileStructureException("Cannot " +
"load image. The IFF file's bitmap header " +
"contains invalid width and height values: " +
width + ", " + height);
}
// next four bytes don't matter
in.skipBytes(4);
// color depth, 1..8 or 24
numPlanes = in.readByte();
if ((numPlanes != 24) && (numPlanes < 1 || numPlanes > 8))
{
throw new UnsupportedTypeException("Cannot load " +
"image, unsupported number of bits per pixel: " +
numPlanes);
}
//System.out.println("\nnum planes=" + numPlanes);
in.readByte(); // discard "masking" value
// compression type, must be 0 or 1
compression = in.readByte();
if (compression != COMPRESSION_NONE &&
compression != COMPRESSION_RLE)
{
throw new UnsupportedTypeException("Cannot load " +
"image, unsupported compression type: " +
compression);
}
//System.out.println(getCompressionName(compression));
in.skipBytes(9);
hasBMHD = true;
break;
}
case(MAGIC_BODY):
{
if (!hasBMHD)
{
// width still has its initialization value -1; no
// bitmap chunk was encountered
throw new InvalidFileStructureException("Cannot load image. Error in " +
"IFF input stream: No bitmap header chunk " +
"encountered before image body chunk.");
}
if (palette == null && (!rgb24))
{
// a missing color map is allowed only for truecolor images
throw new InvalidFileStructureException("Cannot load image. Error in " +
"IFF input stream: No colormap chunk " +
"encountered before image body chunk.");
}
result = loadImage(in);
break;
}
case(MAGIC_CAMG):
{
if (hasCAMG)
{
throw new InvalidFileStructureException("Cannot load image. Error in " +
"IFF input stream: More than one CAMG chunk.");
}
hasCAMG = true;
if (size < 4)
{
throw new InvalidFileStructureException("Cannot load" +
" image. CAMG must be at least four bytes large; " +
"found: " + size);
}
camg = in.readInt();
ham = (camg & 0x800) != 0;
ehb = (camg & 0x80) != 0;
//System.out.println("ham=" + ham);
in.skipBytes(size - 4);
break;
}
case(MAGIC_CMAP): // palette (color map)
{
if (palette != null)
{
throw new InvalidFileStructureException("Cannot " +
"load image. Error in IFF " +
"input stream: More than one palette.");
}
if (size < 3 || (size % 3) != 0)
{
throw new InvalidFileStructureException("Cannot " +
"load image. The size of the colormap is " +
"invalid: " + size);
}
int numColors = size / 3;
palette = new Palette(numColors, 255);
for (int i = 0; i < numColors; i++)
{
palette.putSample(Palette.INDEX_RED, i, in.readByte() & 0xff);
palette.putSample(Palette.INDEX_GREEN, i, in.readByte() & 0xff);
palette.putSample(Palette.INDEX_BLUE, i, in.readByte() & 0xff);
}
break;
}
default:
{
if (in.skipBytes(size) != size)
{
throw new IOException("Error skipping " + size +
" bytes of input stream.");
}
break;
}
}
}
while(result == null);
setImage(result);
}
/**
* Converts input planes to index or truecolor output values.
* Exact interpretation depends on the type of ILBM image storage:
*
*
* @param sourcePlanes
* @param dest
*/
private void convertRow(byte[][] sourcePlaneData, byte[][] dest)
{
int sourceMask = 0x80;
int sourceIndex = 0;
int lastRed = 0;
int lastGreen = 0;
int lastBlue = 0;
for (int x = 0; x < width; x++)
{
int destMask = 1;
int index = 0;
for (int p = 0; p < sourcePlaneData.length; p++)
{
if ((sourcePlaneData[p][sourceIndex] & sourceMask) != 0)
{
index |= destMask;
}
destMask <<= 1;
}
if ((x & 7) == 7)
{
sourceIndex++;
}
if (sourceMask == 0x01)
{
sourceMask = 0x80;
}
else
{
sourceMask >>= 1;
}
if (ham6)
{
//System.out.println("enter ham6");
int paletteIndex = index & 0x0f;
//System.out.println("palette index=" + paletteIndex);
switch((index >> 4) & 0x03)
{
case(0): // HOLD
{
lastRed = palette.getSample(Palette.INDEX_RED, paletteIndex);
lastGreen = palette.getSample(Palette.INDEX_GREEN, paletteIndex);
lastBlue = palette.getSample(Palette.INDEX_BLUE, paletteIndex);
break;
}
case(1): // MODIFY BLUE
{
lastBlue = (lastBlue & 0x0f) | (paletteIndex << 4);
break;
}
case(2): // MODIFY RED
{
lastRed = (lastRed & 0x0f) | (paletteIndex << 4);
break;
}
case(3): // MODIFY GREEN
{
lastGreen = (lastGreen & 0x0f) | (paletteIndex << 4);
break;
}
}
dest[0][x] = (byte)lastRed;
dest[1][x] = (byte)lastGreen;
dest[2][x] = (byte)lastBlue;
}
else
if (ham8)
{
int paletteIndex = index & 0x3f;
//System.out.println("palette index=" + paletteIndex);
switch((index >> 6) & 0x03)
{
case(0): // HOLD
{
lastRed = palette.getSample(Palette.INDEX_RED, paletteIndex);
lastGreen = palette.getSample(Palette.INDEX_GREEN, paletteIndex);
lastBlue = palette.getSample(Palette.INDEX_BLUE, paletteIndex);
break;
}
case(1): // MODIFY BLUE
{
lastBlue = (lastBlue & 0x03) | (paletteIndex << 2);
break;
}
case(2): // MODIFY RED
{
lastRed = (lastRed & 0x03) | (paletteIndex << 2);
break;
}
case(3): // MODIFY GREEN
{
lastGreen = (lastGreen & 0x03) | (paletteIndex << 2);
break;
}
}
dest[0][x] = (byte)lastRed;
dest[1][x] = (byte)lastGreen;
dest[2][x] = (byte)lastBlue;
}
else
if (rgb24)
{
dest[2][x] = (byte)(index >> 16);
dest[1][x] = (byte)(index >> 8);
dest[0][x] = (byte)index;
}
else
{
/* the value is an index into the lookup table */
//destRgbData[destOffset++] = rgbLookup[index];
dest[0][x] = (byte)index;
}
}
}
private void createExtraHalfbritePalette()
{
if (palette == null)
{
return;
}
int numPaletteEntries = palette.getNumEntries();
Palette tempPalette = new Palette(numPaletteEntries * 2, 255);
for (int i = 0; i < numPaletteEntries; i++)
{
int red = palette.getSample(Palette.INDEX_RED, i);
tempPalette.putSample(Palette.INDEX_RED, numPaletteEntries + i, red);
tempPalette.putSample(Palette.INDEX_RED, i, (red / 2) & 0xf0);
int green = palette.getSample(Palette.INDEX_GREEN, i);
tempPalette.putSample(Palette.INDEX_GREEN, numPaletteEntries + i, red);
tempPalette.putSample(Palette.INDEX_GREEN, i, (green / 2) & 0xf0);
int blue = palette.getSample(Palette.INDEX_BLUE, i);
tempPalette.putSample(Palette.INDEX_BLUE, numPaletteEntries + i, blue);
tempPalette.putSample(Palette.INDEX_BLUE, i, (blue / 2) & 0xf0);
}
palette = tempPalette;
}
private static String getChunkName(int name)
{
StringBuffer sb = new StringBuffer(4);
sb.setLength(4);
sb.setCharAt(0, (char)((name >> 24) & 0xff));
sb.setCharAt(1, (char)((name >> 16) & 0xff));
sb.setCharAt(2, (char)((name >> 8) & 0xff));
sb.setCharAt(3, (char)((name & 0xff)));
return new String(sb);
}
/*private static String getCompressionName(byte method)
{
switch(method)
{
case(COMPRESSION_NONE): return "Uncompressed";
case(COMPRESSION_RLE): return "RLE";
default: return "Unknown method (" + (method & 0xff) + ")";
}
}*/
public String[] getFileExtensions()
{
return new String[] {".lbm", ".iff"};
}
public String getFormatName()
{
return "Amiga Interchange File Format (IFF, LBM)";
}
public String[] getMimeTypes()
{
return new String[] {"image/x-iff"};
}
public boolean isLoadingSupported()
{
return true;
}
public boolean isSavingSupported()
{
return false;
}
/**
* Loads data.length bytes from the input stream to the data array,
* regarding the compression type.
* COMPRESSION_NONE will make this method load data.length bytes from
* the input stream.
* COMPRESSION_RLE will make this method decompress data.length bytes
* from input.
*/
private void loadBytes(DataInput in, byte[] data, int num, int y) throws
InvalidFileStructureException,
IOException
{
switch(compression)
{
case(COMPRESSION_NONE):
{
in.readFully(data, 0, num);
break;
}
case(COMPRESSION_RLE):
{
int x = 0;
while (x < num)
{
int n = in.readByte() & 0xff;
//System.out.println("value=" + n);
boolean compressed = false;
int count = -1;
try
{
if (n < 128)
{
// copy next n + 1 bytes literally
n++;
in.readFully(data, x, n);
x += n;
}
else
{
// if n == -128, nothing happens
if (n > 128)
{
compressed = true;
// otherwise, compute counter
count = 257 - n;
// read another byte
byte value = in.readByte();
// write this byte counter times to output
while (count-- > 0)
{
data[x++] = value;
}
}
}
}
catch (ArrayIndexOutOfBoundsException ioobe)
{
//System.out.println("Loading error");
/* if the encoder did anything wrong, the above code
could potentially write beyond array boundaries
(e.g. if runs of data exceed line boundaries);
this would result in an ArrayIndexOutOfBoundsException
thrown by the virtual machine;
to give a more understandable error message to the
user, this exception is caught here and a
explanatory InvalidFileStructureException is thrown */
throw new InvalidFileStructureException("Error: " +
"RLE-compressed image " +
"file seems to be corrupt (compressed=" + compressed +
", x=" + x + ", y=" + y +
", count=" + (compressed ? (-((int)n) + 1) : n) +
", array length=" + data.length + ").");
}
}
break;
}
default:
{
throw new InvalidFileStructureException("Error loading " +
"image; unknown compression type (" + compression + ")");
}
}
}
/**
* Loads an image from given input stream in, regarding the compression
* type. The image will have 1 to 8 or 24 planes, a resolution given by
* the dimension width times height. The color map data will be used to
* convert index values to RGB pixels.
* Returns the resulting image.
* Will throw an IOException if either there were errors reading from the
* input stream or if the file does not exactly match the file format.
*/
private PixelImage loadImage(DataInput in) throws
InvalidFileStructureException,
IOException,
UnsupportedTypeException,
WrongParameterException
{
setBoundsIfNecessary(width, height);
checkImageResolution();
if (ham)
{
if (numPlanes == 6)
{
ham6 = true;
}
else
if (numPlanes == 8)
{
ham8 = true;
}
else
{
throw new UnsupportedTypeException("Cannot handle " +
"IFF ILBM HAM image file with number of planes " +
"other than 6 or 8 (got " + numPlanes + ").");
}
if (palette == null)
{
throw new InvalidFileStructureException("Invalid IFF ILBM " +
"file: HAM (Hold And Modify) image without a palette.");
}
int numPaletteEntries = palette.getNumEntries();
if (ham6 && numPaletteEntries < 16)
{
throw new InvalidFileStructureException("Invalid IFF ILBM " +
"file: HAM (Hold And Modify) 6 bit image with a " +
"number of palette entries less than 16 (" +
numPaletteEntries + ").");
}
if (ham8 && numPaletteEntries < 64)
{
throw new InvalidFileStructureException("Invalid IFF ILBM " +
"file: HAM (Hold And Modify) 8 bit image with a " +
"number of palette entries less than 64 (" +
numPaletteEntries + ").");
}
}
if (ehb)
{
createExtraHalfbritePalette();
}
int numBytesPerPlane = (width + 7) / 8;
PixelImage image = null;
Paletted8Image palettedImage = null;
RGB24Image rgbImage = null;
if (numPlanes == 24 || ham)
{
rgbImage = new MemoryRGB24Image(getBoundsWidth(), getBoundsHeight());
image = rgbImage;
}
else
{
palettedImage = new MemoryPaletted8Image(getBoundsWidth(), getBoundsHeight(), palette);
image = palettedImage;
}
/* only matters for uncompressed files;
will be true if the number of bytes is odd;
is computed differently for PBM and ILBM types
*/
boolean oddBytesPerRow = (((numBytesPerPlane * numPlanes) % 2) != 0);
if (type == MAGIC_PBM)
{
oddBytesPerRow = ((width % 2) == 1);
}
// plane data will have numPlanes planes for ILBM and 1 plane for PBM
byte[][] planes = null;
int numChannels = 1;
if (type == MAGIC_ILBM)
{
int allocBytes = numBytesPerPlane;
if ((numBytesPerPlane % 2) == 1)
{
allocBytes++;
}
// allocate numPlanes byte arrays
planes = new byte[numPlanes][];
if (rgb24 || ham)
{
numChannels = 3;
}
// for each of these byte arrays allocate numBytesPerPlane bytes
for (int i = 0; i < numPlanes; i++)
{
planes[i] = new byte[allocBytes];
}
}
else
{
// only one plane, but each plane has width bytes instead of
// numBytesPerPlane
planes = new byte[1][];
planes[0] = new byte[width];
}
byte[][] dest = new byte[numChannels][];
for (int i = 0; i < numChannels; i++)
{
dest[i] = new byte[width];
}
for (int y = 0, destY = 0 - getBoundsY1(); y <= getBoundsY2(); y++, destY++)
{
// load one row, different approach for PBM and ILBM
if (type == MAGIC_ILBM)
{
// decode all planes for a complete row
for (int p = 0; p < numPlanes; p++)
{
loadBytes(in, planes[p], numBytesPerPlane, y);
}
}
else
if (type == MAGIC_PBM)
{
loadBytes(in, planes[0], numBytesPerPlane, y);
}
/* all uncompressed rows must have an even number of bytes
so in case the number of bytes per row is odd, one byte
is read and dropped */
if (compression == COMPRESSION_NONE && oddBytesPerRow)
{
in.readByte();
}
setProgress(y, getBoundsY2() + 1);
// if we do not need the row we just loaded we continue loading
// the next row
if (!isRowRequired(y))
{
continue;
}
//System.out.println("storing row " + y + " as " + destY + ", numPlanes="+ numPlanes + ",type=" + type);
// compute offset into pixel data array
if (type == MAGIC_ILBM)
{
convertRow(planes, dest);
if (rgb24 || ham)
{
rgbImage.putByteSamples(RGB24Image.INDEX_RED, 0, destY,
getBoundsWidth(), 1, dest[0], getBoundsX1());
rgbImage.putByteSamples(RGB24Image.INDEX_GREEN, 0, destY,
getBoundsWidth(), 1, dest[1], getBoundsX1());
rgbImage.putByteSamples(RGB24Image.INDEX_BLUE, 0, destY,
getBoundsWidth(), 1, dest[2], getBoundsX1());
}
else
{
palettedImage.putByteSamples(0, 0, destY,
getBoundsWidth(), 1, dest[0], getBoundsX1());
}
}
else
if (type == MAGIC_PBM)
{
palettedImage.putByteSamples(0, 0, destY, getBoundsWidth(), 1,
planes[0], getBoundsX1());
}
}
return image;
}
public void process() throws
InvalidFileStructureException,
MissingParameterException,
OperationFailedException,
UnsupportedTypeException,
WrongFileFormatException
{
initModeFromIOObjects();
if (getMode() == CodecMode.LOAD)
{
try
{
checkAndLoad();
}
catch (IOException ioe)
{
throw new InvalidFileStructureException("I/O error while loading: " + ioe.toString());
}
}
else
{
throw new OperationFailedException("Only loading from IFF is supported.");
}
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/GIFCodec.java 0000664 0000000 0000000 00000042056 10542177143 023507 0 ustar /*
* GIFCodec
*
* Copyright (c) 2002, 2003, 2004, 2005, 2006 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.codecs;
import java.io.DataOutput;
import java.io.IOException;
import net.sourceforge.jiu.codecs.ImageCodec;
import net.sourceforge.jiu.codecs.UnsupportedTypeException;
import net.sourceforge.jiu.data.BilevelImage;
import net.sourceforge.jiu.data.Gray8Image;
import net.sourceforge.jiu.data.IntegerImage;
import net.sourceforge.jiu.data.Paletted8Image;
import net.sourceforge.jiu.data.PixelImage;
import net.sourceforge.jiu.data.Palette;
import net.sourceforge.jiu.data.RGBIndex;
import net.sourceforge.jiu.ops.MissingParameterException;
import net.sourceforge.jiu.ops.OperationFailedException;
import net.sourceforge.jiu.ops.WrongParameterException;
/**
* A codec to write Compuserve GIF (Graphics Interchange Format) files.
* Supported image types
* When saving, classes implementing the following image data interfaces
* are supported:
* {@link net.sourceforge.jiu.data.BilevelImage},
* {@link net.sourceforge.jiu.data.Gray8Image} and
* {@link net.sourceforge.jiu.data.Paletted8Image}.
* GIF only supports up to 256 colors in an image, so
* you will have to use one of the quantization classes to reduce
* a truecolor image to 256 or less colors before you can save it
* with this codec.
* Supported I/O classes
* This codec supports {@link java.io.OutputStream}, {@link java.io.DataOutput}
* and {@link java.io.RandomAccessFile}.
* Bounds
* {@link net.sourceforge.jiu.codecs.ImageCodec}'s bounds concept is supported.
* A user of this codec can specify a rectangular part of the input image
* that will be saved instead of the complete image.
* Comments
* GIF - at least in its 89a version - allows for the inclusion of textual
* comments.
* When saving an image to a GIF file, each comment given to a codec
* will be stored in a comment extension block of its own.
* Usage example
* Save an image using this codec:
*
* GIFCodec codec = new GIFCodec();
* codec.appendComment("Bob and Susan at the Munich airport (2002-06-13).");
* codec.setImage(image); // BilevelImage, Gray8Image or Paletted8Image
* codec.setInterlacing(true);
* codec.setFile("output.gif", CodecMode.SAVE);
* codec.process();
* codec.close();
*
* Interlaced storage
* This codec allows creating interlaced and non-interlaced GIF files.
* The default is non-interlaced storage.
* Non-interlaced files store the rows top-to-bottom.
* GIF versions
* There are two versions of GIF, 87a and 89a.
* In 89a, several things were added to the file format specification.
* From the 89a features this codec only uses the possibility of storing textual comments
* in GIF files.
* Thus, the version used for writing depends on the return value of
* {@link #getNumComments()}.
* If there is at least one comment to be written to the file, version 89a
* will be used, 87a otherwise.
* Licensing of the LZW algorithm
* Unisys Corp. had a patent in several countries on the LZW algorithm used within GIF.
* However, this patent has expired (Japan being the last country
* where the patent expired, on July 7th 2004) so that LZW can be used freely.
* Licensing of the file format
* GIF was defined by Compuserve.
* In a technical document file called Gif89a.txt
that I found
* somewhere on the Net they grant a royalty-free license for use of the
* format to anyone - in order to improve the popularity of the format, I guess.
* I don't think that it should be possible to put a file format under a copyright,
* but all that Compuserve asks for in exchange for freely using the format
* is the inclusion of a message.
* So, here is that message:
*
* "The Graphics Interchange Format(c) is the Copyright property of
* CompuServe Incorporated. GIF(sm) is a Service Mark property of
* CompuServe Incorporated."
*
* Animated GIFs
* GIF allows for animations to be stored. This codec only supports storing
* a single image, though.
* File format background
* I've compiled a web page with
* technical
* information on GIF.
* @author Marco Schmidt
*/
public class GIFCodec extends ImageCodec
{
private static final int CODE_ARRAY_LENGTH = 5020;
private static final int[] INTERLACING_FIRST_ROW = {0, 4, 2, 1};
private static final int[] INTERLACING_INCREMENT = {8, 8, 4, 2};
private static final int NUM_INTERLACING_PASSES = 4;
private static final byte[] MAGIC_GIF87A = {71, 73, 70, 56, 55, (byte)97};
private static final byte[] MAGIC_GIF89A = {71, 73, 70, 56, 57, (byte)97};
private int backgroundColor;
private byte[] block;
private int bitOffset;
private int bitsPerPixel;
private int blockLength;
private int clearCode;
private int codeSize;
private int[] currentCode;
private int currentColumn;
private int currentInterlacingPass;
private int currentRow;
private int endOfInformationCode;
private boolean notFinished;
private int freeCode;
private IntegerImage imageToBeSaved;
private int initialCodeSize;
private boolean interlaced;
private int height;
private int maxCode;
private int[] newCode;
private int[] oldCode;
private DataOutput out;
private int processedRows;
private int width;
/**
* Returns the index of the background color.
* @return int value with the color (index into the palette) of the background color
* @see #setBackgroundColor
*/
public int getBackgroundColor()
{
return backgroundColor;
}
public String[] getFileExtensions()
{
return new String[] {".gif"};
}
public String getFormatName()
{
return "Compuserve GIF";
}
public String[] getMimeTypes()
{
return new String[] {"image/gif"};
}
private int getNextSample()
{
int result = imageToBeSaved.getSample(currentColumn++, currentRow);
if (currentColumn > getBoundsX2())
{
setProgress(processedRows++, getBoundsHeight());
currentColumn = getBoundsX1();
if (isInterlaced())
{
currentRow += INTERLACING_INCREMENT[currentInterlacingPass];
boolean done;
do
{
if (currentRow > getBoundsY2())
{
currentInterlacingPass++;
if (currentInterlacingPass < NUM_INTERLACING_PASSES)
{
currentRow = getBoundsY1() + INTERLACING_FIRST_ROW[currentInterlacingPass];
}
}
done = currentRow <= getBoundsY2() || currentInterlacingPass > NUM_INTERLACING_PASSES;
}
while (!done);
}
else
{
currentRow++;
}
notFinished = processedRows < getBoundsHeight();
}
return result;
}
private void initEncoding() throws IOException
{
imageToBeSaved = (IntegerImage)getImage();
currentColumn = getBoundsX1();
currentRow = getBoundsY1();
processedRows = 0;
currentInterlacingPass = 0;
notFinished = true;
block = new byte[255];
currentCode = new int[CODE_ARRAY_LENGTH];
newCode = new int[CODE_ARRAY_LENGTH];
oldCode = new int[CODE_ARRAY_LENGTH];
if (bitsPerPixel == 1)
{
initialCodeSize = 2;
}
else
{
initialCodeSize = bitsPerPixel;
}
}
/**
* Returns if the image will be stored in interlaced (true
)
* or non-interlaced mode (false
).
* @return interlacing mode
* @see #setInterlacing
*/
public boolean isInterlaced()
{
return interlaced;
}
public boolean isLoadingSupported()
{
return false;
}
public boolean isSavingSupported()
{
return true;
}
public void process() throws
MissingParameterException,
OperationFailedException
{
initModeFromIOObjects();
if (getMode() == CodecMode.LOAD)
{
throw new OperationFailedException("Loading is not supported.");
}
else
{
save();
}
}
private void resetBlock()
{
for (int i = 0; i < block.length; i++)
{
block[i] = 0;
}
blockLength = 0;
bitOffset = 0;
}
private void resetEncoder()
{
codeSize = initialCodeSize + 1;
clearCode = 1 << initialCodeSize;
endOfInformationCode = clearCode + 1;
freeCode = endOfInformationCode + 1;
maxCode = (1 << codeSize) - 1;
for (int i = 0; i < currentCode.length; i++)
{
currentCode[i] = 0;
}
}
private void save() throws
MissingParameterException,
OperationFailedException,
UnsupportedTypeException,
WrongParameterException
{
PixelImage image = getImage();
if (image == null)
{
throw new MissingParameterException("No image available for saving.");
}
width = image.getWidth();
height = image.getHeight();
setBoundsIfNecessary(width, height);
width = getBoundsWidth();
height = getBoundsHeight();
if (image instanceof Paletted8Image)
{
Palette palette = ((Paletted8Image)image).getPalette();
int numEntries = palette.getNumEntries();
if (numEntries < 1 || numEntries > 256)
{
throw new WrongParameterException("Palette of image to be saved must have 1..256 entries.");
}
bitsPerPixel = 8;
// determine minimum number of bits per pixel necessary to store image
for (int i = 1; i <= 8; i++)
{
if ((1 << i) >= numEntries)
{
bitsPerPixel = i;
break;
}
}
}
else
if (image instanceof Gray8Image)
{
bitsPerPixel = 8;
}
else
if (image instanceof BilevelImage)
{
bitsPerPixel = 1;
}
else
{
throw new UnsupportedTypeException("Unsupported image type: " + image.getClass().getName());
}
out = getOutputAsDataOutput();
if (out == null)
{
throw new MissingParameterException("Output stream / random access file parameter missing.");
}
// now write the output stream
try
{
writeStream();
}
catch (IOException ioe)
{
throw new OperationFailedException("I/O failure: " + ioe.toString());
}
}
/**
* Specify the value of the background color.
* Default is 0
.
* @param colorIndex int value with the color (index into the palette) of the background color
* @see #getBackgroundColor
*/
public void setBackgroundColor(int colorIndex)
{
backgroundColor = colorIndex;
}
/**
* Specifies whether the image will be stored in interlaced mode
* (true
) or non-interlaced mode (false
).
* @param useInterlacing boolean, if true interlaced mode, otherwise non-interlaced mode
* @see #isInterlaced()
*/
public void setInterlacing(boolean useInterlacing)
{
interlaced = useInterlacing;
}
private void writeBlock() throws IOException
{
if (bitOffset > 0)
{
blockLength++;
}
if (blockLength == 0)
{
return;
}
out.write(blockLength);
out.write(block, 0, blockLength);
resetBlock();
}
private void writeCode(int code) throws IOException
{
int remainingBits = codeSize;
do
{
int bitsFree = 8 - bitOffset;
int bits;
/* bits => number of bits to be copied from "code" to
"block[blockLength]" in this loop iteration */
if (bitsFree < remainingBits)
{
bits = bitsFree;
}
else
{
bits = remainingBits;
}
int value = block[blockLength] & 0xff;
value += (code & ((1 << bits) - 1)) << bitOffset;
block[blockLength] = (byte)value;
bitOffset += bits;
if (bitOffset == 8)
{
blockLength++;
bitOffset = 0;
if (blockLength == 255)
{
writeBlock();
}
}
code >>= bits;
remainingBits -= bits;
}
while (remainingBits != 0);
}
private void writeComments() throws IOException
{
if (getNumComments() < 1)
{
return;
}
for (int commentIndex = 0; commentIndex < getNumComments(); commentIndex++)
{
String comment = getComment(commentIndex);
byte[] data = comment.getBytes();
out.write(0x21); // extension introducer
out.write(0xfe); // comment label
int offset = 0;
while (offset < data.length)
{
int number = Math.min(data.length - offset, 255);
out.write(number);
out.write(data, offset, number);
offset += number;
}
out.write(0); // zero-length block
}
}
/**
* Writes a global header, a global palette and
* an image descriptor to output.
*/
private void writeHeader() throws IOException
{
// pick a GIF version; stay with 87a if possible (no comments included
// which require 89a)
byte[] magic;
if (getNumComments() > 0)
{
magic = MAGIC_GIF89A;
}
else
{
magic = MAGIC_GIF87A;
}
// global header
out.write(magic);
writeShort(width);
writeShort(height);
int depth = bitsPerPixel - 1;
/* meaning of packed byte
128 => there is a global palette following
(depth << 4) => the number of bits used for encoding
depth - 1 => the number of bits in the global palette (same as for encoding) */
int packed = 128 | (depth << 4) | depth;
out.write(packed);
out.write(backgroundColor);
int pixelAspectRatio = 0;
out.write(pixelAspectRatio);
// global palette
writePalette();
// write textual comments (if any) to file as extension blocks
writeComments();
// image descriptor
out.write(44); // comma
writeShort(0); // x1
writeShort(0); // y1
writeShort(width); // width
writeShort(height); // height
packed = 0;
if (isInterlaced())
{
packed |= 64;
}
out.write(packed); // flags
}
private void writeImage() throws IOException
{
out.write(initialCodeSize);
resetBlock();
resetEncoder();
writeCode(clearCode);
int suffixChar = getNextSample();
int prefixCode = suffixChar;
do
{
suffixChar = getNextSample();
int d = 1;
int hashIndex = (prefixCode ^ (suffixChar << 5)) % 5003;
boolean endInnerLoop;
do
{
if (currentCode[hashIndex] == 0)
{
writeCode(prefixCode);
d = freeCode;
if (freeCode <= 4095)
{
oldCode[hashIndex] = prefixCode;
newCode[hashIndex] = suffixChar;
currentCode[hashIndex] = freeCode;
freeCode++;
}
if (d > maxCode)
{
if (codeSize < 12)
{
codeSize++;
maxCode = (1 << codeSize) - 1;
}
else
{
writeCode(clearCode);
resetEncoder();
}
}
prefixCode = suffixChar;
break;
}
if (oldCode[hashIndex] == prefixCode && newCode[hashIndex] == suffixChar)
{
prefixCode= currentCode[hashIndex];
endInnerLoop = true;
}
else
{
hashIndex += d;
d += 2;
if (hashIndex > 5003)
{
hashIndex -= 5003;
}
endInnerLoop = false;
}
}
while (!endInnerLoop);
}
while (notFinished);
writeCode(prefixCode);
writeCode(endOfInformationCode);
writeBlock();
}
private void writePalette() throws IOException
{
PixelImage image = getImage();
if (image instanceof Paletted8Image)
{
Palette palette = ((Paletted8Image)image).getPalette();
int numEntries = 1 << bitsPerPixel;
for (int i = 0; i < numEntries; i++)
{
if (i < palette.getNumEntries())
{
out.write(palette.getSample(RGBIndex.INDEX_RED, i));
out.write(palette.getSample(RGBIndex.INDEX_GREEN, i));
out.write(palette.getSample(RGBIndex.INDEX_BLUE, i));
}
else
{
out.write(0);
out.write(0);
out.write(0);
}
}
}
else
if (image instanceof Gray8Image)
{
for (int i = 0; i < 256; i++)
{
out.write(i);
out.write(i);
out.write(i);
}
}
else
if (image instanceof BilevelImage)
{
out.write(0);
out.write(0);
out.write(0);
out.write(255);
out.write(255);
out.write(255);
}
}
private void writeShort(int value) throws IOException
{
out.write(value & 0xff);
out.write((value >> 8) & 0xff);
}
private void writeStream() throws IOException
{
initEncoding();
writeHeader();
writeImage();
writeTrailer();
}
private void writeTrailer() throws IOException
{
out.write(0); // zero-length block
out.write(59); // semicolon
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/ImageLoader.java 0000664 0000000 0000000 00000025437 10421160275 024313 0 ustar /*
* ImageLoader
*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.codecs;
import java.awt.Frame;
import java.awt.MediaTracker;
import java.awt.Toolkit;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.util.Vector;
import net.sourceforge.jiu.codecs.InvalidFileStructureException;
import net.sourceforge.jiu.codecs.InvalidImageIndexException;
import net.sourceforge.jiu.codecs.WrongFileFormatException;
import net.sourceforge.jiu.codecs.BMPCodec;
import net.sourceforge.jiu.codecs.IFFCodec;
import net.sourceforge.jiu.codecs.PCDCodec;
import net.sourceforge.jiu.codecs.PNGCodec;
import net.sourceforge.jiu.codecs.PNMCodec;
import net.sourceforge.jiu.codecs.PSDCodec;
import net.sourceforge.jiu.codecs.RASCodec;
import net.sourceforge.jiu.codecs.tiff.TIFFCodec;
import net.sourceforge.jiu.data.PixelImage;
import net.sourceforge.jiu.gui.awt.ImageCreator;
import net.sourceforge.jiu.ops.MissingParameterException;
import net.sourceforge.jiu.ops.OperationFailedException;
/**
* A convenience class with static methods to load images from files using JIU codecs.
* The load methods of this class try to load an image with all codecs registered with this class.
* This includes almost every codec that resides in the net.sourceforge.jiu.codecs
package.
* You can register additional codecs with {@link #registerCodecClass} or remove the usage
* of codecs with {@link #removeCodecClass}.
* Usage example
*
* PixelImage image = null;
* try
* {
* image = ImageLoader.load("image.tif");
* }
* catch (Exception e)
* {
* // handle exception
* }
*
* @author Marco Schmidt
*/
public class ImageLoader
{
// all elements of class String
private static Vector fileExtensions;
private static Vector imageCodecClasses;
static
{
imageCodecClasses = new Vector();
registerCodecClass(new BMPCodec());
registerCodecClass(new IFFCodec());
registerCodecClass(new PCDCodec());
registerCodecClass(new PNGCodec());
registerCodecClass(new PNMCodec());
registerCodecClass(new PSDCodec());
registerCodecClass(new RASCodec());
registerCodecClass(new TIFFCodec());
}
private ImageLoader()
{
}
/**
* Creates an instance of one of the codec classes known to ImageLoader.
* @param index 0-based index of codec number, maximum value is {@link #getNumCodecs} - 1
* @return new codec object or null
if no object could be instantiated
*/
public static ImageCodec createCodec(int index)
{
ImageCodec result = null;
if (index >= 0 && index < getNumCodecs())
{
Class c = (Class)imageCodecClasses.elementAt(index);
try
{
Object obj = c.newInstance();
if (obj != null && obj instanceof ImageCodec)
{
result = (ImageCodec)obj;
}
}
catch (IllegalAccessException iae)
{
// ignore
}
catch (InstantiationException ie)
{
// ignore
}
}
return result;
}
/**
* Returns a filename filter ({@link java.io.FilenameFilter}) that accepts files
* with name extensions typical for the image file formats known to ImageLoader.
* The filter could then be used in an file dialog like {@link java.awt.FileDialog}.
* null
on failure
*/
public static PixelImage load(File file) throws
IOException,
InvalidFileStructureException,
InvalidImageIndexException,
UnsupportedTypeException
{
return load(file, null);
}
/**
* Attempts to load an image from a file, notifying the
* argument progress listeners.
* @param file the file to load an image from
* @param listeners a Vector of ProgressListener objects to be notified
* @return an instance of a class implementing {@link PixelImage}
*/
public static PixelImage load(File file, Vector listeners) throws
IOException,
InvalidFileStructureException,
InvalidImageIndexException,
UnsupportedTypeException
{
for (int i = 0; i < getNumCodecs(); i++)
{
PixelImage result = null;
ImageCodec codec = null;
try
{
codec = createCodec(i);
codec.setFile(file, CodecMode.LOAD);
codec.addProgressListeners(listeners);
codec.process();
result = codec.getImage();
if (result != null)
{
return result;
}
}
catch (MissingParameterException mpe)
{
// ignore
}
catch (WrongFileFormatException wffe)
{
// ignore
}
catch (IOException ioe)
{
// ignore
}
catch (OperationFailedException ofe)
{
// ignore
//System.out.println("codec: " + ofe);
}
finally
{
if (codec != null)
{
codec.close();
}
}
}
return null;
}
/**
* Load an image from a file given by its name.
* Simply calls load(fileName, null).
* @param fileName name of the file from which an image is to be loaded
* @return the loaded image on success, null on failure
*/
public static PixelImage load(String fileName) throws
IOException,
InvalidFileStructureException,
InvalidImageIndexException,
UnsupportedTypeException
{
return load(fileName, null);
}
/**
* Attempts to load an image from the file with the given name,
* using the given list of progress listeners.
* @param fileName name of the file from which an image is to be loaded
* @param listeners a list of objects implementing ProgressListener
* @return the loaded image
*/
public static PixelImage load(String fileName, Vector listeners) throws
IOException,
InvalidFileStructureException,
InvalidImageIndexException,
UnsupportedTypeException
{
return load(new File(fileName), listeners);
}
public static PixelImage loadToolkitImageUri(String uri) throws
IOException,
InvalidFileStructureException,
InvalidImageIndexException,
UnsupportedTypeException
{
try
{
ImageLoader loader = new ImageLoader();
InputStream in = loader.getClass().getResourceAsStream(uri);
if (in == null)
{
return null;
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
int b;
while ((b = in.read()) != -1)
{
out.write(b);
}
in.close();
byte[] data = out.toByteArray();
java.awt.Image awtImage = Toolkit.getDefaultToolkit().createImage(data);
MediaTracker mediaTracker = new MediaTracker(new Frame());
mediaTracker.addImage(awtImage, 0);
try
{
mediaTracker.waitForID(0);
}
catch (InterruptedException ie)
{
return null;
}
PixelImage image = ImageCreator.convertImageToRGB24Image(awtImage);
return image;
}
catch (Exception e)
{
e.printStackTrace();
return null;
}
}
/**
* Registers a codec class with ImageLoader.
* The argument is an instance of the class to be registered.
* Note that the codec class must have an empty constructor.
*
* ImageLoader.registerCodecClass(new ACMEImageCodec());
*
*
*
* Compression
* The file format only allows for uncompressed storage.
*
* ASCII mode / binary mode
* PNM streams can be stored in binary mode or ASCII mode.
* ASCII mode files are text files with numbers representing the pixels.
* They become larger than their binary counterparts, but as they are
* very redundant they can be compressed well with archive programs.
* ASCII PGM and PPM files can have all kinds of maximum sample values,
* thus allowing for arbitrary precision.
* They are not restricted by byte limits.
* PBM streams always have two colors, no matter if they are ASCII or binary.
*
* Color depth for PGM / PPM
* DPI values
* PNM files cannot store the physical resolution in DPI.
*
* Number of images
* Only one image can be stored in a PNM file.
*
* Usage example - load an image from a PNM file
*
* PNMCodec codec = new PNMCodec();
* codec.setFile("test.ppm", CodecMode.LOAD);
* codec.process();
* codec.close();
* PixelImage image = codec.getImage();
*
*
* Usage example - save an image to a PNM file
*
* PNMCodec codec = new PNMCodec();
* BilevelImage myFax = ...; // initialize
* codec.setImage(myFax);
* codec.setFile("out.pbm", CodecMode.SAVE);
* codec.process();
* codec.close();
*
*
* @author Marco Schmidt
*/
public class PNMCodec extends ImageCodec
{
/**
* Image type constant for images of unknown type.
*/
public static final int IMAGE_TYPE_UNKNOWN = -1;
/**
* Image type constant for bilevel images, stored in PBM files.
*/
public static final int IMAGE_TYPE_BILEVEL = 0;
/**
* Image type constant for grayscale images, stored in PGM files.
*/
public static final int IMAGE_TYPE_GRAY = 1;
/**
* Image type constant for RGB truecolor images, stored in PPM files.
*/
public static final int IMAGE_TYPE_COLOR = 2;
private static final String[] IMAGE_TYPE_FILE_EXTENSIONS =
{".pbm", ".pgm", ".ppm"};
private Boolean ascii;
private int columns;
private int imageType;
private PushbackInputStream in;
private DataOutput out;
private int height;
private int maxSample;
private int width;
/**
* Attempts to find the appropriate image type by looking at a file's name.
* Ignores case when comparing.
* Returns {@link #IMAGE_TYPE_BILEVEL} for .pbm
,
* {@link #IMAGE_TYPE_GRAY} for .pgm
and
* {@link #IMAGE_TYPE_COLOR} for .ppm
.
* Otherwise, {@link #IMAGE_TYPE_UNKNOWN} is returned.
* To get a file extension given that you have an image type, use
* {@link #getTypicalFileExtension}.
*
* @param fileName the file name to be examined
* @return one of the IMAGE_TYPE_xxx
constants of this class
*/
public static int determineImageTypeFromFileName(String fileName)
{
if (fileName == null || fileName.length() < 4)
{
return IMAGE_TYPE_UNKNOWN;
}
String ext = fileName.substring(fileName.length() - 3);
ext = ext.toLowerCase();
for (int i = 0; i < IMAGE_TYPE_FILE_EXTENSIONS.length; i++)
{
if (IMAGE_TYPE_FILE_EXTENSIONS[i].equals(ext))
{
return i;
}
}
return IMAGE_TYPE_UNKNOWN;
}
/**
* Returns if ASCII mode was used for loading an image or will
* be used to store an image.
* @return true for ASCII mode, false for binary mode, null if that information is not available
* @see #setAscii
*/
public Boolean getAscii()
{
return ascii;
}
public String getFormatName()
{
return "Portable Anymap (PBM, PGM, PPM)";
}
public String[] getMimeTypes()
{
return new String[] {"image/x-ppm", "image/x-pgm", "image/x-pbm", "image/x-pnm",
"image/x-portable-pixmap", "image/x-portable-bitmap", "image/x-portable-graymap",
"image/x-portable-anymap"};
}
/**
* Returns the typical file extension (including leading dot) for an
* image type.
* Returns null
for {@link #IMAGE_TYPE_UNKNOWN}.
* To get the image type given that you have a file name, use
* {@link #determineImageTypeFromFileName}.
*
* @param imageType the image type for which the extension is required
* @return the file extension or null
*/
public static String getTypicalFileExtension(int imageType)
{
if (imageType >= 0 && imageType < IMAGE_TYPE_FILE_EXTENSIONS.length)
{
return IMAGE_TYPE_FILE_EXTENSIONS[imageType];
}
else
{
return null;
}
}
public boolean isLoadingSupported()
{
return true;
}
public boolean isSavingSupported()
{
return true;
}
/**
* Loads an image from a PNM input stream.
* It is assumed that a stream was given to this codec using {@link #setInputStream(InputStream)}.
*
* @return the image as an instance of a class that implements {@link IntegerImage}
* @throws InvalidFileStructureException if the input stream is not a valid PNM stream (or unsupported)
* @throws java.io.IOException if there were problems reading from the input stream
*/
private void load() throws
InvalidFileStructureException,
IOException,
MissingParameterException,
UnsupportedTypeException,
WrongFileFormatException,
WrongParameterException
{
InputStream is = getInputStream();
if (is != null)
{
if (is instanceof PushbackInputStream)
{
in = (PushbackInputStream)is;
}
else
{
in = new PushbackInputStream(is);
}
}
else
{
throw new MissingParameterException("InputStream object required for loading.");
}
loadType();
String resolutionLine = loadTextLine();
setResolution(resolutionLine);
setBoundsIfNecessary(width, height);
if (imageType == IMAGE_TYPE_BILEVEL)
{
maxSample = 1;
}
else
{
// load maximum value
String maxSampleLine = loadTextLine();
setMaximumSample(maxSampleLine);
}
if (maxSample > 65535)
{
throw new UnsupportedTypeException("Cannot deal with samples larger than 65535.");
}
checkImageResolution();
switch (imageType)
{
case(IMAGE_TYPE_BILEVEL):
{
loadBilevelImage();
break;
}
case(IMAGE_TYPE_COLOR):
{
loadColorImage();
break;
}
case(IMAGE_TYPE_GRAY):
{
loadGrayImage();
break;
}
default:
{
throw new UnsupportedTypeException("Cannot deal with image type.");
}
}
}
private int loadAsciiNumber() throws
InvalidFileStructureException,
IOException
{
boolean hasDigit = false;
int result = -1;
do
{
int b = in.read();
if (b >= 48 && b <= 57)
{
// decimal digit
if (hasDigit)
{
result = result * 10 + (b - 48);
}
else
{
hasDigit = true;
result = b - 48;
}
}
else
if (b == 32 || b == 10 || b == 13 || b == 9)
{
// whitespace
if (hasDigit)
{
if (result > maxSample)
{
throw new InvalidFileStructureException("Read number " +
"from PNM stream that is larger than allowed " +
"maximum sample value " + maxSample + " (" + result + ").");
}
return result;
}
// ignore whitespace
}
else
if (b == 35)
{
// the # character, indicating a comment row
if (hasDigit)
{
in.unread(b);
if (result > maxSample)
{
throw new InvalidFileStructureException("Read " +
"number from PNM stream that is larger than " +
"allowed maximum sample value " + maxSample +
" (" + result + ").");
}
return result;
}
do
{
b = in.read();
}
while (b != -1 && b != 10 && b != 13);
if (b == 13)
{
}
// put it into the comment list
}
else
if (b == -1)
{
// the end of file character
if (hasDigit)
{
if (result > maxSample)
{
throw new InvalidFileStructureException("Read number from PNM stream that is larger than allowed maximum sample value " +
maxSample + " (" + result + ")");
}
return result;
}
throw new InvalidFileStructureException("Unexpected end of file while reading ASCII number from PNM stream.");
}
else
{
throw new InvalidFileStructureException("Read invalid character from PNM stream: " + b +
" dec.");
}
}
while(true);
}
private void loadBilevelImage() throws
InvalidFileStructureException,
IOException,
WrongParameterException
{
PixelImage image = getImage();
if (image == null)
{
setImage(new MemoryBilevelImage(getBoundsWidth(), getBoundsHeight()));
}
else
{
if (!(image instanceof BilevelImage))
{
throw new WrongParameterException("Specified input image must implement BilevelImage for this image type.");
}
}
if (getAscii().booleanValue())
{
loadBilevelImageAscii();
}
else
{
loadBilevelImageBinary();
}
}
private void loadBilevelImageAscii() throws
InvalidFileStructureException,
IOException
{
BilevelImage image = (BilevelImage)getImage();
// skip the pixels of the first getBoundsY1() rows
int pixelsToSkip = width * getBoundsY1();
for (int i = 0; i < pixelsToSkip; i++)
{
loadAsciiNumber();
}
final int NUM_ROWS = getBoundsHeight();
final int COLUMNS = getBoundsWidth();
final int X1 = getBoundsX1();
int[] row = new int[width];
// now read and store getBoundsHeight() rows
for (int y = 0; y < NUM_ROWS; y++)
{
for (int x = 0; x < width; x++)
{
int value = loadAsciiNumber();
if (value == 0)
{
row[x] = BilevelImage.WHITE;
}
else
if (value == 1)
{
row[x] = BilevelImage.BLACK;
}
else
{
throw new InvalidFileStructureException("Loaded " +
"number for position x=" + x + ", y=" + (y + getBoundsY1()) +
" is neither 0 nor 1 in PBM stream: " + value);
}
}
image.putSamples(0, 0, y, COLUMNS, 1, row, X1);
setProgress(y, NUM_ROWS);
}
}
private void loadBilevelImageBinary() throws
InvalidFileStructureException,
IOException
{
BilevelImage image = (BilevelImage)getImage();
int bytesPerRow = (width + 7) / 8;
// skip the first getBoundsY1() rows
long bytesToSkip = (long)getBoundsY1() * (long)bytesPerRow;
// Note:
// removed in.skip(bytesToSkip) because that was only available in Java 1.2
// instead the following while loop is used
while (bytesToSkip-- > 0)
{
in.read();
}
// allocate buffer large enough for a complete row
byte[] row = new byte[bytesPerRow];
final int numRows = getBoundsHeight();
// read and store the next getBoundsHeight() rows
for (int y = 0; y < numRows; y++)
{
// read bytesPerRow bytes into row
int bytesToRead = bytesPerRow;
int index = 0;
while (bytesToRead > 0)
{
int result = in.read(row, index, bytesToRead);
if (result >= 0)
{
index += result;
bytesToRead -= result;
}
else
{
throw new InvalidFileStructureException("Unexpected end of input stream while reading.");
}
}
// invert values
for (int x = 0; x < row.length; x++)
{
row[x] = (byte)~row[x];
}
//image.putPackedBytes(0, y, bytesPerRow, buffer, 0);
if (isRowRequired(y))
{
image.putPackedBytes(0, y - getBoundsY1(), getBoundsWidth(), row, getBoundsX1() >> 3, getBoundsX1() & 7);
}
setProgress(y, numRows);
}
}
private void loadColorImage() throws InvalidFileStructureException, IOException
{
RGBIntegerImage image = null;
RGB24Image image24 = null;
if (maxSample <= 255)
{
image24 = new MemoryRGB24Image(width, height);
image = image24;
setImage(image);
}
else
{
image = new MemoryRGB48Image(width, height);
setImage(image);
}
for (int y = 0, destY = - getBoundsY1(); y < height; y++, destY++)
{
if (getAscii().booleanValue())
{
for (int x = 0; x < width; x++)
{
int red = loadAsciiNumber();
if (red < 0 || red > maxSample)
{
throw new InvalidFileStructureException("Invalid " +
"sample value " + red + " for red sample at " +
"(x=" + x + ", y=" + y + ").");
}
image.putSample(RGBIndex.INDEX_RED, x, y, red);
int green = loadAsciiNumber();
if (green < 0 || green > maxSample)
{
throw new InvalidFileStructureException("Invalid " +
"sample value " + green + " for green sample at " +
"(x=" + x + ", y=" + y + ").");
}
image.putSample(RGBIndex.INDEX_GREEN, x, y, green);
int blue = loadAsciiNumber();
if (blue < 0 || blue > maxSample)
{
throw new InvalidFileStructureException("Invalid " +
"sample value " + blue + " for blue sample at " +
"(x=" + x + ", y=" + y + ").");
}
image.putSample(RGBIndex.INDEX_BLUE, x, y, blue);
}
}
else
{
if (image24 != null)
{
for (int x = 0; x < width; x++)
{
int red = in.read();
if (red == -1)
{
throw new InvalidFileStructureException("Unexpected " +
"end of file while reading red sample for pixel " +
"x=" + x + ", y=" + y + ".");
}
image24.putByteSample(RGBIndex.INDEX_RED, x, y, (byte)(red & 0xff));
int green = in.read();
if (green == -1)
{
throw new InvalidFileStructureException("Unexpected " +
"end of file while reading green sample for pixel " +
"x=" + x + ", y=" + y + ".");
}
image24.putByteSample(RGBIndex.INDEX_GREEN, x, y, (byte)(green & 0xff));
int blue = in.read();
if (blue == -1)
{
throw new InvalidFileStructureException("Unexpected " +
"end of file while reading blue sample for pixel " +
"x=" + x + ", y=" + y + ".");
}
image24.putByteSample(RGBIndex.INDEX_BLUE, x, y, (byte)(blue & 0xff));
}
}
}
setProgress(y, getBoundsHeight());
}
}
private void loadGrayImage() throws InvalidFileStructureException, IOException, UnsupportedTypeException
{
final int WIDTH = getBoundsWidth();
final int HEIGHT = getBoundsHeight();
PixelImage pimage = getImage();
if (pimage == null)
{
if (maxSample < 256)
{
pimage = new MemoryGray8Image(WIDTH, HEIGHT);
}
else
if (maxSample < 65536)
{
pimage = new MemoryGray16Image(WIDTH, HEIGHT);
}
else
{
throw new UnsupportedTypeException("Gray images with more than 16 bits per pixel are not supported.");
}
setImage(pimage);
}
else
{
}
GrayIntegerImage image = (GrayIntegerImage)pimage;
int[] buffer = new int[width];
for (int y = 0, destY = -getBoundsY1(); destY < getBoundsHeight(); y++, destY++)
{
if (getAscii().booleanValue())
{
for (int x = 0; x < width; x++)
{
buffer[x] = loadAsciiNumber();
}
}
else
{
if (maxSample < 256)
{
for (int x = 0; x < width; x++)
{
buffer[x] = in.read();
}
}
else
{
for (int x = 0; x < width; x++)
{
int msb = in.read();
int lsb = in.read();
buffer[x] = (msb << 8) | lsb;
}
}
}
if (destY >= 0 && destY < getBoundsHeight())
{
image.putSamples(0, 0, destY, getBoundsWidth(), 1, buffer, getBoundsX1());
}
setProgress(y, getBoundsY2() + 1);
}
}
private String loadTextLine() throws InvalidFileStructureException, IOException
{
// load text lines until
// 1) a normal text line is found
// 2) an error occurs
// any comment lines starting with # are added to the
// comments Vector
boolean isComment;
StringBuffer sb;
do
{
sb = new StringBuffer();
int b;
boolean crOrLf;
do
{
b = in.read();
if (b == -1)
{
throw new InvalidFileStructureException("Unexpected end of file in PNM stream.");
}
crOrLf = (b == 0x0a || b == 0x0d);
if (!crOrLf)
{
sb.append((char)b);
}
}
while (!crOrLf);
if (b == 0x0d)
{
b = in.read();
if (b != 0x0a)
{
throw new InvalidFileStructureException("Unexpected end of file in PNM stream.");
}
}
isComment = (sb.length() > 0 && sb.charAt(0) == '#');
if (isComment)
{
//sb.deleteCharAt(0);
//sb.delete(0, 1);
StringBuffer result = new StringBuffer(sb.length() - 1);
int i = 1;
while (i < sb.length())
{
result.append(sb.charAt(i++));
}
appendComment(result.toString());
}
}
while (isComment);
return sb.toString();
}
/**
* Loads the first two characters (which are expected to be a capital P
* followed by a decimal digit between 1 and 6, inclusively) and skips
* following LF and CR characters.
* This method not only checks the two bytes, it also initializes internal fields
* for storage mode (ASCII or binary) and image type.
*
* @throws WrongFileFormatException if the input stream is not a PNM stream
* @throws InvalidFileStructureException if the format that
* is described above was not encountered
* @throws java.io.IOException if there were errors reading data
* @throws java.lang.IllegalArgumentException if the input stream was not given to this codec
*/
private void loadType() throws InvalidFileStructureException, IOException, WrongFileFormatException
{
// read two bytes
int v1 = in.read();
int v2 = in.read();
// check if first byte is P
if (v1 != 0x50)
{
throw new WrongFileFormatException("Not a PNM stream. First byte " +
"in PNM stream is expected to be 0x50 ('P'); found: " +
v1 + " (dec).");
}
// check if second byte is ASCII of digit from 1 to 6
if (v2 < 0x31 || v2 > 0x36)
{
throw new WrongFileFormatException("Not a PNM stream. Second byte " +
"in PNM stream is expected to be the ASCII value of decimal " +
"digit between 1 and 6 (49 dec to 54 dec); found " +
v2 + " dec.");
}
// determine mode (ASCII or binary) from second byte
ascii = new Boolean(v2 < 0x34);
// determine image type from second byte
v2 = v2 - 0x30;
imageType = (v2 - 1) % 3;
// skip LF and CR
int b;
do
{
b = in.read();
}
while (b == 0x0a || b == 0x0d || b == ' ');
if (b == -1)
{
throw new InvalidFileStructureException("Read type (" +
v2 + "). Unexpected end of file in input PNM stream.");
}
in.unread(b);
}
public void process() throws
MissingParameterException,
OperationFailedException
{
initModeFromIOObjects();
try
{
if (getMode() == CodecMode.LOAD)
{
load();
}
else
{
save();
}
}
catch (IOException ioe)
{
throw new OperationFailedException("I/O error: " + ioe.toString());
}
}
private void save() throws
IOException,
MissingParameterException,
WrongParameterException
{
out = getOutputAsDataOutput();
if (out == null)
{
throw new WrongParameterException("Cannot get a DataOutput object to use for saving.");
}
PixelImage pi = getImage();
if (pi == null)
{
throw new MissingParameterException("Input image missing.");
}
if (!(pi instanceof IntegerImage))
{
throw new WrongParameterException("Input image must implement IntegerImage.");
}
IntegerImage image = (IntegerImage)pi;
width = image.getWidth();
height = image.getHeight();
setBoundsIfNecessary(width, height);
if (image instanceof RGB24Image)
{
imageType = IMAGE_TYPE_COLOR;
maxSample = 255;
save((RGB24Image)image);
}
else
if (image instanceof RGB48Image)
{
imageType = IMAGE_TYPE_COLOR;
maxSample = 65535;
save((RGB48Image)image);
}
else
if (image instanceof BilevelImage)
{
imageType = IMAGE_TYPE_BILEVEL;
maxSample = 1;
save((BilevelImage)image);
}
else
if (image instanceof Gray8Image)
{
imageType = IMAGE_TYPE_GRAY;
maxSample = 255;
save((Gray8Image)image);
}
else
if (image instanceof Gray16Image)
{
imageType = IMAGE_TYPE_GRAY;
maxSample = 65535;
save((Gray16Image)image);
}
else
{
throw new WrongParameterException("Unsupported input image type: " +
image.getClass().getName());
}
close();
}
private void save(BilevelImage image) throws IOException
{
saveHeader();
final int WIDTH = getBoundsWidth();
final int HEIGHT = getBoundsHeight();
final int BYTES_PER_ROW = (WIDTH + 7) / 8;
byte[] buffer = new byte[BYTES_PER_ROW];
for (int y = 0, srcY = getBoundsY1(); y < HEIGHT; y++, srcY++)
{
if (getAscii().booleanValue())
{
for (int x = 0, srcX = getBoundsX1(); x < WIDTH; x++, srcX++)
{
if (image.isBlack(srcX, srcY))
{
out.write(49); // 1
}
else
{
out.write(48); // 0
}
columns ++;
if (columns > 70)
{
columns = 0;
out.write(10);
}
else
{
out.write(32);
columns++;
}
}
}
else
{
image.getPackedBytes(getBoundsX1(), srcY, WIDTH, buffer, 0, 0);
for (int x = 0; x < buffer.length; x++)
{
buffer[x] = (byte)(~buffer[x]);
}
out.write(buffer);
}
setProgress(y, HEIGHT);
}
}
private void save(Gray8Image image) throws IOException
{
saveHeader();
final int HEIGHT = getBoundsHeight();
final int WIDTH = getBoundsWidth();
final int X1 = getBoundsX1();
System.out.println(WIDTH + " " + HEIGHT + " " + X1);
byte[] buffer = new byte[WIDTH];
for (int y = 0, srcY = getBoundsY1(); y < HEIGHT; y++, srcY++)
{
image.getByteSamples(0, X1, srcY, WIDTH, 1, buffer, 0);
if (getAscii().booleanValue())
{
for (int x = 0; x < WIDTH; x++)
{
saveAsciiNumber(buffer[x] & 0xff);
out.write(32);
columns += 2;
if (columns > 70)
{
columns = 0;
out.write(10);
}
else
{
out.write(32);
columns++;
}
}
}
else
{
out.write(buffer);
}
setProgress(y, HEIGHT);
}
}
private void save(Gray16Image image) throws IOException
{
saveHeader();
final int HEIGHT = getBoundsHeight();
final int WIDTH = getBoundsWidth();
final int X1 = getBoundsX1();
short[] buffer = new short[WIDTH];
for (int y = 0, srcY = getBoundsY1(); y < HEIGHT; y++, srcY++)
{
image.getShortSamples(0, X1, srcY, WIDTH, 1, buffer, 0);
if (getAscii().booleanValue())
{
for (int x = 0; x < WIDTH; x++)
{
saveAsciiNumber(buffer[x] & 0xffff);
out.write(32);
columns += 4;
if (columns > 70)
{
columns = 0;
out.write(10);
}
else
{
out.write(32);
columns++;
}
}
}
else
{
for (int x = 0; x < WIDTH; x++)
{
int sample = buffer[x] & 0xffff;
out.write((sample >> 8) & 0xff);
out.write(sample & 0xff);
}
}
setProgress(y, HEIGHT);
}
}
private void save(RGB24Image image) throws IOException
{
saveHeader();
final int WIDTH = getBoundsWidth();
final int HEIGHT = getBoundsHeight();
for (int y = 0, srcY = getBoundsY1(); y < HEIGHT; y++, srcY++)
{
if (getAscii().booleanValue())
{
for (int x = 0, srcX = getBoundsX1(); x < WIDTH; x++, srcX++)
{
int red = image.getSample(RGBIndex.INDEX_RED, srcX, srcY);
int green = image.getSample(RGBIndex.INDEX_GREEN, srcX, srcY);
int blue = image.getSample(RGBIndex.INDEX_BLUE, srcX, srcY);
saveAsciiNumber(red);
out.write(32);
saveAsciiNumber(green);
out.write(32);
saveAsciiNumber(blue);
columns += 11;
if (columns > 80)
{
columns = 0;
out.write(10);
}
else
{
out.write(32);
columns++;
}
}
}
else
{
for (int x = 0, srcX = getBoundsX1(); x < WIDTH; x++, srcX++)
{
out.write(image.getSample(RGBIndex.INDEX_RED, srcX, srcY));
out.write(image.getSample(RGBIndex.INDEX_GREEN, srcX, srcY));
out.write(image.getSample(RGBIndex.INDEX_BLUE, srcX, srcY));
}
}
setProgress(y, HEIGHT);
}
}
private void save(RGB48Image image) throws IOException
{
saveHeader();
final int WIDTH = getBoundsWidth();
final int HEIGHT = getBoundsHeight();
for (int y = 0, srcY = getBoundsY1(); y < HEIGHT; y++, srcY++)
{
if (getAscii().booleanValue())
{
for (int x = 0, srcX = getBoundsX1(); x < WIDTH; x++, srcX++)
{
int red = image.getSample(RGBIndex.INDEX_RED, srcX, srcY);
int green = image.getSample(RGBIndex.INDEX_GREEN, srcX, srcY);
int blue = image.getSample(RGBIndex.INDEX_BLUE, srcX, srcY);
saveAsciiNumber(red);
out.write(32);
saveAsciiNumber(green);
out.write(32);
saveAsciiNumber(blue);
columns += 13;
if (columns > 80)
{
columns = 0;
out.write(10);
}
else
{
out.write(32);
columns++;
}
}
}
else
{
/*
for (int x = 0, srcX = getBoundsX1(); x < WIDTH; x++, srcX++)
{
out.write(image.getSample(RGBIndex.INDEX_RED, srcX, srcY));
out.write(image.getSample(RGBIndex.INDEX_GREEN, srcX, srcY));
out.write(image.getSample(RGBIndex.INDEX_BLUE, srcX, srcY));
}
*/
}
setProgress(y, HEIGHT);
}
}
private void saveAsciiNumber(int number) throws
IOException
{
String s = Integer.toString(number);
for (int i = 0; i < s.length(); i++)
{
char c = s.charAt(i);
out.write(c);
}
columns += s.length();
}
private void saveHeader() throws IOException
{
out.write(80); // 'P'
int pnmType = 49 + imageType;
if (getAscii() == null)
{
setAscii(maxSample > 255);
}
if (!getAscii().booleanValue())
{
pnmType += 3;
}
out.write(pnmType); // '1' .. '6'
out.write(10); // line feed
saveAsciiNumber(getBoundsWidth());
out.write(32); // space
saveAsciiNumber(getBoundsHeight());
out.write(10); // line feed
if (imageType != IMAGE_TYPE_BILEVEL)
{
// bilevel max sample is always 1 and MUST NOT be saved
saveAsciiNumber(maxSample);
out.write(10);// line feed
}
}
/**
* Specify whether ASCII mode is to be used when saving an image.
* Default is binary mode.
* @param asciiMode if true, ASCII mode is used, binary mode otherwise
*/
public void setAscii(boolean asciiMode)
{
ascii = new Boolean(asciiMode);
}
private void setMaximumSample(String line) throws InvalidFileStructureException
{
line = line.trim();
try
{
maxSample = Integer.parseInt(line);
}
catch (NumberFormatException nfe)
{
throw new InvalidFileStructureException("Not a valid value for the maximum sample: " + line);
}
if (maxSample < 0)
{
throw new InvalidFileStructureException("The value for the maximum sample must not be negative; found " + maxSample);
}
}
/*
* Reads resolution from argument String and sets private variables
* width and height.
*/
private void setResolution(String line) throws InvalidFileStructureException
{
line = line.trim();
StringTokenizer st = new StringTokenizer(line, " ");
try
{
if (!st.hasMoreTokens())
{
throw new InvalidFileStructureException("No width value found in line \"" +
line + "\".");
}
String number = st.nextToken();
try
{
width = Integer.parseInt(number);
}
catch (NumberFormatException nfe)
{
throw new InvalidFileStructureException("Not a valid int value for width: " +
number);
}
if (width < 1)
{
throw new InvalidFileStructureException("The width value must be larger than " +
"zero; found " + width + ".");
}
if (!st.hasMoreTokens())
{
throw new InvalidFileStructureException("No height value found in line \"" +
line + "\".");
}
number = st.nextToken();
try
{
height = Integer.parseInt(number);
}
catch (NumberFormatException nfe)
{
throw new InvalidFileStructureException("Not a valid int value for height: " +
number);
}
if (height < 1)
{
throw new InvalidFileStructureException("The height value must be larger than " +
"zero; found " + width + ".");
}
}
catch (NoSuchElementException nsee)
{
// should not happen because we always check if there is a token
}
}
public String suggestFileExtension(PixelImage image)
{
if (image == null)
{
return null;
}
if (image instanceof BilevelImage)
{
return IMAGE_TYPE_FILE_EXTENSIONS[IMAGE_TYPE_BILEVEL];
}
else
if (image instanceof GrayImage)
{
return IMAGE_TYPE_FILE_EXTENSIONS[IMAGE_TYPE_GRAY];
}
else
if (image instanceof RGB24Image)
{
return IMAGE_TYPE_FILE_EXTENSIONS[IMAGE_TYPE_COLOR];
}
return null;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/RASCodec.java 0000664 0000000 0000000 00000030555 07741250131 023524 0 ustar /*
* RASCodec
*
* Copyright (c) 2000, 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.codecs;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import net.sourceforge.jiu.codecs.ImageCodec;
import net.sourceforge.jiu.codecs.InvalidFileStructureException;
import net.sourceforge.jiu.codecs.UnsupportedTypeException;
import net.sourceforge.jiu.codecs.WrongFileFormatException;
import net.sourceforge.jiu.data.BilevelImage;
import net.sourceforge.jiu.data.Gray8Image;
import net.sourceforge.jiu.data.IntegerImage;
import net.sourceforge.jiu.data.MemoryPaletted8Image;
import net.sourceforge.jiu.data.MemoryRGB24Image;
import net.sourceforge.jiu.data.Palette;
import net.sourceforge.jiu.data.Paletted8Image;
import net.sourceforge.jiu.data.PixelImage;
import net.sourceforge.jiu.data.RGB24Image;
import net.sourceforge.jiu.data.RGBIndex;
import net.sourceforge.jiu.ops.OperationFailedException;
import net.sourceforge.jiu.ops.WrongParameterException;
import net.sourceforge.jiu.util.ArrayConverter;
/**
* A codec to read and write Sun Raster (RAS) image files.
* The typical file extension for this format is .ras
.
* Usage example
* This code snippet demonstrate how to read a RAS file.
*
* RASCodec codec = new RASCodec();
* codec.setFile("image.ras", CodecMode.LOAD);
* codec.process();
* PixelImage loadedImage = codec.getImage();
*
* Supported file types when reading
* Only uncompressed RAS files are read.
* Only 8 bit (gray and paletted) and 24 bit are supported when reading.
* Supported image types when writing
* Only {@link net.sourceforge.jiu.data.Paletted8Image} / uncompressed is supported when writing.
* Bounds
* The bounds concept of ImageCodec is supported so that you can load or save only part of an image.
* File format documentation
* This file format is documented as a man page rasterfile(5)
on Sun Unix systems.
* That documentation can also be found online, e.g. at
* http://www.doc.ic.ac.uk/~mac/manuals/sunos-manual-pages/sunos4/usr/man/man5/rasterfile.5.html.
* A web search for rasterfile(5)
* brings up other places as well.
*
* @author Marco Schmidt
*/
public class RASCodec extends ImageCodec
{
private static final int RAS_MAGIC = 0x59a66a95;
private static final int COMPRESSION_NONE = 0x00000001;
private static final int RAS_HEADER_SIZE = 32;
private int width;
private int height;
private int depth;
private int length;
private int type;
private int mapType;
private int mapLength;
private int bytesPerRow;
private int paddingBytes;
private int numColors;
private DataInput in;
private DataOutput out;
private Palette palette;
public String getFormatName()
{
return "Sun Raster (RAS)";
}
public String[] getMimeTypes()
{
return new String[] {"image/x-ras"};
}
public boolean isLoadingSupported()
{
return true;
}
public boolean isSavingSupported()
{
return true;
}
/**
* Loads an image from an RAS input stream.
* It is assumed that a stream was given to this codec using {@link #setInputStream(InputStream)}.
*
* @return the image as an instance of a class that implements {@link IntegerImage}
* @throws InvalidFileStructureException if the input stream is corrupt
* @throws java.io.IOException if there were problems reading from the input stream
* @throws UnsupportedTypeException if an unsupported flavor of the RAS format is encountered
* @throws WrongFileFormatException if this is not a valid RAS stream
*/
private void load() throws
IOException,
OperationFailedException
{
in = getInputAsDataInput();
readHeader();
readImage();
}
public void process() throws OperationFailedException
{
try
{
initModeFromIOObjects();
if (getMode() == CodecMode.LOAD)
{
load();
}
else
if (getMode() == CodecMode.SAVE)
{
save();
}
else
{
throw new WrongParameterException("Could find neither objects for loading nor for saving.");
}
}
catch (IOException ioe)
{
throw new OperationFailedException("I/O error in RAS codec: " + ioe.toString());
}
}
private void readHeader() throws
InvalidFileStructureException,
UnsupportedTypeException,
WrongFileFormatException,
WrongParameterException,
java.io.IOException
{
byte[] header = new byte[RAS_HEADER_SIZE];
in.readFully(header);
int magic = ArrayConverter.getIntBE(header, 0);
if (magic != RAS_MAGIC)
{
throw new WrongFileFormatException("This stream is not a valid " +
"Sun RAS stream (bad magic: " + Integer.toHexString(magic) +
" instead of " + Integer.toHexString(RAS_MAGIC));
}
width = ArrayConverter.getIntBE(header, 4);
height = ArrayConverter.getIntBE(header, 8);
if (width < 1 || height < 1)
{
throw new InvalidFileStructureException("Width and height must both " +
"be larger than zero; found width=" + width + ", height=" +
height + ".");
}
setBoundsIfNecessary(width, height);
checkBounds(width, height);
depth = ArrayConverter.getIntBE(header, 12);
switch (depth)
{
case(1):
{
bytesPerRow = (width + 7) / 8;
break;
}
case(8):
{
bytesPerRow = width;
break;
}
case(24):
{
bytesPerRow = width * 3;
break;
}
default:
{
throw new UnsupportedTypeException("Depths other than 1, 8 and 24 " +
"unsupported when reading RAS stream; found " + depth);
}
}
paddingBytes = (bytesPerRow % 2);
numColors = 1 << depth;
//length = ArrayConverter.getIntBE(header, 16);
type = ArrayConverter.getIntBE(header, 20);
if (type != COMPRESSION_NONE)
{
throw new UnsupportedTypeException("Only uncompressed " +
"RAS streams are read; found " + type);
}
mapType = ArrayConverter.getIntBE(header, 24);
mapLength = ArrayConverter.getIntBE(header, 28);
if (mapLength != 0)
{
if (depth != 8)
{
throw new UnsupportedTypeException("Cannot handle Sun RAS " +
"input streams with color maps and a depth other than " +
"8 (found " + depth + ").");
}
if (mapLength != 768)
{
throw new UnsupportedTypeException("Cannot handle Sun RAS " +
"input streams with color maps of a length different " +
"than 768; found " + mapLength);
}
if (mapType != 1)
{
throw new UnsupportedTypeException("Cannot handle Sun RAS " +
"input streams with color maps of a type other than " +
"1; found " + mapType);
}
palette = readPalette();
}
else
{
palette = null;
}
}
private IntegerImage readImage() throws
InvalidFileStructureException,
java.io.IOException
{
RGB24Image rgb24Image = null;
Paletted8Image paletted8Image = null;
IntegerImage result = null;
int numChannels = 1;
int bytesPerRow = 0;
switch(depth)
{
case(8):
{
paletted8Image = new MemoryPaletted8Image(width, height, palette);
result = paletted8Image;
numChannels = 1;
bytesPerRow = width;
break;
}
case(24):
{
rgb24Image = new MemoryRGB24Image(width, height);
result = rgb24Image;
numChannels = 3;
bytesPerRow = width;
break;
}
}
setImage(result);
byte[][] buffer = new byte[numChannels][];
for (int i = 0; i < numChannels; i++)
{
buffer[i] = new byte[bytesPerRow];
}
for (int y = 0, destY = -getBoundsY1(); destY <= getBoundsY2(); y++, destY++)
{
if (rgb24Image != null)
{
for (int x = 0; x < width; x++)
{
buffer[RGBIndex.INDEX_BLUE][x] = in.readByte();
buffer[RGBIndex.INDEX_GREEN][x] = in.readByte();
buffer[RGBIndex.INDEX_RED][x] = in.readByte();
}
rgb24Image.putByteSamples(RGBIndex.INDEX_RED, 0, destY, getBoundsWidth(), 1, buffer[0], getBoundsX1());
rgb24Image.putByteSamples(RGBIndex.INDEX_GREEN, 0, destY, getBoundsWidth(), 1, buffer[1], getBoundsX1());
rgb24Image.putByteSamples(RGBIndex.INDEX_BLUE, 0, destY, getBoundsWidth(), 1, buffer[2], getBoundsX1());
}
else
if (paletted8Image != null)
{
in.readFully(buffer[0], 0, width);
paletted8Image.putByteSamples(0, 0, destY, getBoundsWidth(), 1, buffer[0], getBoundsX1());
}
if (in.skipBytes(paddingBytes) != paddingBytes)
{
throw new InvalidFileStructureException("Could not skip " +
"byte after row " + y + ".");
}
setProgress(y, getBoundsY2() + 1);
}
return result;
}
private Palette readPalette() throws
InvalidFileStructureException,
java.io.IOException
{
Palette result = new Palette(256, 255);
for (int channel = 0; channel < 3; channel++)
{
int channelIndex = -1;
switch(channel)
{
case(0):
{
channelIndex = Palette.INDEX_RED;
break;
}
case(1):
{
channelIndex = Palette.INDEX_GREEN;
break;
}
case(2):
{
channelIndex = Palette.INDEX_BLUE;
break;
}
}
for (int i = 0; i < numColors; i++)
{
int value = in.readUnsignedByte();
if (value == -1)
{
throw new InvalidFileStructureException("Unexpected end " +
"of file when reading Sun RAS palette.");
}
result.putSample(channelIndex, i, value);
}
}
return result;
}
private void save() throws
IOException,
UnsupportedTypeException,
WrongParameterException
{
PixelImage image = getImage();
if (image == null || (!(image instanceof Paletted8Image)))
{
throw new UnsupportedTypeException("Must have non-null image that is a Paletted8Image.");
}
saveHeader(image);
if (image instanceof Paletted8Image)
{
saveData((Paletted8Image)image);
}
}
private void saveData(Paletted8Image image) throws IOException
{
byte[] row = new byte[getBoundsWidth()];
for (int y1 = 0, y2 = getBoundsY1(); y1 < getBoundsHeight(); y1++, y2++)
{
image.getByteSamples(0, getBoundsX1(), y2, row.length, 1, row, 0);
out.write(row);
int num = paddingBytes;
while (num-- > 0)
{
out.write(0);
}
setProgress(y1, getBoundsHeight());
}
}
private void saveHeader(PixelImage image) throws
IOException,
UnsupportedTypeException,
WrongParameterException
{
setBoundsIfNecessary(width, height);
checkBounds(width, height);
out.writeInt(RAS_MAGIC);
int width = getBoundsWidth();
out.writeInt(width);
int height = getBoundsHeight();
out.writeInt(height);
if (image instanceof BilevelImage)
{
depth = 1;
bytesPerRow = (width + 7) / 8;
}
else
if (image instanceof Gray8Image ||
image instanceof Paletted8Image)
{
depth = 8;
bytesPerRow = width;
}
else
if (image instanceof RGB24Image)
{
bytesPerRow = width * 3;
depth = 24;
}
else
{
throw new UnsupportedTypeException("Cannot store image types " +
"other than bilevel, gray8, paletted8 and RGB24.");
}
out.writeInt(depth);
paddingBytes = (bytesPerRow % 2);
numColors = 1 << depth;
length = bytesPerRow * getBoundsHeight();
out.writeInt(length); // length
out.writeInt(COMPRESSION_NONE); // type
mapType = 1;
mapLength = 0;
if (image instanceof Paletted8Image)
{
mapLength = 768;
}
out.writeInt(mapType);
out.writeInt(mapLength);
if (image instanceof Paletted8Image)
{
Paletted8Image pal = (Paletted8Image)image;
savePalette(pal.getPalette());
}
}
private void savePalette(Palette palette) throws java.io.IOException
{
int numEntries = palette.getNumEntries();
for (int channel = 0; channel < 3; channel++)
{
int channelIndex = -1;
switch(channel)
{
case(0):
{
channelIndex = Palette.INDEX_RED;
break;
}
case(1):
{
channelIndex = Palette.INDEX_GREEN;
break;
}
case(2):
{
channelIndex = Palette.INDEX_BLUE;
break;
}
}
for (int i = 0; i < 256; i++)
{
int value = 0;
if (i < numEntries)
{
value = palette.getSample(channelIndex, i);
}
out.write(value);
}
}
}
public String suggestFileExtension(PixelImage image)
{
return ".ras";
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/ImageCodec.java 0000664 0000000 0000000 00000064272 10377274111 024127 0 ustar /*
* ImageCodec
*
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.codecs;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.util.Vector;
import net.sourceforge.jiu.ops.MissingParameterException;
import net.sourceforge.jiu.ops.Operation;
import net.sourceforge.jiu.ops.WrongParameterException;
import net.sourceforge.jiu.data.PixelImage;
/**
* The base class for image codecs, operations to read images from or write them to streams.
* A codec should support one file format only.
* The word codec is derived from enCOder DECoder.
*
* Usage
* The codecs differ quite a bit in what they support.
* But here are two code snippets that demonstrate how to do loading and saving in general.
*
* Load image
*
* ImageCodec codec = new BMPCodec(); // BMPCodec is just an example
* codec.setFile("image.bmp", CodecMode.LOAD);
* codec.process();
* PixelImage image = codec.getImage();
*
*
* Save image
*
* PixelImage image = ...; // the image to be saved
* ImageCodec codec = new BMPCodec(); // BMPCodec is just an example
* codec.setFile("image.bmp", CodecMode.SAVE);
* codec.setImage(image);
* codec.process();
*
*
* I/O objects
* There are several set and get methods for I/O objects, including
* DataInput, DataOutput, InputStream, OutputStream and RandomAccessFile.
* If you are just using the codec (and not developing one) make it easier
* for yourself and use {@link #setFile(String, CodecMode)}.
* That way the picking of the right type of I/O class and the creation of a
* buffered stream wrapper is done automatically.
* Mode
* Codecs can be used to save images or load them, or both.
* As was g; by default, no mode (of enumeration type {@link CodecMode})
* is specified and {@link #getMode()} returns null
.
* Mode only has two possible values, {@link CodecMode#LOAD} and
* {@link CodecMode#SAVE}.
* In some cases, the codec can find out whether to load or save from the I/O objects
* that were given to it; if it has an input stream, something must be loaded,
* if it has an output stream, something is to be saved.
* If a codec demands a {@link RandomAccessFile}, there is no way to find out
* the mode automatically, that is why {@link #setRandomAccessFile} also has an
* argument of type {@link CodecMode}.
* Textual comments
* Some file formats allow for the inclusion of textual comments, to
* store a description, creator, copyright owner or anything else within the image
* file without actually drawing that text on the image itself.
* Some codecs support reading and writing of comments.
*
* Other methods
* null
.
* However, it is encouraged that codec implementors provide this method as well.
* Most file formats only have one typical extension (e. g. .bmp
).
* However, for a file format like PNM, the extension depends on the image type (a grayscale
* image would end in .pgm
, a color image in .ppm
).
* (0, 0) / (width - 1, height - 1)
.
* If the bounds are incorrect, a {@link WrongParameterException}
* is thrown, otherwise nothing happens.
* To be used within codecs that support the bounds concept.
*/
public void checkBounds(int width, int height) throws WrongParameterException
{
if (!hasBounds())
{
return;
}
int x1 = getBoundsX1();
if (x1 >= width)
{
throw new WrongParameterException("Codec bounds x1 (" + x1 +
") must be smaller than image width (" + width + ").");
}
int x2 = getBoundsX2();
if (x2 >= width)
{
throw new WrongParameterException("Codec bounds x2 (" + x2 +
") must be smaller than image width (" + width + ").");
}
int y1 = getBoundsY1();
if (y1 >= height)
{
throw new WrongParameterException("Codec bounds y1 (" + y1 +
") must be smaller than image height (" + height + ").");
}
int y2 = getBoundsY2();
if (y2 >= height)
{
throw new WrongParameterException("Codec bounds y2 (" + y2 +
") must be smaller than image height (" + height + ").");
}
}
/**
* If an image object was provided to be used for loading via {@link #setImage},
* this method checks if its resolution is the same as the bounds' resolution.
* If the two differ, a {@link net.sourceforge.jiu.ops.WrongParameterException} is thrown.
* @throws WrongParameterException if image resolution and bounds dimension differ
*/
public void checkImageResolution() throws WrongParameterException
{
PixelImage image = getImage();
if (image != null)
{
if (image.getWidth() != getBoundsWidth())
{
throw new WrongParameterException("Specified input image must have width equal to getBoundsWidth().");
}
if (image.getHeight() != getBoundsHeight())
{
throw new WrongParameterException("Specified input image must have height equal to getBoundsHeight().");
}
}
}
/**
* Calls the close method of all input and output I/O objects
* that were given to this object.
* Catches and ignores any IOException objects that may be
* thrown in the process.
* Note that not all I/O objects have a close method (e.g. {@link java.io.DataInput}
* and {@link java.io.DataOutput} have not).
*/
public void close()
{
try
{
if (in != null)
{
in.close();
}
if (out != null)
{
out.close();
}
if (raf != null)
{
raf.close();
}
}
catch (IOException ioe)
{
}
}
/**
* Returns x coordinate of the upper left corner of the bounds.
* Bounds must have been specified using {@link #setBounds(int, int, int, int)},
* otherwise the return value is undefined.
* @return x coordinate of the upper left corner of the bounds
*/
public int getBoundsX1()
{
return boundsX1;
}
/**
* Returns x coordinate of the lower right corner of the bounds.
* Bounds must have been specified using {@link #setBounds(int, int, int, int)},
* otherwise the return value is undefined.
* @return x coordinate of the lower right corner of the bounds
*/
public int getBoundsX2()
{
return boundsX2;
}
/**
* Returns y coordinate of the upper left corner of the bounds.
* Bounds must have been specified using {@link #setBounds(int, int, int, int)},
* otherwise the return value is undefined.
* @return y coordinate of the upper left corner of the bounds
*/
public int getBoundsY1()
{
return boundsY1;
}
/**
* Returns y coordinate of the lower right corner of the bounds.
* Bounds must have been specified using {@link #setBounds(int, int, int, int)},
* otherwise the return value is undefined.
* @return y coordinate of the lower right corner of the bounds
*/
public int getBoundsY2()
{
return boundsY2;
}
/**
* Returns the height of the rectangle specified by bounds.
* Bounds must have been specified using {@link #setBounds(int, int, int, int)},
* otherwise the return value is undefined.
* This equals {@link #getBoundsY2()} - {@link #getBoundsY1()} + 1.
* @return height of bounds rectangle
*/
public int getBoundsHeight()
{
return boundsHeight;
}
/**
* Returns the width of the rectangle specified by bounds.
* Bounds must have been specified using {@link #setBounds(int, int, int, int)},
* otherwise the return value is undefined.
* This equals {@link #getBoundsX2()} - {@link #getBoundsX1()} + 1.
* @return width of bounds rectangle
*/
public int getBoundsWidth()
{
return boundsWidth;
}
/**
* Returns a comment from the internal list of comments.
* @param index the index of the comment to be returned, must be from
* 0
to {@link #getNumComments()} - 1
; if this is not
* the case, null
will be returned
* @see #getNumComments
* @see #appendComment
* @see #removeAllComments
*/
public String getComment(int index)
{
if (index >= 0 && index < comments.size())
{
return (String)comments.elementAt(index);
}
else
{
return null;
}
}
/**
* Returns a {@link java.io.DataInput} object if one was provided
* via {@link #setDataInput(DataInput)} or null
otherwise.
* @return the DataInput object
*/
public DataInput getDataInput()
{
return din;
}
/**
* Returns a {@link java.io.DataOutput} object if one was provided
* via {@link #setDataOutput(DataOutput)} or null
otherwise.
* @return the DataInput object
*/
public DataOutput getDataOutput()
{
return dout;
}
/**
* Returns the horizontal physical resolution of the image associated
* with this codec.
* This resolution value was either retrieved from an image file or
* set via {@link #setDpi(int, int)}.
* @return horizontal physical resolution in dpi
* @see #getDpiY
*/
public int getDpiX()
{
return dpiX;
}
/**
* Returns the vertical physical resolution of the image associated
* with this codec.
* This resolution value was either retrieved from an image file or
* set via {@link #setDpi(int, int)}.
* @return horizontal physical resolution in dpi
* @see #getDpiX
*/
public int getDpiY()
{
return dpiY;
}
/**
* Returns all file extensions that are typical for this file format.
* The default implementation in ImageCodec returns null
.
* The file extension strings should include a leading dot
* and are supposed to be lower case (if that is allowed for
* the given file format).
* Example: {".jpg", ".jpeg"}
for the JPEG file format.
* @return String array with typical file extensions
*/
public String[] getFileExtensions()
{
return null;
}
/**
* Returns the name of the file format supported by this codec.
* All classes extending {@link ImageCodec} must override this method.
* When overriding, leave out any words in a particular language so
* that this format name can be understood by everyone.
* Usually it is enough to return the format creator plus a typical
* abbreviation, e.g. Microsoft BMP
or Portable Anymap (PNM)
.
* @return name of the file format supported by this codec
*/
public abstract String getFormatName();
/**
* Returns the image object stored in this codec.
* This is either an image given to this object via
* {@link #setImage(PixelImage)} or it was created by the codec
* itself during a loading operation.
* @return PixelImage object stored in this codec
*/
public PixelImage getImage()
{
return image;
}
/**
* Returns the zero-based index of the image to be loaded.
* Default is zero.
* @return zero-based image index value
*/
public int getImageIndex()
{
return imageIndex;
}
/**
* Returns a {@link java.io.DataInput} object if one was specified
* using {@link #setDataInput(DataInput)},
* or creates a {@link java.io.DataInputStream} if an
* {@link java.io.InputStream} was specified,
* or returns a {@link java.io.RandomAccessFile} if one was specified
* (RandomAccessFile implements DataInput).
* If neither of those has been given to this object, null
is returned.
* @return DataInput object or null
*/
public DataInput getInputAsDataInput()
{
DataInput din = getDataInput();
if (din != null)
{
return din;
}
RandomAccessFile raf = getRandomAccessFile();
if (getMode() == CodecMode.LOAD && raf != null)
{
return raf;
}
InputStream in = getInputStream();
if (in != null)
{
if (in instanceof DataInput)
{
return (DataInput)in;
}
else
{
return new DataInputStream(in);
}
}
return null;
}
/**
* Returns an {@link java.io.InputStream} object that was given to
* this codec via {@link #setInputStream(InputStream)}
* (or null
otherwise).
* @return InputStream object
*/
public InputStream getInputStream()
{
return in;
}
/**
* Return the MIME
* (Multipurpose Internet Mail Extensions) type strings for this format, or null
* if none are available.
* @return MIME type strings or null
*/
public abstract String[] getMimeTypes();
/**
* Returns the mode this codec is in.
* Can be null
, so that the codec will have to find out
* itself what to do.
* @return codec mode (load or save)
*/
public CodecMode getMode()
{
return mode;
}
/**
* Returns the current number of comments in the internal comment list.
* @return number of comments in the internal comment list
*/
public int getNumComments()
{
return comments.size();
}
/**
* Attempts to return an output object as a {@link java.io.DataOutput} object.
* @return a DataOutput object or null if that was not possible
*/
public DataOutput getOutputAsDataOutput()
{
DataOutput dout = getDataOutput();
if (dout != null)
{
return dout;
}
OutputStream out = getOutputStream();
if (out != null)
{
if (out instanceof DataOutput)
{
return (DataOutput)out;
}
else
{
return new DataOutputStream(out);
}
}
RandomAccessFile raf = getRandomAccessFile();
if (raf != null && getMode() == CodecMode.SAVE)
{
return raf;
}
return null;
}
/**
* Returns an {@link java.io.OutputStream} object that was given to
* this codec via {@link #setOutputStream(OutputStream)}
* (or null
otherwise).
* @return OutputStream object
*/
public OutputStream getOutputStream()
{
return out;
}
/**
* Returns a {@link java.io.RandomAccessFile} object that was given to
* this codec via {@link #setRandomAccessFile(RandomAccessFile, CodecMode)}
* (or null
otherwise).
* @return RandomAccessFile object
*/
public RandomAccessFile getRandomAccessFile()
{
return raf;
}
/**
* Returns if bounds have been specified.
* @return if bounds have been specified
* @see #removeBounds()
* @see #setBounds(int, int, int, int)
*/
public boolean hasBounds()
{
return boundsAvail;
}
protected void initModeFromIOObjects() throws MissingParameterException
{
if (getMode() != null)
{
return;
}
if (getInputStream() != null || getDataInput() != null)
{
mode = CodecMode.LOAD;
}
else
if (getOutputStream() != null || getDataOutput() != null)
{
mode = CodecMode.SAVE;
}
else
{
throw new MissingParameterException("No streams or files available.");
}
}
/**
* Returns if this codec is able to load images in the file format supported by this codec.
* If true
is returned this does not necessarily mean that all files in this
* format can be read, but at least some.
* @return if loading is supported
*/
public abstract boolean isLoadingSupported();
/**
* Returns if this codec is able to save images in the file format supported by this codec.
* If true
is returned this does not necessarily mean that all types files in this
* format can be written, but at least some.
* @return if saving is supported
*/
public abstract boolean isSavingSupported();
/**
* Returns if an image row given by its number (zero-based) must be loaded
* in the context of the current bounds.
* true
, anything
* else (e.g. 12 or 45) would result in false
.
*
* @param row the number of the row to be checked
* @return if row must be loaded, regarding the current bounds
*/
public boolean isRowRequired(int row)
{
if (hasBounds())
{
return (row >= boundsY1 && row <= boundsY2);
}
else
{
return (row >= 0 && row < getImage().getHeight());
}
}
/**
* Returns if the tile formed by the argument coordinates
* form a rectangle that overlaps with the bounds.
* If no bounds were defined, returns true
.
* @param x1
* @param y1
* @param x2
* @param y2
* @return if the argument tile is required
*/
public boolean isTileRequired(int x1, int y1, int x2, int y2)
{
if (hasBounds())
{
return !
(getBoundsY2() < y1 ||
getBoundsY1() > y2 ||
getBoundsX2() < x1 ||
getBoundsX1() > x2);
}
else
{
return true;
}
}
/**
* Removes all entries from the internal list of comments.
*/
public void removeAllComments()
{
comments.removeAllElements();
}
/**
* If bounds were set using {@link #setBounds(int, int, int, int)}, these
* bounds are no longer regarded after the call to this method.
*/
public void removeBounds()
{
boundsAvail = false;
}
/**
* Sets the bounds of a rectangular part of the image that
* is to be loaded or saved, instead of the complete image.
*/
public void setBounds(int x1, int y1, int x2, int y2)
{
if (x1 < 0 || y1 < 0 || x2 < x1 || y2 < y1)
{
throw new IllegalArgumentException("Not a valid bounds rectangle: " +
"x1=" + x1 + ", y1=" + y1 + ", x2=" + x2 + ", y2=" + y2);
}
boundsX1 = x1;
boundsY1 = y1;
boundsX2 = x2;
boundsY2 = y2;
boundsAvail = true;
boundsWidth = x2 - x1 + 1;
boundsHeight = y2 - y1 + 1;
}
/**
* If no bounds have been set ({@link #hasBounds()} returns false
),
* this method will set the bounds to 0, 0, width - 1, height - 1
.
* By calling this method somewhere in the codec, no distinction has to
* be made for the two cases bounds have been defined and
* bounds have not been defined.
* @param width width of the image to be loaded or saved
* @param height height of the image to be loaded or saved
*/
public void setBoundsIfNecessary(int width, int height)
{
if (!hasBounds())
{
setBounds(0, 0, width - 1, height - 1);
}
}
/**
* Specifies a DataInput object to be used for loading.
* @param dataInput DataInput object to be used for loading an image
*/
public void setDataInput(DataInput dataInput)
{
din = dataInput;
}
/**
* Sets a {@link java.io.DataOutput} object to be used for saving
* an image.
* @param dataOutput the object to be used for output
*/
public void setDataOutput(DataOutput dataOutput)
{
dout = dataOutput;
}
/**
* Sets the DPI values to be stored in the file to the argument values.
* @param horizontalDpi horizontal physical resolution in DPI (dots per inch)
* @param verticalDpi vertical physical resolution in DPI (dots per inch)
* @see #getDpiX
* @see #getDpiY
*/
public void setDpi(int horizontalDpi, int verticalDpi)
{
dpiX = horizontalDpi;
dpiY = verticalDpi;
}
/**
* Gives a File object and a codec mode to this codec and attempts
* to initialize the appropriate I/O objects.
* Simply calls {@link #setFile(String, CodecMode)} with the absolute
* path of the File object.
* @param file File object for the file to be used
* @param codecMode defines whether an image is to be loaded from or saved to the file
*/
public void setFile(File file, CodecMode codecMode) throws
IOException,
UnsupportedCodecModeException
{
setFile(file.getAbsolutePath(), codecMode);
}
/**
* Gives a file name and codec mode to the codec which will then
* try to create the corresponding I/O object.
* The default implementation in ImageCodec creates a DataInputStream object
* wrapped around a BufferedInputStream wrapped around a FileInputStream for
* CodecMode.LOAD.
* Similar for CodecMode.SAVE: a DataOutputStream around a BufferedOutputStream
* object around a FileOutputStream object.
* Codecs that need different I/O objects must override this method
* (some codecs may need random access and thus require a RandomAccessFile object).
* @param fileName name of the file to be used for loading or saving
* @param codecMode defines whether file is to be used for loading or saving
*/
public void setFile(String fileName, CodecMode codecMode) throws
IOException,
UnsupportedCodecModeException
{
if (codecMode == CodecMode.LOAD)
{
if (isLoadingSupported())
{
setInputStream(new BufferedInputStream(new FileInputStream(fileName)));
}
else
{
throw new UnsupportedCodecModeException("Loading is not supported for this codec (" + getFormatName() + ").");
}
}
else
{
if (isSavingSupported())
{
setOutputStream(new BufferedOutputStream(new FileOutputStream(fileName)));
}
else
{
throw new UnsupportedCodecModeException("Saving is not supported for this codec (" + getFormatName() + ").");
}
}
}
/**
* Give an image to this codec to be used for loading an image into it
* or saving the image.
* @param img image object to save or to load data into
*/
public void setImage(PixelImage img)
{
image = img;
}
/**
* Sets the index of the image to be loaded to the argument value
* (which must be zero or larger).
* @param index int index value (zero-based) of the image to be loaded
* @throws IllegalArgumentException if the argument is negative
*/
public void setImageIndex(int index)
{
if (index < 0)
{
throw new IllegalArgumentException("The index must be 0 or larger.");
}
imageIndex = index;
}
/**
* An {@link java.io.InputStream} can be given to this codec using this method.
* @param inputStream InputStream object to read from
*/
public void setInputStream(InputStream inputStream)
{
in = inputStream;
}
/**
* A method to give an {@link java.io.OutputStream} to this codec to be used
* for saving an image.
* @param outputStream the output stream to be used by this codec
*/
public void setOutputStream(OutputStream outputStream)
{
out = outputStream;
}
/**
* A method to give a {@link java.io.RandomAccessFile} to this codec to be used
* for loading or saving an image.
* It is not possible to determine from a RandomAccessFile object whether it
* was opened in read-only or read-and-write mode.
* To let the codec know whether the object is to be used for loading or saving
* the second argument is of type CodecMode.
* @param randomAccessFile the file to be used for loading or saving
* @param codecMode tells the codec whether the file is to be used for loading or saving
*/
public void setRandomAccessFile(RandomAccessFile randomAccessFile, CodecMode codecMode)
{
if (randomAccessFile == null)
{
throw new IllegalArgumentException("Argument RandomAccessFile must be non-null.");
}
if (codecMode == null)
{
throw new IllegalArgumentException("Argument codec mode must be non-null.");
}
raf = randomAccessFile;
mode = codecMode;
}
/**
* Attempts to suggest a filename extension.
* The type of the argument image will be taken into consideration,
* although this will be necessary for some file formats only (as an
* example, PNM has different extensions for different image types, see
* {@link PNMCodec}).
* This default implementation always returns null
.
* @param image the image that is to be written to a file
* @return the file extension, including a leading dot, or null
if no file extension can be recommended
*/
public String suggestFileExtension(PixelImage image)
{
return null;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/jpeg/ 0000775 0000000 0000000 00000000000 10546532262 022220 5 ustar java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/jpeg/JPEGCodec.java 0000664 0000000 0000000 00000014673 10523756546 024571 0 ustar /*
* JPEGCodec
*
* Copyright (c) 2004, 2005, 2006 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.codecs.jpeg;
import java.io.DataInput;
import java.io.File;
import java.io.IOException;
import net.sourceforge.jiu.codecs.CodecMode;
import net.sourceforge.jiu.codecs.ImageCodec;
import net.sourceforge.jiu.codecs.InvalidFileStructureException;
import net.sourceforge.jiu.codecs.UnsupportedTypeException;
import net.sourceforge.jiu.codecs.WrongFileFormatException;
import net.sourceforge.jiu.data.PixelImage;
import net.sourceforge.jiu.ops.MissingParameterException;
import net.sourceforge.jiu.ops.OperationFailedException;
import net.sourceforge.jiu.util.ArrayConverter;
/**
* A codec for the JPEG file format.
* Supported JPEG types
* The codec is still under development.
* Nothing can be read with it right now.
* Writing JPEG files is not even in development stage.
* Credits
* "JPEG Still Image Data Compression Standard" by William B. Pennebaker and
* Joan L. Mitchell. Published 1993 by Van Nostrand Reinhold.
* ISBN 0-442-01272-1.
* This book is referenced as P&M throughout the source code.
* It's an invaluable resource for anything related to JPEG.
* @author Marco Schmidt
* @since 0.13.0
*/
public class JPEGCodec extends ImageCodec
{
private DataInput in;
private void decodeScan(JPEGData jpegData)
{
JPEGFrame frame = jpegData.getFrame();
int width = frame.getWidth();
int height = frame.getHeight();
/*Gray8Image image = new MemoryGray8Image(width, height);
int x = 0;
int y = 0;*/
int numMCUs = ((width + 7) / 8) * ((height + 7) / 8);
while (numMCUs > 0)
{
numMCUs--;
}
}
public String[] getFileExtensions()
{
return new String[] {".jpg", ".jpeg"};
}
public String getFormatName()
{
return "JPEG File Interchange Format";
}
public String[] getMimeTypes()
{
// image/pjpeg for progressive JPEGs is not included
// because it's not supported by this codec (yet)
return new String[] {"image/jpeg"};
}
public boolean isLoadingSupported()
{
return true;
}
public boolean isSavingSupported()
{
return false;
}
private void load() throws
OperationFailedException,
WrongFileFormatException
{
in = getInputAsDataInput();
if (in == null)
{
throw new MissingParameterException(
"Input object missing (could not retrieve via getAsDataInput).");
}
try
{
// read and check the first two bytes
byte[] data = new byte[4];
in.readFully(data, 0, 2);
int signature = ArrayConverter.getShortBEAsInt(data, 0);
if (signature != JPEGConstants.JFIF_SIGNATURE)
{
throw new WrongFileFormatException(
"Not a JFIF file (first two bytes are not 0xff 0xd8).");
}
// continuously read markers, updating a JPEGData object
JPEGData jpegData = new JPEGData();
while (true)
{
// read and decode marker type and length
in.readFully(data);
int marker = ArrayConverter.getShortBEAsInt(data, 0);
int length = ArrayConverter.getShortBEAsInt(data, 2);
// read the actual marker information
readMarker(jpegData, marker, length);
}
}
catch (IOException ioe)
{
throw new OperationFailedException("Error reading from input.");
}
finally
{
close();
}
}
public static void main(String[] args) throws Exception
{
if (args.length < 1)
{
System.err.println("Need JPEG file names as arguments.");
System.exit(1);
}
for (int i = 0; i < args.length; i++)
{
String fileName = args[i];
JPEGCodec codec = new JPEGCodec();
codec.setFile(new File(fileName), CodecMode.LOAD);
codec.process();
//PixelImage image = codec.getImage();
}
}
public void process() throws
MissingParameterException,
OperationFailedException,
WrongFileFormatException
{
initModeFromIOObjects();
if (getMode() == CodecMode.LOAD)
{
load();
}
else
if (getMode() == CodecMode.SAVE)
{
throw new OperationFailedException("Saving is not supported.");
}
else
{
throw new OperationFailedException("Unsupported codec mode.");
}
}
private void readMarker(JPEGData jpegData, int marker, int length) throws
InvalidFileStructureException,
IOException,
UnsupportedTypeException
{
// make sure marker is a valid marker
if ((marker >> 8) != 0xff)
{
// TODO: instead of giving up, search for next occurrence of 0xff (error recovery)
throw new InvalidFileStructureException("Marker " +
marker + " does not have 0xff in its top eight bits.");
}
// zero out everything but the least significant byte
marker &= 0xff;
// decrease two bytes for the marker length field
length -= 2;
// react on marker, possible reactions:
// - call corresponding method if available
// - throw exception if unsupported
// - skip otherwise (= marker is unknown)
switch(marker)
{
case(JPEGConstants.MARKER_DHT):
{
JPEGMarkerReader.readHuffmanTables(in, jpegData, length);
break;
}
case(JPEGConstants.MARKER_DQT):
{
JPEGMarkerReader.readQuantizationTables(in, jpegData, length);
break;
}
// Start of frame: Huffman Baseline DCT
case(JPEGConstants.MARKER_SOF0):
{
JPEGMarkerReader.readStartOfFrame(in, jpegData, marker, length);
break;
}
// unsupported frame types
case(JPEGConstants.MARKER_SOF1):
case(JPEGConstants.MARKER_SOF2):
case(JPEGConstants.MARKER_SOF3):
case(JPEGConstants.MARKER_SOF5):
case(JPEGConstants.MARKER_SOF6):
case(JPEGConstants.MARKER_SOF7):
case(JPEGConstants.MARKER_SOF9):
case(JPEGConstants.MARKER_SOFA):
case(JPEGConstants.MARKER_SOFB):
case(JPEGConstants.MARKER_SOFD):
case(JPEGConstants.MARKER_SOFE):
case(JPEGConstants.MARKER_SOFF):
{
throw new UnsupportedTypeException(
"Unsupported JPEG SOF type: " + Integer.toHexString(marker));
}
case(JPEGConstants.MARKER_SOS):
{
JPEGMarkerReader.readStartOfScan(in, jpegData, length);
decodeScan(jpegData);
break;
}
default:
{
System.out.println("Unknown marker: " + Integer.toHexString(marker));
// skip marker data
while (length > 0)
{
int skipped = in.skipBytes(length);
if (skipped > 0)
{
length -= skipped;
}
}
break;
}
}
}
public String suggestFileExtension(PixelImage image)
{
return ".jpg";
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/jpeg/JPEGScan.java 0000664 0000000 0000000 00000001172 10332236672 024415 0 ustar package net.sourceforge.jiu.codecs.jpeg;
/**
* Data class for information from a JPEG scan header (stored in an SOS marker).
* @author Marco Schmidt
* @since 0.13.0
*/
public class JPEGScan
{
private int numComponents;
private JPEGScanComponentSpecification[] compSpecs;
public int getNumComponents()
{
return numComponents;
}
public void setNumComponents(int i)
{
numComponents = i;
}
public JPEGScanComponentSpecification[] getCompSpecs()
{
return compSpecs;
}
public void setCompSpecs(JPEGScanComponentSpecification[] specifications)
{
compSpecs = specifications;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/jpeg/JPEGFrame.java 0000664 0000000 0000000 00000003402 10421163624 024554 0 ustar /*
* JPEGFrame
*
* Copyright (c) 2005, 2006 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.codecs.jpeg;
/**
* Data class to store information on a JPEG frame.
* A frame here is JPEG terminology for a complete image
* and has nothing to do with GUI components like JFrame objects
* in Swing.
* @author Marco Schmidt
* @since 0.13.0
*/
public class JPEGFrame
{
private JPEGFrameComponent[] components;
private int numComponents;
private int height;
private int samplePrecision;
private int width;
public JPEGFrameComponent[] getComponents()
{
return components;
}
public int getHeight()
{
return height;
}
public int getNumComponents()
{
return numComponents;
}
public int getSamplePrecision()
{
return samplePrecision;
}
public int getWidth()
{
return width;
}
public void setComponents(JPEGFrameComponent[] components)
{
this.components = components;
}
public void setHeight(int i)
{
height = i;
}
public void setNumComponents(int i)
{
numComponents = i;
}
public void setSamplePrecision(int i)
{
samplePrecision = i;
}
public void setWidth(int i)
{
width = i;
}
public String toString()
{
StringBuffer sb = new StringBuffer();
sb.append("#components=");
sb.append(numComponents);
sb.append("/precision=");
sb.append(samplePrecision);
sb.append("/width=");
sb.append(width);
sb.append("/height=");
sb.append(height);
if (components != null)
{
for (int i = 0; i < components.length; i++)
{
JPEGFrameComponent comp = components[i];
if (comp != null)
{
sb.append("/");
sb.append(comp.toString());
}
}
}
return sb.toString();
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/jpeg/JPEGConstants.java 0000664 0000000 0000000 00000005245 10522414465 025511 0 ustar /*
* JPEGConstants
*
* Copyright (c) 2004, 2005, 2006 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.codecs.jpeg;
/**
* Constants necessary to encode and decode JPEG streams.
* @author Marco Schmidt
* @since 0.13.0
*/
public final class JPEGConstants
{
/**
* Length of sample block edge, in samples (8).
*/
public static final int BLOCK_EDGE_LENGTH = 8;
/**
* 16 bit value that denotes the beginning of a JPEG stream (0xffd8).
*/
public static final int JFIF_SIGNATURE = 0xffd8;
/**
* DHT (define Huffman table) marker ID value.
*/
public static final int MARKER_DHT = 0xc4;
/**
* DQT (define quantization table) marker ID value.
*/
public static final int MARKER_DQT = 0xdb;
/**
* SOF0 (start of frame, type 0) marker ID value.
*/
public static final int MARKER_SOF0 = 0xc0;
/**
* SOF1 (start of frame, type 1) marker ID value.
*/
public static final int MARKER_SOF1 = 0xc1;
/**
* SOF2 (start of frame, type 2) marker ID value.
*/
public static final int MARKER_SOF2 = 0xc2;
/**
* SOF3 (start of frame, type 3) marker ID value.
*/
public static final int MARKER_SOF3 = 0xc3;
/**
* SOF5 (start of frame, type 5) marker ID value.
*/
public static final int MARKER_SOF5 = 0xc5;
/**
* SOF6 (start of frame, type 6) marker ID value.
*/
public static final int MARKER_SOF6 = 0xc6;
/**
* SOF7 (start of frame, type 7) marker ID value.
*/
public static final int MARKER_SOF7 = 0xc7;
/**
* SOF9 (start of frame, type 9) marker ID value.
*/
public static final int MARKER_SOF9 = 0xc9;
/**
* SOFa (start of frame, type a) marker ID value.
*/
public static final int MARKER_SOFA = 0xca;
/**
* SOFb (start of frame, type b) marker ID value.
*/
public static final int MARKER_SOFB = 0xcb;
/**
* SOFd (start of frame, type d) marker ID value.
*/
public static final int MARKER_SOFD = 0xcd;
/**
* SOFe (start of frame, type e) marker ID value.
*/
public static final int MARKER_SOFE = 0xce;
/**
* SOFf (start of frame, type f) marker ID value.
*/
public static final int MARKER_SOFF = 0xcf;
/**
* SOS (start of scan) marker ID value.
*/
public static final int MARKER_SOS = 0xda;
/**
* Maximum length of a Huffman code in bit (16).
*/
public static final int MAX_HUFFMAN_CODE_LENGTH = 16;
/**
* Number of samples in a block of samples (64).
*/
public static final int SAMPLES_PER_BLOCK = BLOCK_EDGE_LENGTH * BLOCK_EDGE_LENGTH;
/**
* Empty private constructor to prevent instantiation of this class.
*/
private JPEGConstants()
{
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/jpeg/JPEGHuffmanTable.java 0000664 0000000 0000000 00000005020 10421163377 026061 0 ustar /*
* JPEGHuffmanTable
*
* Copyright (c) 2005, 2006 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.codecs.jpeg;
/**
* Data class that stores a single Huffman table, including class
* (AC or DC), ID and codes for the 16 possible bit lengths from 1 to 16.
* @author Marco Schmidt
* @since 0.13.0
*/
public class JPEGHuffmanTable
{
public static final int TABLE_CLASS_AC = 1;
public static final int TABLE_CLASS_DC = 0;
private int id;
private int classAcDc;
private int[][] codes;
private int[] huffCode;
private int[] huffSize;
private int lastK;
public void createDecoderTables()
{
generateSizeTable();
generateCodeTable();
// TODO: F.15
}
/**
* Initialize huffCode from huffSize.
* P&M figure C.2, p. 406f.
*/
private void generateCodeTable()
{
huffCode = new int[257];
int k = 0;
int code = 0;
int si = huffSize[0];
while (true)
{
while (true)
{
huffCode[k] = code;
code++;
k++;
if (huffSize[k] != si)
{
break;
}
}
if (huffSize[k] == 0)
{
break;
}
while (true)
{
code <<= 1;
si++;
if (huffSize[k] == si)
{
break;
}
}
}
}
/**
* Initialize huffSize and lastK from codes.
* P&M figure C.1, p. 405f.
*/
private void generateSizeTable()
{
huffSize = new int[257];
int i = 1;
int j = 1;
int k = 0;
while (true)
{
while (true)
{
if (j > codes[i].length)
{
break;
}
huffSize[k] = i;
k++;
j++;
}
i++;
j = 1;
if (i > JPEGConstants.MAX_HUFFMAN_CODE_LENGTH)
{
break;
}
}
huffSize[k] = 0;
lastK = k;
}
public int getClassAcDc()
{
return classAcDc;
}
public int[][] getCodes()
{
return codes;
}
public int getId()
{
return id;
}
public void setClassAcDc(int i)
{
classAcDc = i;
}
public void setCodes(int[][] is)
{
codes = is;
}
public void setId(int i)
{
id = i;
}
public String toString()
{
StringBuffer sb = new StringBuffer();
sb.append("id=");
sb.append(id);
sb.append("/class=");
sb.append(classAcDc == TABLE_CLASS_AC ? "AC" : "DC");
if (codes != null)
{
sb.append("/codes(length,number)=");
for (int i = 0; i < codes.length; i++)
{
if (codes[i].length > 0)
{
sb.append(" ");
sb.append((i+1));
sb.append(":");
sb.append(codes[i].length);
}
}
}
return sb.toString();
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/jpeg/JPEGData.java 0000664 0000000 0000000 00000002571 10421163521 024375 0 ustar /*
* JPEGData
*
* Copyright (c) 2005, 2006 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.codecs.jpeg;
import java.util.Vector;
/**
* Data for decoding or encoding images from or to
* JPEG File Interchange Format (JFIF) files.
* @author Marco Schmidt
* @since 0.13.0
*/
public class JPEGData
{
private JPEGFrame frame;
private Vector huffmanTables = new Vector();
private Vector quantTables = new Vector();
private Vector scans = new Vector();
public void addQuantizationTable(JPEGQuantizationTable table)
{
quantTables.add(table);
}
public void addHuffmanTable(JPEGHuffmanTable table)
{
huffmanTables.add(table);
}
public void addScan(JPEGScan scan)
{
scans.add(scan);
}
public JPEGFrame getFrame()
{
return frame;
}
/**
* Return a quantization table with a given id or
* null on failure to find it.
* @param id integer id value of table
* @return actual table or null on failure
*/
public JPEGQuantizationTable getQuantizationTable(int id)
{
JPEGQuantizationTable table = null;
int index = 0;
while (index < quantTables.size())
{
table = (JPEGQuantizationTable)quantTables.elementAt(index++);
if (table.getId() == id)
{
return table;
}
}
return null;
}
public void setFrame(JPEGFrame newFrame)
{
frame = newFrame;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/jpeg/package.html 0000664 0000000 0000000 00000000436 10104434033 024467 0 ustar
Package Specification
Related Documentation
././@LongLink 0000000 0000000 0000000 00000000151 00000000000 011562 L ustar root root java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/jpeg/JPEGScanComponentSpecification.java java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/jpeg/JPEGScanComponentSpecification.0000664 0000000 0000000 00000001277 10332236675 030150 0 ustar package net.sourceforge.jiu.codecs.jpeg;
/**
* Data class to store information on one component in one scan.
* @author Marco Schmidt
* @since 0.13.0
*/
public class JPEGScanComponentSpecification
{
private int component;
private int acEntropyTable;
private int dcEntropyTable;
public int getAcEntropyTable()
{
return acEntropyTable;
}
public int getComponent()
{
return component;
}
public int getDcEntropyTable()
{
return dcEntropyTable;
}
public void setAcEntropyTable(int i)
{
acEntropyTable = i;
}
public void setComponent(int i)
{
component = i;
}
public void setDcEntropyTable(int i)
{
dcEntropyTable = i;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/jpeg/JPEGMarkerReader.java 0000664 0000000 0000000 00000021777 10542200240 026073 0 ustar /*
* JPEGMarkerReader
*
* Copyright (c) 2006 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.codecs.jpeg;
import java.io.DataInput;
import java.io.IOException;
import net.sourceforge.jiu.codecs.InvalidFileStructureException;
import net.sourceforge.jiu.codecs.UnsupportedTypeException;
import net.sourceforge.jiu.util.ArrayConverter;
/**
* Static helper methods to read various JPEG bitstream headers from a
* {@link java.io.DataInput} source into objects of the appropriate
* data classes.
* Objects are then added to a {@link JPEGData} object.
* @author Marco Schmidt
* @since 0.14.0
*/
public class JPEGMarkerReader
{
/**
* Private constructor to prevent instantiation.
*/
private JPEGMarkerReader()
{
}
public static void readHuffmanTables(DataInput in, JPEGData jpegData, int length) throws
InvalidFileStructureException,
IOException
{
while (length > 0)
{
if (length < 17)
{
throw new InvalidFileStructureException("DHT marker - " +
"less than 17 bytes left.");
}
JPEGHuffmanTable table = new JPEGHuffmanTable();
int classId = in.readUnsignedByte();
// class (AC or DC)
int tableClass = (classId >> 4) & 0x0f;
if (tableClass != JPEGHuffmanTable.TABLE_CLASS_AC &&
tableClass != JPEGHuffmanTable.TABLE_CLASS_DC)
{
throw new InvalidFileStructureException(
"Table class in DHT marker is neither AC nor DC.");
}
table.setClassAcDc(tableClass);
// ID
int tableId = classId & 0x0f;
table.setId(tableId);
// codes
byte[] numCodes = new byte[16];
in.readFully(numCodes);
length -= 17;
int[][] codes = new int[16][];
for (int codeLength = 1; codeLength <= 16; codeLength++)
{
int number = numCodes[codeLength - 1] & 0xff;
if (length < number)
{
throw new InvalidFileStructureException(
"Not enough data left in DHT marker for codes of " +
"length " + codeLength + ".");
}
codes[codeLength - 1] = new int[number];
for (int codeIndex = 0; codeIndex < number; codeIndex++)
{
codes[codeLength - 1][codeIndex] = in.readUnsignedByte();
}
length -= number;
}
table.setCodes(codes);
System.out.println(table);
jpegData.addHuffmanTable(table);
}
}
/**
* Read quantization tables from a DQT marker.
* P&M 7.8.3, p. 118f.
* @param jpegData data object which will store the table(s)
* @param length length of marker
* @throws InvalidFileStructureException if the DQT contains invalid data
* @throws IOException on reading errors
*/
public static void readQuantizationTables(DataInput in, JPEGData jpegData, int length) throws
InvalidFileStructureException,
IOException
{
while (length > 0)
{
int precId = in.readUnsignedByte();
length--;
JPEGQuantizationTable table = new JPEGQuantizationTable();
int elementPrecision = (precId >> 4) & 0x0f;
switch(elementPrecision)
{
case(0):
{
table.setElementPrecision(8);
break;
}
case(1):
{
table.setElementPrecision(16);
break;
}
default:
{
throw new InvalidFileStructureException(
"Not a valid value for quantization table element precision: " +
elementPrecision + " (expected 0 or 1).");
}
}
int id = precId & 0x0f;
if (id > 3)
{
throw new InvalidFileStructureException(
"Not a valid quantization table id: " +
id + " (expected 0 to 3).");
}
table.setId(id);
// check if there's enough data left for the table elements
int tableDataLength = JPEGConstants.SAMPLES_PER_BLOCK * (elementPrecision + 1);
if (length < tableDataLength)
{
throw new InvalidFileStructureException(
"Not enough data left in marker for quantization table data: " +
length + "byte(s) (expected at least " + tableDataLength + ").");
}
int[] data = new int[JPEGConstants.SAMPLES_PER_BLOCK];
for (int i = 0; i < data.length; i++)
{
switch(elementPrecision)
{
case(0):
{
data[i] = in.readUnsignedByte();
break;
}
case(1):
{
data[i] = in.readShort() & 0xffff;
break;
}
}
}
length -= tableDataLength;
table.setData(data);
jpegData.addQuantizationTable(table);
}
}
public static void readStartOfFrame(DataInput in, JPEGData jpegData,
int marker, int length) throws
InvalidFileStructureException,
IOException,
UnsupportedTypeException
{
if (length < 9)
{
throw new InvalidFileStructureException(
"JPEG SOF header length must be at least nine bytes; got " +
length + ".");
}
byte[] data = new byte[6];
in.readFully(data);
JPEGFrame frame = new JPEGFrame();
// sample precision
int samplePrecision = data[0] & 0xff;
if (samplePrecision != 8)
{
throw new UnsupportedTypeException("Unsupported JPEG sample precision: " +
samplePrecision);
}
frame.setSamplePrecision(samplePrecision);
// height
int height = ArrayConverter.getShortBEAsInt(data, 1);
if (height < 1)
{
throw new InvalidFileStructureException(
"JPEG SOF height value must be 1 or higher; got " +
height + ".");
}
frame.setHeight(height);
// width
int width = ArrayConverter.getShortBEAsInt(data, 3);
if (width < 1)
{
throw new InvalidFileStructureException(
"JPEG SOF width value must be 1 or higher; got " +
width + ".");
}
frame.setWidth(width);
// number of components (= channels)
int numComponents = data[5] & 0xff;
if (numComponents != 1)
{
throw new UnsupportedTypeException("Unsupported number of JPEG components: " +
numComponents);
}
frame.setNumComponents(numComponents);
if (length - 6 != numComponents * 3)
{
throw new InvalidFileStructureException(
"SOF marker has not expected size for " +
numComponents + " component(s); got " + length +
" instead of " + (6 + numComponents * 3));
}
JPEGFrameComponent[] frameComponents = new JPEGFrameComponent[numComponents];
for (int componentIndex = 0; componentIndex < numComponents; componentIndex++)
{
in.readFully(data, 0, 3);
JPEGFrameComponent frameComponent = new JPEGFrameComponent();
int componentIdentifier = data[0] & 0xff;
frameComponent.setComponentId(componentIdentifier);
int horizontalSamplingFactor = (data[1] & 0xf0) >> 4;
frameComponent.setHorizontalSamplingFactor(horizontalSamplingFactor);
int verticalSamplingFactor = data[1] & 0x0f;
frameComponent.setVerticalSamplingFactor(verticalSamplingFactor);
int quantizationTable = data[2] & 0xff;
frameComponent.setQuantizationTableId(quantizationTable);
frameComponents[componentIndex] = frameComponent;
}
frame.setComponents(frameComponents);
jpegData.setFrame(frame);
System.out.println(frame);
}
/**
* Read an SOS (start of scan) marker.
* P&M 7.6, p. 113.
* @param in source to read marker information from
* @param jpegData {@link JPEGData} object to update with information from the marker
* @param length size of marker in bytes
* @throws InvalidFileStructureException if encountered data does not follow the JPEG standard
* @throws IOException on I/O errors
* @throws UnsupportedTypeException if encountered data is valid but unsupported by this package
*/
public static void readStartOfScan(DataInput in, JPEGData jpegData, int length) throws
InvalidFileStructureException,
IOException,
UnsupportedTypeException
{
if (length < 6)
{
throw new InvalidFileStructureException("SOS marker must be at least six bytes large; got " + length);
}
int numScanComponents = in.readUnsignedByte();
length--;
if (numScanComponents < 1)
{
throw new InvalidFileStructureException("Number of scan components must be one or larger.");
}
JPEGScan scan = new JPEGScan();
scan.setNumComponents(numScanComponents);
JPEGScanComponentSpecification[] specs = new JPEGScanComponentSpecification[numScanComponents];
byte[] data = new byte[2];
for (int i = 0; i < numScanComponents; i++)
{
in.readFully(data);
length -= 2;
int componentSelector = data[0] & 0xff;
int dcTableSelector = (data[1] & 0xf0) >> 4;
int acTableSelector = data[1] & 0x0f;
JPEGScanComponentSpecification spec = new JPEGScanComponentSpecification();
spec.setAcEntropyTable(acTableSelector);
spec.setDcEntropyTable(dcTableSelector);
spec.setComponent(componentSelector);
specs[i] = spec;
}
scan.setCompSpecs(specs);
if (length != 3)
{
throw new InvalidFileStructureException(
"Expected exactly three bytes left after scan component specs; got " +
length);
}
data = new byte[3];
in.readFully(data);
// TODO: add these as fields to JPEGScan, check their values and call the scan setters to copy the data
/*
int spectralStart = data[0] & 0xff;
int spectralEnd = data[1] & 0xff;
int highSuccessiveBit = (data[2] & 0xf0) >> 4;
int lowSuccessiveBit = data[2] & 0x0f;
*/
jpegData.addScan(scan);
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/jpeg/JPEGQuantizationTable.java 0000664 0000000 0000000 00000001303 10332236666 027166 0 ustar package net.sourceforge.jiu.codecs.jpeg;
/**
* Data for a JPEG bitstream quantization table.
* Includes quantization data, table id (0 to 3)
* and element precision in bits (8 or 16).
* @author Marco Schmidt
* @since 0.13.0
*/
public class JPEGQuantizationTable
{
private int[] data;
private int elementPrecision;
private int id;
public int[] getData()
{
return data;
}
public int getElementPrecision()
{
return elementPrecision;
}
public int getId()
{
return id;
}
public void setData(int[] is)
{
data = is;
}
public void setElementPrecision(int i)
{
elementPrecision = i;
}
public void setId(int i)
{
id = i;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/jpeg/JPEGFrameComponent.java 0000664 0000000 0000000 00000002676 10410704642 026452 0 ustar /*
* JPEGFrameComponent
*
* Copyright (c) 2005, 2006 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.codecs.jpeg;
/**
* Data class for information on a JPEG frame component.
* @author Marco Schmidt
* @since 0.13.0
*/
public class JPEGFrameComponent
{
private int componentId;
private int horizontalSamplingFactor;
private int verticalSamplingFactor;
private int quantizationTableId;
public int getComponentId()
{
return componentId;
}
public int getHorizontalSamplingFactor()
{
return horizontalSamplingFactor;
}
public int getQuantizationTableId()
{
return quantizationTableId;
}
public int getVerticalSamplingFactor()
{
return verticalSamplingFactor;
}
public void setComponentId(int i)
{
componentId = i;
}
public void setHorizontalSamplingFactor(int i)
{
horizontalSamplingFactor = i;
}
public void setQuantizationTableId(int i)
{
quantizationTableId = i;
}
public void setVerticalSamplingFactor(int i)
{
verticalSamplingFactor = i;
}
public String toString()
{
StringBuffer sb = new StringBuffer();
sb.append("component id=");
sb.append(componentId);
sb.append(", horiz. sampling=");
sb.append(horizontalSamplingFactor);
sb.append(", vert. sampling=");
sb.append(verticalSamplingFactor);
sb.append(", quantization table=");
sb.append(quantizationTableId);
return sb.toString();
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/package.html 0000664 0000000 0000000 00000006567 10324344522 023564 0 ustar
Package Specification
Related Documentation
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/WrongFileFormatException.java 0000664 0000000 0000000 00000002206 07741250131 027055 0 ustar /*
* WrongFileFormatException
*
* Copyright (c) 2000, 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.codecs;
import net.sourceforge.jiu.ops.OperationFailedException;
/**
* This exception is thrown during image loading.
* If a codec is sure that the file or input stream that was given to
* it is not in the format supported by that codec, an instance of
* this exception class is thrown.
* This is usually the case if the magic byte sequence of that format
* is not found at the beginning of the stream.
* .bmp
and .rle
* (the latter is only used for compressed files).
* Bounds
* Supported BMP types when loading
*
*
* There is no support for 16 bpp images or BI_BITFIELDS compression (for lack of test files).
* Supported JIU image data classes when saving to BMP
*
*
* There is no support for compressed BMP files when saving.
* I/O classes
* BMPCodec works with all input and output classes supported by ImageCodec
* ({@link java.io.InputStream}, {@link java.io.OutputStream},
* {@link java.io.DataInput}, {@link java.io.DataOutput},
* {@link java.io.RandomAccessFile}).
* Problems
* 0
, the EOL is ignored.
* Usage examples
* Write an image to a BMP file.
*
* BMPCodec codec = new BMPCodec();
* codec.setImage(image);
* codec.setFile("out.bmp", CodecMode.SAVE);
* codec.process();
* codec.close();
*
* Read an image from a BMP file.
*
* BMPCodec codec = new BMPCodec();
* codec.setFile("image.bmp", CodecMode.LOAD);
* codec.process();
* codec.close();
* PixelImage image = codec.getImage();
*
* @author Marco Schmidt
* @since 0.7.0
*/
public class BMPCodec extends ImageCodec
{
private int colorDepth;
private int compression;
private int dataOffset;
private int imageHeight;
private int imageWidth;
private DataInput in;
private DataOutput out;
private Palette palette;
public String[] getFileExtensions()
{
return new String[] {".bmp", ".rle"};
}
public String getFormatName()
{
return "Windows BMP";
}
public String[] getMimeTypes()
{
return new String[] {"image/bmp", "image/x-ms-bmp"};
}
public boolean isLoadingSupported()
{
return true;
}
public boolean isSavingSupported()
{
return true;
}
private void load() throws
MissingParameterException,
OperationFailedException,
UnsupportedTypeException,
WrongFileFormatException
{
in = getInputAsDataInput();
if (in == null)
{
throw new MissingParameterException("Input stream / random access file parameter missing.");
}
// now write the output stream
try
{
loadHeader();
loadStream();
}
catch (IOException ioe)
{
// wrap any I/O failures in an OperationFailedException
throw new OperationFailedException("I/O failure: " + ioe.toString());
}
}
private void loadCompressedPaletted4Stream() throws IOException
{
Paletted8Image image = (Paletted8Image)getImage();
int imageBytesPerRow = imageWidth;
int bytesPerRow = imageBytesPerRow;
int mod = bytesPerRow % 4;
if (mod != 0)
{
bytesPerRow += 4 - mod;
}
final int COLUMNS = getBoundsWidth();
final int ROWS = imageHeight - getBoundsY1();
final int X1 = getBoundsX1();
int processedRows = 0;
byte[] row = new byte[bytesPerRow];
int x = 0;
int y = imageHeight - 1;
boolean endOfBitmap = false;
boolean delta = false;
int newX = 0;
int newY = 0;
while (processedRows < ROWS)
{
int v1 = in.readUnsignedByte();
int v2 = in.readUnsignedByte();
if (v1 == 0)
{
switch(v2)
{
case(0):
{
// end of line
if (x != 0)
{
x = bytesPerRow;
}
break;
}
case(1):
{
// end of bitmap
x = bytesPerRow;
endOfBitmap = true;
break;
}
case(2):
{
// delta
delta = true;
newX = x + in.readUnsignedByte();
newY = y - in.readUnsignedByte();
x = bytesPerRow;
break;
}
default:
{
// copy the next v2 (3..255) samples from file to output
// two samples are packed into one byte
// if the number of bytes used to pack is not a multiple of 2,
// an additional padding byte is in the stream and must be skipped
boolean paddingByte = (((v2 + 1) / 2) % 2) != 0;
while (v2 > 1)
{
int packed = in.readUnsignedByte();
int sample1 = (packed >> 4) & 0x0f;
int sample2 = packed & 0x0f;
row[x++] = (byte)sample1;
row[x++] = (byte)sample2;
v2 -= 2;
}
if (v2 == 1)
{
int packed = in.readUnsignedByte();
int sample = (packed >> 4) & 0x0f;
row[x++] = (byte)sample;
}
if (paddingByte)
{
v2 = in.readUnsignedByte();
}
break;
}
}
}
else
{
// rle: replicate the two samples in v2 as many times as v1 says
byte sample1 = (byte)((v2 >> 4) & 0x0f);
byte sample2 = (byte)(v2 & 0x0f);
while (v1 > 1)
{
row[x++] = sample1;
row[x++] = sample2;
v1 -= 2;
}
if (v1 == 1)
{
row[x++] = sample1;
}
}
// end of line?
if (x == bytesPerRow)
{
if (y <= getBoundsY2())
{
image.putByteSamples(0, 0, y - getBoundsY1(), COLUMNS, 1, row, X1);
}
if (delta)
{
x = newX;
y = newY;
}
else
{
x = 0;
y--;
}
if (endOfBitmap)
{
processedRows = ROWS - 1;
}
setProgress(processedRows, ROWS);
processedRows++;
delta = false;
}
}
}
private void loadCompressedPaletted8Stream() throws IOException
{
Paletted8Image image = (Paletted8Image)getImage();
int imageBytesPerRow = imageWidth;
int bytesPerRow = imageBytesPerRow;
int mod = bytesPerRow % 4;
if (mod != 0)
{
bytesPerRow += 4 - mod;
}
final int COLUMNS = getBoundsWidth();
final int ROWS = imageHeight - getBoundsY1();
final int X1 = getBoundsX1();
int processedRows = 0;
byte[] row = new byte[bytesPerRow];
int x = 0;
int y = imageHeight - 1;
boolean endOfBitmap = false;
boolean delta = false;
int newX = 0;
int newY = 0;
while (processedRows < ROWS)
{
int v1 = in.readUnsignedByte();
int v2 = in.readUnsignedByte();
if (v1 == 0)
{
switch(v2)
{
case(0):
{
// end of line
if (x != 0)
{
x = bytesPerRow;
}
break;
}
case(1):
{
// end of bitmap
x = bytesPerRow;
endOfBitmap = true;
break;
}
case(2):
{
// delta
delta = true;
newX = x + in.readUnsignedByte();
newY = y - in.readUnsignedByte();
x = bytesPerRow;
break;
}
default:
{
// copy the next v2 (3..255) bytes from file to output
boolean paddingByte = (v2 % 2) != 0;
while (v2-- > 0)
{
row[x++] = (byte)in.readUnsignedByte();
}
if (paddingByte)
{
v2 = in.readUnsignedByte();
}
break;
}
}
}
else
{
// rle: replicate v2 as many times as v1 says
byte value = (byte)v2;
while (v1-- > 0)
{
row[x++] = value;
}
}
// end of line?
if (x == bytesPerRow)
{
if (y <= getBoundsY2())
{
image.putByteSamples(0, 0, y - getBoundsY1(), COLUMNS, 1, row, X1);
}
if (delta)
{
x = newX;
y = newY;
}
else
{
x = 0;
y--;
}
if (endOfBitmap)
{
processedRows = ROWS - 1;
}
setProgress(processedRows, ROWS);
processedRows++;
delta = false;
}
}
}
private void loadHeader() throws
IOException,
MissingParameterException,
OperationFailedException,
UnsupportedTypeException,
WrongFileFormatException
{
byte[] header = new byte[54];
in.readFully(header);
if (header[0] != 'B' || header[1] != 'M')
{
throw new WrongFileFormatException("Not a BMP file (first two bytes are not 0x42 0x4d).");
}
dataOffset = ArrayConverter.getIntLE(header, 0x0a);
if (dataOffset < 54)
{
throw new InvalidFileStructureException("BMP data expected to be 54dec or larger, got " + dataOffset);
}
imageWidth = ArrayConverter.getIntLE(header, 0x12);
imageHeight = ArrayConverter.getIntLE(header, 0x16);
if (imageWidth < 1 || imageHeight < 1)
{
throw new InvalidFileStructureException("BMP image width and height must be larger than 0, got " + imageWidth + " x " + imageHeight);
}
int planes = ArrayConverter.getShortLE(header, 0x1a);
if (planes != 1)
{
throw new InvalidFileStructureException("Can only handle BMP number of planes = 1, got " + planes);
}
colorDepth = ArrayConverter.getShortLE(header, 0x1c);
if (colorDepth != 1 && colorDepth != 4 && colorDepth != 8 && colorDepth != 24)
{
// TO DO: add support for 16 bpp BMP reading
throw new InvalidFileStructureException("Unsupported BMP color depth: " + colorDepth);
}
compression = ArrayConverter.getIntLE(header, 0x1e);
if (compression != 0 && !(compression == 1 && colorDepth == 8) && !(compression == 2 && colorDepth == 4))
{
throw new InvalidFileStructureException("Unsupported BMP compression type / color depth combination: " +
compression + " / " + colorDepth);
}
float dpiXValue = ArrayConverter.getIntLE(header, 0x26) / (100.0f / 2.54f);
float dpiYValue = ArrayConverter.getIntLE(header, 0x2a) / (100.0f / 2.54f);
setDpi((int)dpiXValue, (int)dpiYValue);
}
private void loadStream() throws
IOException,
MissingParameterException,
OperationFailedException,
UnsupportedTypeException
{
// 1. check bounds, initialize them if necessary
setBoundsIfNecessary(imageWidth, imageHeight);
checkBounds(imageWidth, imageHeight);
// 2. read palette if the image isn't truecolor (even monochrome BMPs have a palette)
int bytesToSkip;
if (colorDepth <= 8)
{
int numPaletteEntries = 1 << colorDepth;
int expectedPaletteSize = 4 * numPaletteEntries;
int headerSpaceLeft = dataOffset - 54;
bytesToSkip = headerSpaceLeft - expectedPaletteSize;
if (bytesToSkip < 0)
{
throw new InvalidFileStructureException("Not enough space in header for palette with " +
numPaletteEntries + "entries.");
}
palette = new Palette(numPaletteEntries);
for (int index = 0; index < numPaletteEntries; index++)
{
int blue = in.readUnsignedByte();
int green = in.readUnsignedByte();
int red = in.readUnsignedByte();
in.readUnsignedByte();
palette.put(index, red, green, blue);
}
}
else
{
bytesToSkip = dataOffset - 54;
}
// 3. seek to beginning of image data
while (bytesToSkip > 0)
{
int skipped = in.skipBytes(bytesToSkip);
if (skipped > 0)
{
bytesToSkip -= skipped;
}
}
// 4. check if we have an image object that we are supposed to reuse
// if there is one, check if it has the correct type
// if there is none, create a new one
PixelImage image = getImage();
if (image == null)
{
switch(colorDepth)
{
case(1):
{
setImage(new MemoryBilevelImage(getBoundsWidth(), getBoundsHeight()));
break;
}
case(4):
case(8):
{
setImage(new MemoryPaletted8Image(getBoundsWidth(), getBoundsHeight(), palette));
break;
}
case(24):
{
setImage(new MemoryRGB24Image(getBoundsWidth(), getBoundsHeight()));
break;
}
// loadHeader would have thrown an exception for any other color depths
}
}
else
{
// TODO: check if image is of correct type
}
// now read actual image data
if (compression == 0)
{
loadUncompressedStream();
}
else
if (compression == 1)
{
loadCompressedPaletted8Stream();
}
else
if (compression == 2)
{
loadCompressedPaletted4Stream();
}
}
private void loadUncompressedBilevelStream() throws
IOException,
OperationFailedException
{
if ((getBoundsX1() % 8) != 0)
{
throw new OperationFailedException("When loading bilevel images, horizontal X1 bounds must be a multiple of 8; got " + getBoundsX1());
}
BilevelImage image = (BilevelImage)getImage();
int imageBytesPerRow = (imageWidth + 7) / 8;
int bytesPerRow = imageBytesPerRow;
int mod = bytesPerRow % 4;
if (mod != 0)
{
bytesPerRow += 4 - mod;
}
int bottomRowsToSkip = imageHeight - 1 - getBoundsY2();
int bytesToSkip = bottomRowsToSkip * bytesPerRow;
while (bytesToSkip > 0)
{
int skipped = in.skipBytes(bytesToSkip);
if (skipped > 0)
{
bytesToSkip -= skipped;
}
}
final int COLUMNS = getBoundsWidth();
final int ROWS = getBoundsHeight();
final int SRC_OFFSET = getBoundsX1() / 8;
final int SRC_BIT_OFFSET = getBoundsX1() % 8;
int y = image.getHeight() - 1;
int processedRows = 0;
byte[] row = new byte[bytesPerRow];
while (processedRows < ROWS)
{
in.readFully(row);
image.putPackedBytes(0, y, COLUMNS, row, SRC_OFFSET, SRC_BIT_OFFSET);
y--;
setProgress(processedRows, ROWS);
processedRows++;
}
}
private void loadUncompressedPaletted4Stream() throws
IOException
{
Paletted8Image image = (Paletted8Image)getImage();
int imageBytesPerRow = (imageWidth + 1) / 2;
int bytesPerRow = imageBytesPerRow;
int mod = bytesPerRow % 4;
if (mod != 0)
{
bytesPerRow += 4 - mod;
}
int bottomRowsToSkip = imageHeight - 1 - getBoundsY2();
int bytesToSkip = bottomRowsToSkip * bytesPerRow;
while (bytesToSkip > 0)
{
int skipped = in.skipBytes(bytesToSkip);
if (skipped > 0)
{
bytesToSkip -= skipped;
}
}
final int COLUMNS = getBoundsWidth();
final int ROWS = getBoundsHeight();
final int X1 = getBoundsX1();
int y = image.getHeight() - 1;
int processedRows = 0;
byte[] row = new byte[bytesPerRow];
byte[] samples = new byte[bytesPerRow * 2];
while (processedRows < ROWS)
{
in.readFully(row);
ArrayConverter.decodePacked4Bit(row, 0, samples, 0, row.length);
image.putByteSamples(0, 0, y, COLUMNS, 1, samples, X1);
y--;
setProgress(processedRows, ROWS);
processedRows++;
}
}
private void loadUncompressedPaletted8Stream() throws IOException
{
Paletted8Image image = (Paletted8Image)getImage();
int imageBytesPerRow = imageWidth;
int bytesPerRow = imageBytesPerRow;
int mod = bytesPerRow % 4;
if (mod != 0)
{
bytesPerRow += 4 - mod;
}
int bottomRowsToSkip = imageHeight - 1 - getBoundsY2();
int bytesToSkip = bottomRowsToSkip * bytesPerRow;
while (bytesToSkip > 0)
{
int skipped = in.skipBytes(bytesToSkip);
if (skipped > 0)
{
bytesToSkip -= skipped;
}
}
final int COLUMNS = getBoundsWidth();
final int ROWS = getBoundsHeight();
final int X1 = getBoundsX1();
int y = image.getHeight() - 1;
int processedRows = 0;
byte[] row = new byte[bytesPerRow];
while (processedRows < ROWS)
{
in.readFully(row);
image.putByteSamples(0, 0, y, COLUMNS, 1, row, X1);
y--;
setProgress(processedRows, ROWS);
processedRows++;
}
}
private void loadUncompressedRgb24Stream() throws IOException
{
RGB24Image image = (RGB24Image)getImage();
int imageBytesPerRow = imageWidth * 3;
int bytesPerRow = imageBytesPerRow;
int mod = bytesPerRow % 4;
if (mod != 0)
{
bytesPerRow += 4 - mod;
}
int bottomRowsToSkip = imageHeight - 1 - getBoundsY2();
int bytesToSkip = bottomRowsToSkip * bytesPerRow;
while (bytesToSkip > 0)
{
int skipped = in.skipBytes(bytesToSkip);
if (skipped > 0)
{
bytesToSkip -= skipped;
}
}
final int COLUMNS = getBoundsWidth();
final int ROWS = getBoundsHeight();
final int X1 = getBoundsX1();
int y = image.getHeight() - 1;
int processedRows = 0;
byte[] row = new byte[bytesPerRow];
byte[] samples = new byte[COLUMNS];
while (processedRows < ROWS)
{
in.readFully(row);
// copy red samples to array samples and store those samples
for (int x = X1 * 3 + 2, i = 0; i < COLUMNS; x += 3, i++)
{
samples[i] = row[x];
}
image.putByteSamples(RGBIndex.INDEX_RED, 0, y, COLUMNS, 1, samples, 0);
// copy green samples to array samples and store those samples
for (int x = X1 * 3 + 1, i = 0; i < COLUMNS; x += 3, i++)
{
samples[i] = row[x];
}
image.putByteSamples(RGBIndex.INDEX_GREEN, 0, y, COLUMNS, 1, samples, 0);
// copy blue samples to array samples and store those samples
for (int x = X1 * 3, i = 0; i < COLUMNS; x += 3, i++)
{
samples[i] = row[x];
}
image.putByteSamples(RGBIndex.INDEX_BLUE, 0, y, COLUMNS, 1, samples, 0);
y--;
setProgress(processedRows, ROWS);
processedRows++;
}
}
private void loadUncompressedStream() throws
IOException,
OperationFailedException
{
switch(colorDepth)
{
case(1):
{
loadUncompressedBilevelStream();
break;
}
case(4):
{
loadUncompressedPaletted4Stream();
break;
}
case(8):
{
loadUncompressedPaletted8Stream();
break;
}
case(24):
{
loadUncompressedRgb24Stream();
break;
}
}
}
public void process() throws
MissingParameterException,
OperationFailedException
{
initModeFromIOObjects();
if (getMode() == CodecMode.LOAD)
{
load();
}
else
{
save();
}
}
private void save() throws
MissingParameterException,
OperationFailedException,
UnsupportedTypeException
{
// check parameters of this operation
// 1 image to be saved
// 1.1 is it available?
PixelImage image = getImage();
if (image == null)
{
throw new MissingParameterException("No image available.");
}
// 1.2 is it supported?
if (!(image instanceof Paletted8Image ||
image instanceof Gray8Image ||
image instanceof BilevelImage ||
image instanceof RGB24Image))
{
throw new UnsupportedTypeException("Unsupported image type: " + image.getClass().getName());
}
// 2 is output stream available?
out = getOutputAsDataOutput();
if (out == null)
{
throw new MissingParameterException("Output stream / random access file parameter missing.");
}
// now write the output stream
try
{
writeStream();
}
catch (IOException ioe)
{
throw new OperationFailedException("I/O failure: " + ioe.toString());
}
}
public String suggestFileExtension(PixelImage image)
{
return ".bmp";
}
private void writeHeader(PixelImage image, int filesize, int offset, int numBits) throws IOException
{
out.write(0x42); // 'B'
out.write(0x4d); // 'M'
writeInt(filesize);
writeShort(0);
writeShort(0);
writeInt(offset);
writeInt(40); // BITMAP_INFO header length
writeInt(getBoundsWidth());
writeInt(getBoundsHeight());
writeShort(1); // # of planes
writeShort(numBits);
writeInt(0); // compression (0 = none)
writeInt(filesize - offset); // size of image data in bytes
writeInt((int)(getDpiX() * (100f / 2.54f))); // horizontal resolution in dpi
writeInt((int)(getDpiY() * (100f / 2.54f))); // vertical resolution in dpi
writeInt(0); // # of used colors
writeInt(0); // # of important colors
}
// we can't use out.writeInt because we need little endian byte order
private void writeInt(int value) throws IOException
{
out.write(value & 0xff);
out.write((value >> 8) & 0xff);
out.write((value >> 16) & 0xff);
out.write((value >> 24) & 0xff);
}
/**
* Write the palette associated with the image getImage().
* Required not only for image objects that implement PalettedImage
* but also for BilevelImage and Grayscale8Image.
* For the latter two the palette values must be explicitly written into the file.
*/
private void writePalette() throws IOException
{
PixelImage pi = getImage();
if (pi == null)
{
return;
}
if (pi instanceof Paletted8Image)
{
// always write 256 entries; if there aren't enough
// in the palette, fill it up to 256 with (0, 0, 0, 0)
Palette palette = ((Paletted8Image)pi).getPalette();
for (int i = 0; i < 256; i++)
{
if (i < palette.getNumEntries())
{
out.write(palette.getSample(RGBIndex.INDEX_BLUE, i));
out.write(palette.getSample(RGBIndex.INDEX_GREEN, i));
out.write(palette.getSample(RGBIndex.INDEX_RED, i));
out.write(0);
}
else
{
out.writeInt(0); // writes four 0 bytes
}
}
}
if (pi instanceof Gray8Image)
{
for (int i = 0; i < 256; i++)
{
out.write(i);
out.write(i);
out.write(i);
out.write(0);
}
}
if (pi instanceof BilevelImage)
{
for (int i = 0; i < 2; i++)
{
out.write(i * 255);
out.write(i * 255);
out.write(i * 255);
out.write(0);
}
}
}
// we can't use out.writeShort because we need little endian byte order
private void writeShort(int value) throws IOException
{
out.write(value & 0xff);
out.write((value >> 8) & 0xff);
}
private void writeStream() throws IOException
{
PixelImage image = getImage();
setBoundsIfNecessary(image.getWidth(), image.getHeight());
int width = getBoundsWidth();
int height = getBoundsHeight();
ByteChannelImage bcimg = null;
BilevelImage bilevelImage = null;
RGB24Image rgbimg = null;
int bytesPerRow = 0;
int offset = 54;
int numBits = 0;
int numPackedBytes = 0;
if (image instanceof Paletted8Image ||
image instanceof Gray8Image)
{
bcimg = (ByteChannelImage)image;
bytesPerRow = width;
offset += 1024;
numBits = 8;
}
else
if (image instanceof BilevelImage)
{
bilevelImage = (BilevelImage)image;
numPackedBytes = (width + 7) / 8;
bytesPerRow = numPackedBytes;
offset += 8;
numBits = 1;
}
else
if (image instanceof RGB24Image)
{
rgbimg = (RGB24Image)image;
bytesPerRow = width * 3;
numBits = 24;
}
if ((bytesPerRow % 4) != 0)
{
bytesPerRow = ((bytesPerRow + 3) / 4) * 4;
}
int filesize = offset + bytesPerRow * height;
writeHeader(image, filesize, offset, numBits);
writePalette();
byte[] row = new byte[bytesPerRow];
final int X1 = getBoundsX1();
for (int y = getBoundsY2(), processed = 0; processed < height; y--, processed++)
{
if (bilevelImage != null)
{
bilevelImage.getPackedBytes(X1, y, width, row, 0, 0);
}
else
if (bcimg != null)
{
bcimg.getByteSamples(0, 0, y, width, 1, row, 0);
}
else
if (rgbimg != null)
{
int offs = 0;
for (int x = X1; x < X1 + width; x++)
{
row[offs++] = rgbimg.getByteSample(RGBIndex.INDEX_BLUE, x, y);
row[offs++] = rgbimg.getByteSample(RGBIndex.INDEX_GREEN, x, y);
row[offs++] = rgbimg.getByteSample(RGBIndex.INDEX_RED, x, y);
}
}
else
{
// error
}
out.write(row);
setProgress(processed, height);
if (getAbort())
{
break;
}
}
close();
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/tiff/ 0000775 0000000 0000000 00000000000 10546532076 022226 5 ustar java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/tiff/TIFFRational.java 0000664 0000000 0000000 00000003677 07741250131 025320 0 ustar /*
* TIFFRational
*
* Copyright (c) 2001, 2002 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.codecs.tiff;
/**
* Data class to store a TIFF rational number.
* A TIFF rational number is a fraction given by 32 bit integer numerator and denominator values.
* It is one of the data types used in TIFF tags ({@link TIFFTag}).
* For more information on TIFF's internals, see {@link TIFFCodec}, which lists a few links
* to TIFF specification documents.
* @author Marco Schmidt
*/
public class TIFFRational
{
private int numerator;
private int denominator;
/**
* Creates a TiffRational object from the arguments.
* @param numerator the numerator of the fraction stored in this object
* @param denominator the denominator of the fraction stored in this object
* @throws IllegalArgumentException if denominator is 0
(division by zero is not allowed)
*/
public TIFFRational(int numerator, int denominator)
{
if (denominator == 0)
{
throw new IllegalArgumentException("A zero denominator is not allowed.");
}
this.numerator = numerator;
this.denominator = denominator;
}
/**
* Returns the denominator value that was given to the constructor.
* @return denominator value
*/
public int getDenominator()
{
return denominator;
}
/**
* Returns the fraction as a double
value.
* @return the fraction stored in this object
* @see #getAsFloat
*/
public double getAsDouble()
{
return (double)numerator / (double)denominator;
}
/**
* Returns the fraction as a float
value.
* @return the fraction stored in this object
* @see #getAsDouble
*/
public float getAsFloat()
{
return (float)numerator / (float)denominator;
}
/**
* Returns the numerator value that was given to the constructor.
* @return numerator value
*/
public int getNumerator()
{
return numerator;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/tiff/TIFFDecoderLogLuv.java 0000664 0000000 0000000 00000007702 07741250131 026236 0 ustar /*
* TIFFDecoderLogLuv
*
* Copyright (c) 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.codecs.tiff;
import java.io.DataInput;
import java.io.IOException;
import net.sourceforge.jiu.codecs.tiff.TIFFConstants;
import net.sourceforge.jiu.codecs.tiff.TIFFDecoder;
import net.sourceforge.jiu.codecs.InvalidFileStructureException;
import net.sourceforge.jiu.ops.MissingParameterException;
/**
* A TIFF decoder for files compressed with the LogLuv RLE method.
* This compression algorithm has the value 34676
* ({@link TIFFConstants#COMPRESSION_SGI_LOG_RLE})
* in the compression tag of an image file directory.
* Only image data with a photometric interpretation value of
* {@link TIFFConstants#PHOTOMETRIC_TRUECOLOR_LOGLUV} can be compressed with this method.
* tif_luv.c
which
* is part of the TIFF library libtiff.
* The original implementation was written by Greg W. Larson.
* null
) is returned.
* Use {@link #setTimeZone} to provide a time zone before the date
* parsing is done.
* @see #getDateTimeString
*/
public Date getDateTime()
{
return date;
}
/**
* If there was a date / time tag in this IFD, its String value
* is returned.
* @see #getDateTime
*/
public String getDateTimeString()
{
return dateTime;
}
public int getDpiX()
{
return dpiX;
}
public int getDpiY()
{
return dpiY;
}
public int getHeight()
{
return height;
}
public String getHostComputer()
{
return hostComputer;
}
public String getImageDescription()
{
return imageDescription;
}
public int getImageType()
{
return imageType;
}
public String getModel()
{
return model;
}
public int getNumHorizontalTiles()
{
return horizontalTiles;
}
public int getNumStrips()
{
return numStrips;
}
public int getNumTiles()
{
return numTiles;
}
public int getNumVerticalTiles()
{
return verticalTiles;
}
public Palette getPalette()
{
return palette;
}
public int getPhotometricInterpretation()
{
return photometricInterpretation;
}
public int getPredictor()
{
return predictor;
}
public int getRowsPerStrip()
{
return rowsPerStrip;
}
public int getSamplesPerPixel()
{
return samplesPerPixel;
}
public String getSoftware()
{
return software;
}
public Vector getStripOffsets()
{
return stripOffsets;
}
public int getT4Options()
{
return t4Options;
}
public int getT6Options()
{
return t6Options;
}
public int getTileHeight()
{
return tileHeight;
}
public long getTileOffset(int tileIndex)
{
if (stripOffsets != null)
{
Number number = (Number)stripOffsets.elementAt(tileIndex);
return number.longValue();
}
else
if (tileOffsets != null)
{
Number number = (Number)tileOffsets.elementAt(tileIndex);
return number.longValue();
}
else
{
throw new IllegalArgumentException("Tile index invalid: " + tileIndex);
}
}
public int getTileWidth()
{
return tileWidth;
}
public int getTileX1(int tileIndex)
{
if (tileIndex < 0 || tileIndex >= getNumTiles())
{
throw new IllegalArgumentException("Not a valid tile index: " + tileIndex);
}
else
{
return (tileIndex % getNumHorizontalTiles()) * getTileWidth();
}
}
public int getTileX2(int tileIndex)
{
if (tileIndex < 0 || tileIndex >= getNumTiles())
{
throw new IllegalArgumentException("Not a valid tile index: " + tileIndex);
}
else
{
return ((tileIndex % getNumHorizontalTiles()) + 1) * getTileWidth() - 1;
}
}
public int getTileY1(int tileIndex)
{
if (tileIndex < 0 || tileIndex >= getNumTiles())
{
throw new IllegalArgumentException("Not a valid tile index: " + tileIndex);
}
else
{
return (tileIndex % getNumVerticalTiles()) * getTileHeight();
}
}
public int getTileY2(int tileIndex)
{
if (tileIndex < 0 || tileIndex >= getNumTiles())
{
throw new IllegalArgumentException("Not a valid tile index: " + tileIndex);
}
else
{
int result = ((tileIndex % getNumVerticalTiles()) + 1) * getTileHeight() - 1;
if (result >= height)
{
result = height - 1;
}
return result;
}
}
public int getWidth()
{
return width;
}
public void initMembers()
{
bitsPerPixel = -1;
bitsPerSample = null;
compression = -1;
height = -1;
horizontalTiles = -1;
invertGraySamples = false;
numStrips = -1;
numTiles = -1;
orientation = 1;
photometricInterpretation = -1;
planarConfiguration = -1;
resolutionUnit = 2;
resolutionX = -1.0;
resolutionY = -1.0;
rowsPerStrip = -1;
stripOffsets = null;
tags = null;
tileOffsets = null;
tileWidth = -1;
tileHeight = -1;
verticalTiles = -1;
width = -1;
}
public void initFromTags(boolean check) throws
InvalidFileStructureException,
UnsupportedTypeException
{
int index = 0;
while (index < tags.size())
{
TIFFTag tag = (TIFFTag)tags.elementAt(index++);
int id = tag.getId();
int count = tag.getCount();
int type = tag.getType();
boolean isNotInt = !tag.isInt();
switch(id)
{
case(TAG_ARTIST):
{
artist = tag.getString();
break;
}
case(TAG_BITS_PER_SAMPLE):
{
if (isNotInt)
{
throw new InvalidFileStructureException("Bits per " +
"sample value(s) must be byte/short/long; type=" +
type);
}
if (count == 1)
{
bitsPerSample = new int[1];
bitsPerSample[0] = tag.getOffset();
bitsPerPixel = bitsPerSample[0];
}
else
{
bitsPerPixel = 0;
bitsPerSample = new int[count];
for (int i = 0; i < count; i++)
{
bitsPerSample[i] = tag.getElementAsInt(i);
if (bitsPerSample[i] < 1)
{
throw new InvalidFileStructureException("Bits per " +
"sample value #" + i + " is smaller than 1.");
}
bitsPerPixel += bitsPerSample[i];
}
}
break;
}
case(TAG_COLOR_MAP):
{
if ((count % 3) != 0)
{
throw new InvalidFileStructureException("Number of palette entries must be divideable by three without rest; " + count);
}
if (count < 3 || count > 768)
{
throw new UnsupportedTypeException("Unsupported number of palette entries: " + count + ".");
}
if (type != TAG_TYPE_SHORT)
{
throw new UnsupportedTypeException("Unsupported number type for palette entries: " + type);
}
int numEntries = count / 3;
palette = new Palette(numEntries, 255);
int vectorIndex = 0;
for (int paletteIndex = 0; paletteIndex < numEntries; paletteIndex++)
{
palette.putSample(RGBIndex.INDEX_RED, paletteIndex, tag.getElementAsInt(vectorIndex++) >> 8);
}
for (int paletteIndex = 0; paletteIndex < numEntries; paletteIndex++)
{
palette.putSample(RGBIndex.INDEX_GREEN, paletteIndex, tag.getElementAsInt(vectorIndex++) >> 8);
}
for (int paletteIndex = 0; paletteIndex < numEntries; paletteIndex++)
{
palette.putSample(RGBIndex.INDEX_BLUE, paletteIndex, tag.getElementAsInt(vectorIndex++) >> 8);
}
break;
}
case(TAG_COMPRESSION):
{
if (count != 1 || isNotInt)
{
throw new InvalidFileStructureException("Expected " +
" single byte/short/long value for compression " +
"(count=" + count + ", type=" + type + ").");
}
compression = tag.getOffset();
break;
}
case(TAG_DATE_TIME):
{
dateTime = tag.getString();
if (dateTime != null)
{
dateTime = dateTime.trim();
}
if (dateTime != null)
{
SimpleDateFormat format = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss");
if (timeZone != null)
{
format.setCalendar(new GregorianCalendar(timeZone));
}
try
{
date = format.parse(dateTime);
}
catch (ParseException pe)
{
date = null;
}
}
break;
}
case(TAG_HOST_COMPUTER):
{
hostComputer = tag.getString();
break;
}
case(TAG_IMAGE_DESCRIPTION):
{
imageDescription = tag.getString();
break;
}
case(TAG_IMAGE_WIDTH):
{
if (count != 1 || isNotInt)
{
throw new InvalidFileStructureException("Expected " +
"single byte/short/long value for image width " +
"(count=" + count + ", type=" + type + ").");
}
width = tag.getOffset();
break;
}
case(TAG_IMAGE_LENGTH):
{
if (count != 1 || isNotInt)
{
throw new InvalidFileStructureException("Expected " +
"single byte/short/long value for image height " +
"(count=" + count + ", type=" + type + ").");
}
height = tag.getOffset();
break;
}
case(TAG_MAKE):
{
make = tag.getString();
break;
}
case(TAG_MODEL):
{
model = tag.getString();
break;
}
case(TAG_ORIENTATION):
{
if (count != 1 || isNotInt)
{
throw new InvalidFileStructureException("Expected " +
"single byte/short/long value for image height " +
"(count=" + count + ", type=" + type + ").");
}
orientation = tag.getOffset();
break;
}
case(TAG_PHOTOMETRIC_INTERPRETATION):
{
if (count != 1 || isNotInt)
{
throw new InvalidFileStructureException("Expected " +
"single byte/short/long value for photometric interpretation.");
}
photometricInterpretation = tag.getOffset();
break;
}
case(TAG_RESOLUTION_UNIT):
{
if (count != 1 || isNotInt)
{
throw new InvalidFileStructureException("Expected " +
"single byte/short/long value for planar configuration.");
}
resolutionUnit = tag.getOffset();
break;
}
case(TAG_RESOLUTION_X):
{
if (count != 1 || type != TAG_TYPE_RATIONAL)
{
throw new InvalidFileStructureException("Expected " +
"single byte/short/long value for planar configuration.");
}
Object o = tag.getObject(0);
if (o != null && o instanceof TIFFRational)
{
TIFFRational rational = (TIFFRational)o;
resolutionX = rational.getAsDouble();
}
break;
}
case(TAG_RESOLUTION_Y):
{
if (count != 1 || type != TAG_TYPE_RATIONAL)
{
throw new InvalidFileStructureException("Expected " +
"single byte/short/long value for planar configuration.");
}
Object o = tag.getObject(0);
if (o != null && o instanceof TIFFRational)
{
TIFFRational rational = (TIFFRational)o;
resolutionY = rational.getAsDouble();
}
break;
}
case(TAG_PLANAR_CONFIGURATION):
{
if (count != 1 || isNotInt)
{
throw new InvalidFileStructureException("Expected " +
"single byte/short/long value for planar configuration.");
}
planarConfiguration = tag.getOffset();
break;
}
case(TAG_ROWS_PER_STRIP):
{
if (count != 1 || isNotInt)
{
throw new InvalidFileStructureException("Expected " +
"single byte/short/long value for image height.");
}
rowsPerStrip = tag.getOffset();
break;
}
case(TAG_SAMPLES_PER_PIXEL):
{
if (count != 1 || isNotInt)
{
throw new InvalidFileStructureException("Expected " +
"single byte/short/long value for samples per pixel.");
}
samplesPerPixel = tag.getOffset();
break;
}
case(TAG_SOFTWARE):
{
software = tag.getString();
break;
}
case(TAG_STRIP_BYTE_COUNTS):
{
if (count < 1)
{
throw new InvalidFileStructureException("Need at least one strip offset.");
}
if (count == 1)
{
if (isNotInt)
{
throw new InvalidFileStructureException("There is " +
"only one strip offset, but its type is not integer.");
}
stripByteCounts = new Vector();
stripByteCounts.addElement(new Long(tag.getOffset()));
}
else
{
stripByteCounts = tag.getVector();
}
break;
}
case(TAG_STRIP_OFFSETS):
{
if (count < 1)
{
throw new InvalidFileStructureException("Need at least one strip offset.");
}
if (count == 1)
{
if (isNotInt)
{
throw new InvalidFileStructureException("There is " +
"only one strip offset, but its type is not integer.");
}
stripOffsets = new Vector();
stripOffsets.addElement(new Long(tag.getOffset()));
}
else
{
stripOffsets = tag.getVector();
}
numStrips = count;
numTiles = count;
horizontalTiles = 1;
verticalTiles = count;
break;
}
case(TAG_T4_OPTIONS):
{
if (count != 1 || isNotInt)
{
throw new InvalidFileStructureException("Expected " +
"single byte/short/long value for T4 Options.");
}
t4Options = tag.getOffset();
break;
}
case(TAG_T6_OPTIONS):
{
if (count != 1 || isNotInt)
{
throw new InvalidFileStructureException("Expected " +
"single byte/short/long value for T6 Options.");
}
t6Options = tag.getOffset();
break;
}
case(TAG_TILE_HEIGHT):
{
if (count != 1 || isNotInt)
{
throw new InvalidFileStructureException("Expected " +
"single byte/short/long value for image height " +
"(count=" + count + ", type=" + type + ").");
}
tileHeight = tag.getOffset();
if (tileHeight < 1)
{
throw new InvalidFileStructureException("Tile height must be one or larger.");
}
verticalTiles = height / tileHeight;
if ((height % tileHeight) != 0)
{
verticalTiles++;
}
break;
}
case(TAG_TILE_OFFSETS):
{
if (count < 1)
{
throw new InvalidFileStructureException("Need at least one tile offset.");
}
if (count == 1)
{
if (isNotInt)
{
throw new InvalidFileStructureException("There is " +
"only one tile offset, but its type is not integer.");
}
tileOffsets = new Vector();
tileOffsets.addElement(new Long(tag.getOffset()));
}
else
{
tileOffsets = tag.getVector();
}
numStrips = count;
numTiles = count;
horizontalTiles = 1;
verticalTiles = count;
break;
}
case(TAG_TILE_WIDTH):
{
if (count != 1 || isNotInt)
{
throw new InvalidFileStructureException("Expected " +
"single byte/short/long value for image height " +
"(count=" + count + ", type=" + type + ").");
}
tileWidth = tag.getOffset();
if (tileWidth < 1)
{
throw new InvalidFileStructureException("Tile width must be one or larger.");
}
horizontalTiles = width / tileWidth;
if ((width % tileWidth) != 0)
{
horizontalTiles++;
}
break;
}
}
}
if (planarConfiguration == -1)
{
planarConfiguration = PLANAR_CONFIGURATION_CHUNKY;
}
if (photometricInterpretation == TIFFConstants.PHOTOMETRIC_PALETTED)
{
if (bitsPerPixel == 4)
{
imageType = TYPE_PALETTED4;
}
else
if (bitsPerPixel == 8)
{
imageType = TYPE_PALETTED8;
}
else
{
throw new UnsupportedTypeException("Only paletted images with 4 or 8 bits per sample are supported.");
}
}
if (resolutionUnit == 2 && resolutionX > 0.0 && resolutionY > 0.0)
{
dpiX = (int)resolutionX;
dpiY = (int)resolutionY;
}
if (isStriped())
{
tileWidth = width;
if (numStrips == 1 && rowsPerStrip == -1)
{
rowsPerStrip = height;
}
tileHeight = rowsPerStrip;
}
if (check)
{
checkContent();
}
}
public boolean isGrayscale()
{
return getBitsPerPixel() > 1 &&
(photometricInterpretation == PHOTOMETRIC_BLACK_IS_ZERO ||
photometricInterpretation == PHOTOMETRIC_WHITE_IS_ZERO);
}
public boolean isPaletted()
{
return (photometricInterpretation == PHOTOMETRIC_PALETTED);
}
/**
* Returns true
if the image belonging to this IFD
* is stored as strips, false
otherwise.
* @see #isTiled
*/
public boolean isStriped()
{
return (stripOffsets != null);
}
/**
* Returns true
if the image belonging to this IFD
* is stored as tiles, false
otherwise.
* @see #isStriped
*/
public boolean isTiled()
{
return (tileOffsets != null);
}
/**
* Sets the time zone to be used when trying to interpret dates
* found in a {@link #TAG_DATE_TIME} tag.
* Example call:
* setTimeZone(TimeZone.getTimeZone("America/New_York");
.
* @param tz TimeZone object
*/
public void setTimeZone(TimeZone tz)
{
timeZone = tz;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/tiff/TIFFDecoderPackbits.java 0000664 0000000 0000000 00000002750 07741250131 026564 0 ustar /*
* TIFFDecoderPackbits
*
* Copyright (c) 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.codecs.tiff;
import java.io.DataInput;
import java.io.IOException;
import net.sourceforge.jiu.codecs.tiff.TIFFDecoder;
import net.sourceforge.jiu.codecs.InvalidFileStructureException;
/**
* A TIFF decoder for files compressed with the Packbits method.
* This compression algorithm has the value 32773
* in the compression tag of an image file directory.
* @author Marco Schmidt
* @since 0.9.0
*/
public class TIFFDecoderPackbits extends TIFFDecoder
{
public void decode() throws
InvalidFileStructureException,
IOException
{
DataInput in = getInput();
byte[] row = new byte[getBytesPerRow()];
for (int y = getY1(); y <= getY2(); y++)
{
int index = 0;
do
{
byte value = in.readByte();
if (value >= 0)
{
int numSamples = value + 1;
// copy bytes literally
in.readFully(row, index, numSamples);
index += numSamples;
}
else
if (value != (byte)-128)
{
int numSamples = - value + 1;
// write run
byte sample = in.readByte();
while (numSamples-- != 0)
{
row[index++] = sample;
}
}
}
while (index != row.length);
putBytes(row, 0, row.length);
}
}
public Integer[] getCompressionTypes()
{
return new Integer[] {new Integer(TIFFConstants.COMPRESSION_PACKBITS)};
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/tiff/TIFFDecoderDeflated.java 0000664 0000000 0000000 00000007130 10505557641 026541 0 ustar /*
* TIFFDecoderDeflated
*
* Copyright (c) 2002, 2003, 2004, 2005, 2006 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.codecs.tiff;
import java.io.DataInput;
import java.io.IOException;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;
import net.sourceforge.jiu.codecs.tiff.TIFFConstants;
import net.sourceforge.jiu.codecs.tiff.TIFFDecoder;
import net.sourceforge.jiu.codecs.tiff.TIFFImageFileDirectory;
import net.sourceforge.jiu.codecs.InvalidFileStructureException;
import net.sourceforge.jiu.ops.MissingParameterException;
/**
* A TIFF decoder for files compressed with the Deflated method.
* This compression algorithm has the values 31946
* ({@link TIFFConstants#COMPRESSION_DEFLATED_INOFFICIAL}) and 8
* ({@link TIFFConstants#COMPRESSION_DEFLATED_OFFICIAL})
* in the compression tag of an image file directory.
* All types of image data can be compressed with this method.
* Package Specification
1
, no compression)
for each strip or tile and lets them do the image loading.
2
* in the compression tag of an image file directory.
* Only bilevel images can be encoded with that method.
* @author Marco Schmidt
* @since 0.9.0
*/
public class TIFFDecoderModifiedHuffman extends TIFFDecoder
{
private DataInput in;
private int bitBuffer;
private int numBufferedBits;
public void decode() throws
InvalidFileStructureException,
IOException
{
byte[] row = new byte[getBytesPerRow()];
for (int y = getY1(); y <= getY2(); y++)
{
decodeRow(row);
putBytes(row, 0, row.length);
}
}
private int decodeBlackRun() throws
InvalidFileStructureException,
IOException
{
return decodeRun(TIFFFaxCodes.BLACK_CODES, TIFFFaxCodes.MIN_BLACK_CODE_SIZE);
}
private void decodeRow(byte[] row) throws
InvalidFileStructureException,
IOException
{
reset();
boolean black = false;
int index = 0;
do
{
// this will hold the accumulated run length for the current
// color at the end of this loop iteration
int completeRunLength = 0;
// get run lengths regarding current color until one is smaller than 64
int runLength;
do
{
if (black)
{
runLength = decodeBlackRun();
}
else
{
runLength = decodeWhiteRun();
}
completeRunLength += runLength;
}
while (runLength >= 64);
// pick color value for output row
byte value;
if (black)
{
value = (byte)BilevelImage.BLACK;
}
else
{
value = (byte)BilevelImage.WHITE;
}
// fill row buffer with value
while (completeRunLength-- > 0)
{
row[index++] = value;
}
// switch colors (black to white or vice versa)
black = !black;
}
while (index < row.length);
}
private int decodeRun(int[][][] codes, int minCodeSize) throws
InvalidFileStructureException,
IOException
{
int code = readBits(minCodeSize);
//int currentCodeSize = minCodeSize;
for (int i = 0; i < codes.length; i++)
{
int[][] data = codes[i];
int j = 0;
final int LENGTH = data.length;
while (j < LENGTH)
{
int[] pair = data[j++];
if (pair[TIFFFaxCodes.INDEX_CODE_WORD] == code)
{
return pair[TIFFFaxCodes.INDEX_CODE_VALUE];
}
}
code = (code << 1) | readBit();
}
throw new InvalidFileStructureException("Could not identify Huffman code in TIFF file.");
}
private int decodeWhiteRun() throws
InvalidFileStructureException,
IOException
{
return decodeRun(TIFFFaxCodes.WHITE_CODES, TIFFFaxCodes.MIN_WHITE_CODE_SIZE);
}
public Integer[] getCompressionTypes()
{
return new Integer[] {new Integer(TIFFConstants.COMPRESSION_CCITT_GROUP3_1D_MODIFIED_HUFFMAN)};
}
public void initialize() throws
IOException,
MissingParameterException
{
super.initialize();
in = getInput();
}
private int readBit() throws IOException
{
int result;
if (numBufferedBits == 0)
{
bitBuffer = in.readUnsignedByte();
if ((bitBuffer & 0x80) == 0)
{
result = 0;
}
else
{
result = 1;
}
bitBuffer &= 0x7f;
numBufferedBits = 7;
}
else
{
numBufferedBits--;
result = bitBuffer >> numBufferedBits;
bitBuffer &= (1 << numBufferedBits) - 1;
}
return result;
}
private int readBits(int number) throws IOException
{
// make sure there are at least number bits
while (numBufferedBits < number)
{
int b = in.readUnsignedByte();
bitBuffer = (bitBuffer << 8) | b;
numBufferedBits += 8;
}
numBufferedBits -= number;
int result = bitBuffer >> numBufferedBits;
bitBuffer &= (1 << numBufferedBits) - 1;
return result;
}
private void reset()
{
bitBuffer = 0;
numBufferedBits = 0;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/tiff/TIFFDecoder.java 0000664 0000000 0000000 00000037263 07762134364 025126 0 ustar /*
* TIFFDecoder
*
* Copyright (c) 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.codecs.tiff;
import java.io.DataInput;
import java.io.IOException;
import java.io.RandomAccessFile;
import net.sourceforge.jiu.codecs.InvalidFileStructureException;
import net.sourceforge.jiu.color.conversion.CMYKConversion;
import net.sourceforge.jiu.color.conversion.LogLuvConversion;
import net.sourceforge.jiu.data.BilevelImage;
import net.sourceforge.jiu.data.ByteChannelImage;
import net.sourceforge.jiu.data.RGBIndex;
import net.sourceforge.jiu.data.ShortChannelImage;
import net.sourceforge.jiu.ops.MissingParameterException;
import net.sourceforge.jiu.util.ArrayConverter;
/**
* The abstract base class for a TIFF decoder, a class that decompresses one tile or
* strip of image data and understands one or more compression types.
* Each child class implements the decoding of a particular TIFF compression type
* in its {@link #decode} method.
* number
bytes
* in data
.
* @param data byte array with image data that has been decoded
* @param offset int index into data where the first byte to be stored is situated
* @param number int number of bytes to be stored
*/
public void putBytes(byte[] data, int offset, int number)
{
// assert(bufferIndex < rowBuffer.length);
while (number > 0)
{
int remaining = rowBuffer.length - bufferIndex;
int numCopy;
if (number > remaining)
{
numCopy = remaining;
}
else
{
numCopy = number;
}
System.arraycopy(data, offset, rowBuffer, bufferIndex, numCopy);
number -= numCopy;
offset += numCopy;
bufferIndex += numCopy;
if (bufferIndex == getBytesPerRow())
{
storeRow(rowBuffer, 0);
bufferIndex = 0;
}
}
}
/**
* Specify the codec to be used with this decoder.
* This is a mandatory parameter - without it, {@link #initialize}
* will throw an exception.
* @param tiffCodec TIFFCodec object to be used by this decoder
* @see #getCodec
*/
public void setCodec(TIFFCodec tiffCodec)
{
codec = tiffCodec;
}
/**
* Specify the IFD to be used with this decoder.
* This is a mandatory parameter - without it, {@link #initialize}
* will throw an exception.
* @param tiffIfd object to be used by this decoder
* @see #getImageFileDirectory
*/
public void setImageFileDirectory(TIFFImageFileDirectory tiffIfd)
{
ifd = tiffIfd;
}
/**
* Specify the zero-based tile index for the tile or strip to be decompressed
* by this decoder.
* This is a mandatory parameter - without it, {@link #initialize}
* will throw an exception.
* @param index zero-based tile / strip index
* @see #getTileIndex
*/
public void setTileIndex(int index)
{
if (index < 0)
{
throw new IllegalArgumentException("Tile index must be 0 or larger.");
}
tileIndex = index;
}
private void storeRow(byte[] data, int offset)
{
codec.setProgress(processedTileRows++, totalTileRows);
// get current row number and increase field currentRow by one
int y = currentRow++;
// buffer index field is reset to zero so that putBytes will start at the beginning of the buffer next time
bufferIndex = 0;
// leave if we don't need that row because of bounds
if (!codec.isRowRequired(y))
{
return;
}
// adjust y so that it will be in bounds coordinate space
y -= codec.getBoundsY1();
// get leftmost and rightmost pixel index of the current tile
int x1 = getX1();
int x2 = getX2();
// compute number of pixels, adjust for bounds
int numPixels = x2 - x1 + 1;
int leftPixels = 0;
if (getX1() < codec.getBoundsX1())
{
leftPixels = codec.getBoundsX1() - getX1();
}
int rightPixels = 0;
if (getX2() > codec.getBoundsX2())
{
rightPixels = getX2() - codec.getBoundsX2();
}
numPixels -= (rightPixels + leftPixels);
switch(ifd.getImageType())
{
case(TIFFImageFileDirectory.TYPE_BILEVEL_BYTE):
{
BilevelImage image = (BilevelImage)codec.getImage();
int index = offset + leftPixels;
int x = getX1() - codec.getBoundsX1() + leftPixels;
while (numPixels-- > 0)
{
if (data[index++] == (byte)BilevelImage.BLACK)
{
image.putBlack(x++, y);
}
else
{
image.putWhite(x++, y);
}
}
break;
}
case(TIFFImageFileDirectory.TYPE_BILEVEL_PACKED):
{
BilevelImage image = (BilevelImage)codec.getImage();
int x = getX1() - codec.getBoundsX1() + leftPixels;
image.putPackedBytes(x, y, numPixels, data, offset + (leftPixels / 8), leftPixels % 8);
break;
}
case(TIFFImageFileDirectory.TYPE_GRAY4):
{
ByteChannelImage image = (ByteChannelImage)codec.getImage();
byte[] dest = new byte[data.length * 2];
ArrayConverter.decodePacked4Bit(data, 0, dest, 0, data.length);
for (int i = 0; i < dest.length; i++)
{
int value = dest[i] & 15;
value = (value << 4) | value;
dest[i] = (byte)value;
}
image.putByteSamples(0, getX1() - codec.getBoundsX1() + leftPixels, y, numPixels, 1, dest, offset + leftPixels);
break;
}
case(TIFFImageFileDirectory.TYPE_PALETTED4):
{
ByteChannelImage image = (ByteChannelImage)codec.getImage();
byte[] dest = new byte[data.length * 2];
ArrayConverter.decodePacked4Bit(data, 0, dest, 0, data.length);
image.putByteSamples(0, getX1() - codec.getBoundsX1() + leftPixels, y, numPixels, 1, dest, offset + leftPixels);
break;
}
case(TIFFImageFileDirectory.TYPE_GRAY8):
case(TIFFImageFileDirectory.TYPE_PALETTED8):
{
ByteChannelImage image = (ByteChannelImage)codec.getImage();
image.putByteSamples(0, getX1() - codec.getBoundsX1() + leftPixels, y, numPixels, 1, data, offset + leftPixels);
break;
}
case(TIFFImageFileDirectory.TYPE_CMYK32_INTERLEAVED):
{
ByteChannelImage image = (ByteChannelImage)codec.getImage();
byte[] dest = new byte[data.length];
int numSamples = ifd.getTileWidth();
CMYKConversion.convertCMYK32InterleavedToRGB24Planar(
data, 0,
dest, 0,
dest, numSamples,
dest, numSamples * 2,
numSamples);
image.putByteSamples(RGBIndex.INDEX_RED, getX1() - codec.getBoundsX1() + leftPixels, y, numPixels, 1, dest, leftPixels);
image.putByteSamples(RGBIndex.INDEX_GREEN, getX1() - codec.getBoundsX1() + leftPixels, y, numPixels, 1, dest, numSamples + leftPixels);
image.putByteSamples(RGBIndex.INDEX_BLUE, getX1() - codec.getBoundsX1() + leftPixels, y, numPixels, 1, dest, 2 * numSamples + leftPixels);
break;
}
/* case(TIFFImageFileDirectory.TYPE_CMYK32_PLANAR):
{
ByteChannelImage image = (ByteChannelImage)codec.getImage();
byte[] dest = new byte[data.length];
int numSamples = ifd.getTileWidth();
CMYKConversion.convertCMYK32PlanarToRGB24Planar(
data, 0,
data, numPixels,
data, numPixels * 2,
data, numPixels * 3,
dest, 0,
dest, numSamples,
dest, numSamples * 2,
numSamples);
image.putByteSamples(RGBIndex.INDEX_RED, getX1() - codec.getBoundsX1() + leftPixels, y, numPixels, 1, dest, leftPixels);
image.putByteSamples(RGBIndex.INDEX_GREEN, getX1() - codec.getBoundsX1() + leftPixels, y, numPixels, 1, dest, numSamples + leftPixels);
image.putByteSamples(RGBIndex.INDEX_BLUE, getX1() - codec.getBoundsX1() + leftPixels, y, numPixels, 1, dest, 2 * numSamples + leftPixels);
break;
}*/
case(TIFFImageFileDirectory.TYPE_RGB24_INTERLEAVED):
{
ByteChannelImage image = (ByteChannelImage)codec.getImage();
offset += leftPixels * 3;
for (int i = 0, x = getX1() - codec.getBoundsX1() + leftPixels; i < numPixels; i++, x++)
{
image.putByteSample(RGBIndex.INDEX_RED, x, y, data[offset++]);
image.putByteSample(RGBIndex.INDEX_GREEN, x, y, data[offset++]);
image.putByteSample(RGBIndex.INDEX_BLUE, x, y, data[offset++]);
}
break;
}
case(TIFFImageFileDirectory.TYPE_RGB48_INTERLEAVED):
{
ShortChannelImage image = (ShortChannelImage)codec.getImage();
offset += leftPixels * 3;
short[] triplet = new short[3];
boolean littleEndian = codec.getByteOrder() == TIFFCodec.BYTE_ORDER_INTEL;
for (int i = 0, x = getX1() - codec.getBoundsX1() + leftPixels; i < numPixels; i++, x++)
{
for (int j = 0; j < 3; j++, offset += 2)
{
if (littleEndian)
{
triplet[j] = ArrayConverter.getShortLE(data, offset);
}
else
{
triplet[j] = ArrayConverter.getShortBE(data, offset);
}
}
image.putShortSample(RGBIndex.INDEX_RED, x, y, triplet[0]);
image.putShortSample(RGBIndex.INDEX_GREEN, x, y, triplet[1]);
image.putShortSample(RGBIndex.INDEX_BLUE, x, y, triplet[2]);
}
break;
}
case(TIFFImageFileDirectory.TYPE_LOGLUV32_INTERLEAVED):
{
if (getImageFileDirectory().getCompression() == TIFFConstants.COMPRESSION_SGI_LOG_RLE)
{
ByteChannelImage image = (ByteChannelImage)codec.getImage();
int numSamples = ifd.getTileWidth();
byte[] red = new byte[numSamples];
byte[] green = new byte[numSamples];
byte[] blue = new byte[numSamples];
LogLuvConversion.convertLogLuv32InterleavedtoRGB24Planar(data, red, green, blue, numSamples);
image.putByteSamples(RGBIndex.INDEX_RED, getX1() - codec.getBoundsX1() + leftPixels, y, numPixels, 1, red, leftPixels);
image.putByteSamples(RGBIndex.INDEX_GREEN, getX1() - codec.getBoundsX1() + leftPixels, y, numPixels, 1, green, leftPixels);
image.putByteSamples(RGBIndex.INDEX_BLUE, getX1() - codec.getBoundsX1() + leftPixels, y, numPixels, 1, blue, leftPixels);
}
else
if (getImageFileDirectory().getCompression() == TIFFConstants.COMPRESSION_SGI_LOG_24_PACKED)
{
ByteChannelImage image = (ByteChannelImage)codec.getImage();
int numSamples = ifd.getTileWidth();
byte[] red = new byte[numSamples];
byte[] green = new byte[numSamples];
byte[] blue = new byte[numSamples];
LogLuvConversion.convertLogLuv24InterleavedtoRGB24Planar(data, red, green, blue, numSamples);
image.putByteSamples(RGBIndex.INDEX_RED, getX1() - codec.getBoundsX1() + leftPixels, y, numPixels, 1, red, leftPixels);
image.putByteSamples(RGBIndex.INDEX_GREEN, getX1() - codec.getBoundsX1() + leftPixels, y, numPixels, 1, green, leftPixels);
image.putByteSamples(RGBIndex.INDEX_BLUE, getX1() - codec.getBoundsX1() + leftPixels, y, numPixels, 1, blue, leftPixels);
}
break;
}
case(TIFFImageFileDirectory.TYPE_LOGL):
{
ByteChannelImage image = (ByteChannelImage)codec.getImage();
int numSamples = ifd.getTileWidth();
byte[] gray = new byte[numSamples];
LogLuvConversion.convertLogL16toGray8(data, gray, numSamples);
image.putByteSamples(0, getX1() - codec.getBoundsX1() + leftPixels, y, numPixels, 1, gray, leftPixels);
break;
}
}
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/tiff/TIFFCodec.java 0000664 0000000 0000000 00000067146 10542176267 024577 0 ustar /*
* TIFFCodec
*
* Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.codecs.tiff;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Hashtable;
import java.util.Vector;
import net.sourceforge.jiu.codecs.CodecMode;
import net.sourceforge.jiu.codecs.ImageCodec;
import net.sourceforge.jiu.codecs.InvalidFileStructureException;
import net.sourceforge.jiu.codecs.UnsupportedCodecModeException;
import net.sourceforge.jiu.codecs.UnsupportedTypeException;
import net.sourceforge.jiu.codecs.WrongFileFormatException;
import net.sourceforge.jiu.data.MemoryBilevelImage;
import net.sourceforge.jiu.data.MemoryGray16Image;
import net.sourceforge.jiu.data.MemoryGray8Image;
import net.sourceforge.jiu.data.MemoryPaletted8Image;
import net.sourceforge.jiu.data.MemoryRGB24Image;
import net.sourceforge.jiu.data.MemoryRGB48Image;
import net.sourceforge.jiu.data.PixelImage;
import net.sourceforge.jiu.ops.MissingParameterException;
import net.sourceforge.jiu.ops.OperationFailedException;
import net.sourceforge.jiu.ops.WrongParameterException;
/**
* A codec to read Tagged Image File Format (TIFF) image files.
*
* Usage example
* Load an image from a TIFF file.
*
* TIFFCodec codec = new TIFFCodec();
* codec.setFile("image.tif", CodecMode.LOAD);
* codec.process();
* PixelImage loadedImage = codec.getImage();
*
* Saving images is not supported by this codec.
*
* Compression types
* Reading
* The TIFF package supports the following compression types when reading:
*
*
* Image types
* Reading
* The TIFF package supports the following image / color types when reading:
*
*
* Writing
* Strips and tiles
* The early versions of TIFF considered an image to be a sequence of strips.
* Each strip was a rectangular part of the image, as wide as the complete image,
* and with a certain height defined by the rows per strip tag.
* So with a number of rows per strip of 10, and an image height of 200, you would
* have to store 20 strips.
* It was recommended that a strip should not be larger than 8 KB (RAM was tighter
* in those days).
* The rule of thumb to define the number of rows per strip was to see how many rows
* would fit into 8 KB.
* Number of images
* TIFF allows for multiple images in a single file.
* This codec regards the image index, queries {@link #getImageIndex} and skips to the
* correct image.
*
* Bounds
* The bounds concept of JIU is supported by this codec.
* So you can specify bounds of a rectangular part of an image that you want to load
* instead of loading the complete image.
*
* Color spaces
* The following color spaces are understood when reading truecolor TIFF files.
*
*
* Physical resolution
* DPI information can be stored in TIFF files.
* If that information is available, this codec retrieves it so that it
* can be queried using {@link #getDpiX} and {@link #getDpiY}.
*
* Background information on TIFF
* TIFF is an important image file format for DTP (desktop publishing).
* The advantages of TIFF include its flexibility, availability of libraries to read
* and write TIFF files and its good support in existing software.
* The major disadvantage of TIFF is its complexity, which makes it hard for software
* to support all possible valid TIFF files.
*
*
*
* @author Marco Schmidt
*/
public class TIFFCodec extends ImageCodec implements TIFFConstants
{
public static final int BYTE_ORDER_MOTOROLA = 0;
public static final int BYTE_ORDER_INTEL = 1;
private static final int MAGIC_INTEL = 0x49492a00;
private static final int MAGIC_MOTOROLA = 0x4d4d002a;
private int byteOrder;
private int nextIfdOffset;
private static Hashtable decoders;
static
{
decoders = new Hashtable();
registerDecoder(TIFFDecoderDeflated.class);
registerDecoder(TIFFDecoderModifiedHuffman.class);
registerDecoder(TIFFDecoderPackbits.class);
registerDecoder(TIFFDecoderUncompressed.class);
registerDecoder(TIFFDecoderLogLuv.class);
}
/**
* If the current byte order is {@link BYTE_ORDER_MOTOROLA} and the type
* argument is {@link TiffConstants.TAG_TYPE_BYTE} or
* {@link TiffConstants.TAG_TYPE_SHORT}, the value parameter must
* be adjusted by some bitshifting.
* If the above mentioned criteria are not met, the value argument is
* returned without any modifications.
* ?
*/
public static String getTagName(int id)
{
switch(id)
{
case(TAG_ARTIST): return "Artist";
case(TAG_BAD_FAX_LINES): return "Bad fax lines";
case(TAG_BITS_PER_SAMPLE): return "Bits per sample";
case(TAG_CELL_LENGTH): return "Cell length";
case(TAG_CELL_WIDTH): return "Cell width";
case(TAG_CLEAN_FAX_DATA): return "Clean fax data";
case(TAG_COLOR_MAP): return "Color map";
case(TAG_COMPRESSION): return "Compression";
case(TAG_CONSECUTIVE_BAD_FAX_LINES): return "Consecutive bad fax lines";
case(TAG_COPYRIGHT): return "Copyright";
case(TAG_DATE_TIME): return "Date and time";
case(TAG_DOCUMENT_NAME): return "Document name";
case(TAG_EXTRA_SAMPLES): return "Extra samples";
case(TAG_FILL_ORDER): return "Fill order";
case(TAG_FREE_BYTE_COUNTS): return "Free byte counts";
case(TAG_FREE_OFFSETS): return "Free offsets";
case(TAG_GRAY_RESPONSE_CURVE): return "Gray response curve";
case(TAG_GRAY_RESPONSE_UNIT): return "Gray response unit";
case(TAG_HOST_COMPUTER): return "Host computer";
case(TAG_IMAGE_DESCRIPTION): return "Image description";
case(TAG_IMAGE_LENGTH): return "Image length";
case(TAG_IMAGE_WIDTH): return "Image width";
case(TAG_MAKE): return "Make";
case(TAG_MAX_SAMPLE_VALUE): return "Maximum sample value";
case(TAG_MIN_SAMPLE_VALUE): return "Minimum sample value";
case(TAG_MODEL): return "Model";
case(TAG_NEW_SUBFILE_TYPE): return "New subfile type";
case(TAG_ORIENTATION): return "Orientation";
case(TAG_PHOTOMETRIC_INTERPRETATION): return "Photometric interpretation";
case(TAG_PLANAR_CONFIGURATION): return "Planar configuration";
case(TAG_PREDICTOR): return "Predictor";
case(TAG_RESOLUTION_UNIT): return "Resolution unit";
case(TAG_RESOLUTION_X): return "Resolution X";
case(TAG_RESOLUTION_Y): return "Resolution Y";
case(TAG_ROWS_PER_STRIP): return "Rows per strip";
case(TAG_SAMPLES_PER_PIXEL): return "Samples per pixel";
case(TAG_SOFTWARE): return "Software";
case(TAG_STRIP_BYTE_COUNTS): return "Strip byte counts";
case(TAG_STRIP_OFFSETS): return "Strip offsets";
case(TAG_TILE_BYTE_COUNTS): return "Byte counts";
case(TAG_TILE_HEIGHT): return "Tile height";
case(TAG_TILE_OFFSETS): return "Tile offsets";
case(TAG_TILE_WIDTH): return "Tile width";
default: return "?";
}
}
public boolean isLoadingSupported()
{
return true;
}
public boolean isSavingSupported()
{
return false;
}
/**
* Attempts to load an image from a file in the TIFF format.
* Some options can be given to this codec before the call
* to this load method.
*
*
*
* @return the image if everything was successful
* @throws InvalidFileStructureException if the TIFF file was corrupt in some way
* @throws IOException if there were errors reading from the input file
* @throws UnsupportedTypeException if the flavour of TIFF encountered in the input
* file is not supported yet
* @throws WrongFileFormatException
*/
private void load() throws
InvalidFileStructureException,
IOException,
UnsupportedTypeException,
WrongFileFormatException,
WrongParameterException
{
readHeader();
skipImageFileDirectories(getImageIndex());
TIFFImageFileDirectory ifd = readImageFileDirectory();
ifd.initFromTags(true);
int dpiX = ifd.getDpiX();
int dpiY = ifd.getDpiY();
if (dpiX > 0 && dpiY > 0)
{
setDpi(dpiX, dpiY);
}
//ifd.dump();
load(ifd);
}
private void load(TIFFImageFileDirectory ifd) throws
InvalidFileStructureException,
IOException,
UnsupportedTypeException,
WrongFileFormatException,
WrongParameterException
{
setBoundsIfNecessary(ifd.getWidth(), ifd.getHeight());
checkImageResolution();
int width = getBoundsWidth();
int height = getBoundsHeight();
// create image if necessary
PixelImage image = getImage();
if (image == null)
{
int imageType = ifd.getImageType();
switch (imageType)
{
case(TIFFImageFileDirectory.TYPE_BILEVEL_BYTE):
case(TIFFImageFileDirectory.TYPE_BILEVEL_PACKED):
{
image = new MemoryBilevelImage(width, height);
break;
}
case(TIFFImageFileDirectory.TYPE_GRAY4):
case(TIFFImageFileDirectory.TYPE_GRAY8):
case(TIFFImageFileDirectory.TYPE_LOGL):
{
image = new MemoryGray8Image(width, height);
break;
}
case(TIFFImageFileDirectory.TYPE_GRAY16):
{
image = new MemoryGray16Image(width, height);
break;
}
case(TIFFImageFileDirectory.TYPE_PALETTED4):
case(TIFFImageFileDirectory.TYPE_PALETTED8):
{
image = new MemoryPaletted8Image(width, height, ifd.getPalette());
break;
}
case(TIFFImageFileDirectory.TYPE_CMYK32_INTERLEAVED):
case(TIFFImageFileDirectory.TYPE_CMYK32_PLANAR):
case(TIFFImageFileDirectory.TYPE_RGB24_INTERLEAVED):
case(TIFFImageFileDirectory.TYPE_LOGLUV32_INTERLEAVED):
{
image = new MemoryRGB24Image(width, height);
break;
}
case(TIFFImageFileDirectory.TYPE_RGB48_INTERLEAVED):
{
image = new MemoryRGB48Image(width, height);
break;
}
default:
{
throw new UnsupportedTypeException("Unsupported image type.");
}
}
setImage(image);
}
int tileIndex = 0;
int numTiles = ifd.getNumTiles();
while (tileIndex < numTiles && !getAbort())
{
int x1 = ifd.getTileX1(tileIndex);
int y1 = ifd.getTileY1(tileIndex);
int x2 = ifd.getTileX2(tileIndex);
int y2 = ifd.getTileY2(tileIndex);
if (isTileRequired(x1, y1, x2, y2))
{
TIFFDecoder decoder = createDecoder(this, ifd, tileIndex);
decoder.decode();
}
tileIndex++;
}
}
public void process() throws
MissingParameterException,
OperationFailedException
{
initModeFromIOObjects();
try
{
if (getMode() == CodecMode.LOAD && getRandomAccessFile() != null)
{
load();
}
else
{
throw new MissingParameterException("TIFF codec must have RandomAccessFile object opened for reading.");
}
}
catch (IOException ioe)
{
close();
throw new OperationFailedException("I/O error occurred: " + ioe.toString());
}
}
/**
* Reads the first eight bytes from the input file, checks if this is a
* valid TIFF file and stores byte order and offset of the first image
* file directory.
* @throws IOException if there were reading errors
* @throws WrongFileFormatException if this is not a valid TIFF file
*/
private void readHeader() throws
IOException,
WrongFileFormatException
{
RandomAccessFile in = getRandomAccessFile();
// the argument to in.seek must be changed to a variable in the future for
// this codec to be used to read EXIF information from JPEGs;
// for some reason, TIFF was chosen for that
in.seek(0);
// note: this is the only place where we use in.readInt()
// directly; afterwards, the detected byte order
// is regarded via this class' methods readInt() and readShort()
// methods
int magic = in.readInt();
if (magic == MAGIC_INTEL)
{
setByteOrder(BYTE_ORDER_INTEL);
}
else
if (magic == MAGIC_MOTOROLA)
{
setByteOrder(BYTE_ORDER_MOTOROLA);
}
else
{
throw new WrongFileFormatException("Not a TIFF file (does not " +
"begin with II or MM followed by 42).");
}
nextIfdOffset = readInt();
}
/**
* Reads a complete TIFF image file directory including all data that is
* pointed to using the offset components and returns it.
*
* @return the image file directory data or 0
,
* the second 1
and so on. The default is 0
.null
on failure
*/
private TIFFImageFileDirectory readImageFileDirectory() throws
InvalidFileStructureException,
IOException
{
TIFFImageFileDirectory result = new TIFFImageFileDirectory();
RandomAccessFile in = getRandomAccessFile();
in.seek(nextIfdOffset);
short numTags = readShort();
if (numTags < 0)
{
throw new InvalidFileStructureException("Number of tags in IFD " +
"smaller than 1 @" + nextIfdOffset + ": " + numTags);
}
for (int i = 0; i < numTags; i++)
{
TIFFTag tag = readTag();
if (tag != null)
{
result.append(tag);
}
}
nextIfdOffset = in.readInt();
return result;
}
/**
* Reads a 32 bit signed integer value, regarding the current byte order.
* @return the loaded value
* @see #getByteOrder
*/
private int readInt() throws IOException
{
RandomAccessFile in = getRandomAccessFile();
int result = in.readInt();
if (getByteOrder() == BYTE_ORDER_INTEL)
{
int r1 = (result >> 24) & 0xff;
int r2 = (result >> 16) & 0xff;
int r3 = (result >> 8) & 0xff;
int r4 = result & 0xff;
return r1 | (r2 << 8) | (r3 << 16) | (r4 << 24);
}
else
{
return result;
}
}
/**
* Reads a 16 bit signed integer value, regarding the current byte order.
* @return the loaded value
*/
private short readShort() throws IOException
{
RandomAccessFile in = getRandomAccessFile();
short result = in.readShort();
if (getByteOrder() == BYTE_ORDER_INTEL)
{
int r1 = (result >> 8) & 0xff;
int r2 = result & 0xff;
return (short)((r2 << 8) | r1);
}
else
{
return result;
}
}
/**
* Loads a String of a given length from current position of input file.
* Characters are one-byte ASCII.
* Non-text characters are dropped.
* @param length number of characters in a row to be loaded
* @return loaded String
* @throws IOException if there were reading errors or an unexpected
* end of file
*/
private String readString(int length) throws IOException
{
RandomAccessFile in = getRandomAccessFile();
StringBuffer sb = new StringBuffer(length - 1);
while (length-- > 0)
{
int value = in.read();
if (value >= 32 && value < 256)
{
sb.append((char)value);
}
}
return sb.toString();
}
/**
* Reads a TIFF tag and all data belonging to it and returns a
* TIFFTag object.
* The additional data is somewhere in the TIFF file.
* The current position will be stored, the method will seek to the offset
* position and load the data.
*
* @return TIFFTag containing information on the tag
*/
private TIFFTag readTag() throws
InvalidFileStructureException,
IOException
{
RandomAccessFile in = getRandomAccessFile();
int id = readShort() & 0xffff;
int type = readShort() & 0xffff;
int count = readInt();
int offset = readInt();
if (count < 1)
{
//throw new InvalidFileStructureException("Invalid count value for tag " + id + " (" + count + ").");
return null;
}
Vector vector = null;
// perform weird bitshifting magic if necessary
if (count == 1 &&
(type == TAG_TYPE_BYTE || type == TAG_TYPE_SHORT || type == TAG_TYPE_LONG))
{
offset = adjustInt(offset, type);
}
else
if (count <= 4 && type == TAG_TYPE_BYTE)
{
vector = new Vector();
for (int i = 0; i < count; i++)
{
byte b = (byte)((offset << (i * 8)) & 0xff);
vector.addElement(new Byte(b));
}
}
else
if (count >= 1)
{
long oldOffset = in.getFilePointer();
in.seek(offset);
vector = new Vector();
if (type == TAG_TYPE_ASCII)
{
vector.addElement(readString(count));
}
else
if (type == TAG_TYPE_BYTE)
{
for (int i = 0; i < count; i++)
{
byte b = in.readByte();
vector.addElement(new Byte(b));
}
}
else
if (type == TAG_TYPE_SHORT)
{
for (int i = 0; i < count; i++)
{
int s = readShort();
vector.addElement(new Short((short)s));
}
}
else
if (type == TAG_TYPE_LONG)
{
for (int i = 0; i < count; i++)
{
int v = adjustInt(readInt(), type);
vector.addElement(new Integer(v));
}
}
else
if (type == TAG_TYPE_RATIONAL)
{
for (int i = 0; i < count; i++)
{
int v1 = adjustInt(readInt(), TAG_TYPE_LONG);
int v2 = adjustInt(readInt(), TAG_TYPE_LONG);
vector.addElement(new TIFFRational(v1, v2));
}
}
in.seek(oldOffset);
}
TIFFTag result = new TIFFTag(id, type, count, offset);
result.setVector(vector);
return result;
}
/**
* Register a {@link TIFFDecoder} class.
* TIFF knows many compression types, and JIU only supports some of them.
* To register an external TIFFDecoder class with TIFFCodec, call this method
* with the class field of your decoder.
* As an example, for your TIFFDecoderMyCompression class,
* call TIFFCodec.registerDecoder(TIFFDecoderMyCompression.class)
.
* It will be checked if
* decoderClass.newInstance() instanceof TIFFDecoder
* is true and, if so, the class will be added to an internal list.
* Whenever a TIFF file is to be decoded, the correct decoder is determined
* (each decoder knows about the compression types it supports via the getCompressionTypes method)
* and for each tile or strip such a decoder object will be created.
*/
public static void registerDecoder(Class decoderClass)
{
if (decoderClass == null)
{
return;
}
Object instance;
try
{
instance = decoderClass.newInstance();
}
catch (Exception e)
{
return;
}
if (instance instanceof TIFFDecoder)
{
TIFFDecoder decoder = (TIFFDecoder)instance;
Integer[] compressionTypes = decoder.getCompressionTypes();
if (compressionTypes == null)
{
return;
}
int index = 0;
while (index < compressionTypes.length)
{
Integer type = compressionTypes[index++];
if (type != null)
{
decoders.put(type, decoderClass);
}
}
}
}
/**
* Sets the byte order to the argument.
* The byte order in a TIFF file is either {@link #BYTE_ORDER_INTEL} or
* {@link #BYTE_ORDER_MOTOROLA}.
* @param newByteOrder the new byte order to be set
* @throws IllegalArgumentException if the argument is not one of the above
* mentioned constants
*/
private void setByteOrder(int newByteOrder)
{
if (newByteOrder == BYTE_ORDER_INTEL ||
newByteOrder == BYTE_ORDER_MOTOROLA)
{
byteOrder = newByteOrder;
}
else
{
throw new IllegalArgumentException("Byte order must be either " +
"BYTE_ORDER_INTEL or BYTE_ORDER_MOTOROLA.");
}
}
public void setFile(String fileName, CodecMode codecMode) throws
IOException,
UnsupportedCodecModeException
{
if (codecMode == CodecMode.LOAD)
{
setRandomAccessFile(new RandomAccessFile(fileName, "r"), CodecMode.LOAD);
}
else
{
throw new UnsupportedCodecModeException("This TIFF codec can only load images.");
}
}
/**
* Skips a given number of image file directories in this TIFF files.
* Throws an exception if there were errors or not enough image file
* directories.
* @param numDirectories the number of directories to be skipped,
* should be non-negative
* @throws IllegalArgumentException if argument is negative
* @throws InvalidFileStructureException if there aren't enough image
* file directories
* @throws IOExceptions if there were errors reading or skipping data
*/
private void skipImageFileDirectories(int numDirectories) throws
InvalidFileStructureException,
IOException
{
RandomAccessFile in = getRandomAccessFile();
if (numDirectories < 0)
{
throw new IllegalArgumentException("Cannot skip negative number " +
"of image file directories: " + numDirectories);
}
int skipped = 0;
while (numDirectories-- > 0)
{
in.seek(nextIfdOffset);
short numTags = readShort();
in.skipBytes(numTags * 12);
nextIfdOffset = readInt();
if (nextIfdOffset == 0)
{
throw new InvalidFileStructureException("Could only skip " +
skipped + " image file directories, no more images in file.");
}
skipped++;
}
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/tiff/TIFFTag.java 0000664 0000000 0000000 00000011271 07741250131 024247 0 ustar /*
* TIFFTag
*
* Copyright (c) 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.codecs.tiff;
import java.util.Vector;
import net.sourceforge.jiu.codecs.tiff.TIFFConstants;
/**
* This encapsulates the data stored in a TIFF tag (a single image file directory entry).
* That includes the following items:
*
*
* See the TIFF specification manual linked in the description of {@link TIFFCodec}
* for more details.
*
* @author Marco Schmidt
* @see TIFFImageFileDirectory
*/
public class TIFFTag implements TIFFConstants
{
private int id;
private int type;
private int count;
private int offset;
private Vector objects;
/**
* Creates a new tag with the given ID, type, number of objects / primitives stored in it
* and offset value.
*/
public TIFFTag(int id, int type, int count, int offset)
{
this.id = id;
this.type = type;
this.count = count;
if (count < 1)
{
throw new IllegalArgumentException("Tiff tag count value must " +
"not be smaller than 1: " + count);
}
this.offset = offset;
objects = null;
}
public TIFFTag(int id, int type, int count, int offset, Vector vector)
{
this(id, type, count, offset);
objects = vector;
}
/**
* Returns the number of items stored in this tag.
*/
public int getCount()
{
return count;
}
/**
* Returns an item stored in this tag an int
value.
* @param index zero-based index of the integer item to be returned
*/
public int getElementAsInt(int index)
{
Object element = getObject(index);
if (element == null)
{
throw new IllegalArgumentException("Tag does not contain a list of values.");
}
if (element instanceof Short)
{
return ((Short)element).shortValue() & 0xffff;
}
if (element instanceof Integer)
{
return ((Integer)element).intValue();
}
if (element instanceof Byte)
{
return ((Byte)element).byteValue() & 0xff;
}
throw new IllegalArgumentException("Element #" + index + " is not an integer value.");
}
/**
* Returns the ID of this tag, which may be one of the TAG_xyz constants.
*/
public int getId()
{
return id;
}
/**
* Returns an object from this tag's Vector of items,
* or null
if no such Vector exists.
*/
public Object getObject(int index)
{
if (objects == null)
{
return null;
}
else
{
return objects.elementAt(index);
}
}
/**
* Returns the offset value stored in this tag.
*/
public int getOffset()
{
return offset;
}
/**
* If this tag has a Vector of items and if the first item
* is a String, that String is returned, null
* otherwise.
*/
public String getString()
{
if (objects != null && objects.size() > 0)
{
Object o = objects.elementAt(0);
if (o != null && o instanceof String)
{
return (String)o;
}
}
return null;
}
/**
* Returns the type of this tag's content as a TAG_TYPE_xyz constant.
*/
public int getType()
{
return type;
}
/**
* Returns the Vector encapsulating the items stored in this tag.
* @see #setVector
*/
public Vector getVector()
{
return objects;
}
/**
* Returns if the value(s) stored in this tag are of type BYTE, SHORT or
* LONG.
* Note that BYTE and SHORT have the same meaning as in Java (one and two bytes
* large) while LONG is a 32-bit-value, just like int
in Java.
* @return if this tag's contains integer values <= 32 bits
*/
public boolean isInt()
{
return (type == TAG_TYPE_BYTE || type == TAG_TYPE_SHORT || type == TAG_TYPE_LONG);
}
/**
* If this tag encapsulates more than one item or a single
* item that does not fit into four bytes, this Vector
* will store all elements in it.
* The size() method called on that Vector object returns
* the same value as getCount().
* @param vector the Vector with the items to be encapsulated by this tag
* @see #getVector
*/
public void setVector(Vector vector)
{
objects = vector;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/PalmCodec.java 0000664 0000000 0000000 00000125340 10523755353 023775 0 ustar /*
* PalmCodec
*
* Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.codecs;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.io.RandomAccessFile;
import net.sourceforge.jiu.codecs.ImageCodec;
import net.sourceforge.jiu.codecs.InvalidFileStructureException;
import net.sourceforge.jiu.codecs.UnsupportedTypeException;
import net.sourceforge.jiu.codecs.WrongFileFormatException;
import net.sourceforge.jiu.data.BilevelImage;
import net.sourceforge.jiu.data.ByteChannelImage;
import net.sourceforge.jiu.data.Gray8Image;
import net.sourceforge.jiu.data.MemoryBilevelImage;
import net.sourceforge.jiu.data.MemoryGray8Image;
import net.sourceforge.jiu.data.MemoryPaletted8Image;
import net.sourceforge.jiu.data.MemoryRGB24Image;
import net.sourceforge.jiu.data.PixelImage;
import net.sourceforge.jiu.data.Palette;
import net.sourceforge.jiu.data.Paletted8Image;
import net.sourceforge.jiu.data.RGBIndex;
import net.sourceforge.jiu.data.RGB24Image;
import net.sourceforge.jiu.ops.MissingParameterException;
import net.sourceforge.jiu.ops.OperationFailedException;
import net.sourceforge.jiu.ops.WrongParameterException;
import net.sourceforge.jiu.util.ArrayConverter;
import net.sourceforge.jiu.util.SeekableByteArrayOutputStream;
/**
* A codec to read and write image files in the native image file format of
* Palm OS,
* an operating system for handheld devices.
*
* Supported file types when loading
* This codec reads uncompressed, scan line compressed and RLE compressed Palm files
* with bit depths of 1, 2, 4, 8 and 16 bits per pixel.
* Not supported are the Packbits compression algorithm or any color depths other
* then the aforementioned.
*
* Supported image types when saving
* Compression types Uncompressed, Scan line and RLE are written.
* When saving an image as a Palm, the image data classes will be mapped to file types as follows:
*
*
*
* I/O objects
* This codec supports all the I/O classes that are considered in ImageCodec.
* If you save images and want a correct compressed size field
* in the resulting Palm file, make sure to give a RandomAccessFile object to
* the codec.
* Or simply use {@link #setFile} which does that automatically.
*
* File extension
* This codec suggests .palm
as file extension for this file format.
* This is by no means official, but I find it helpful.
*
* Transparency information
* The transparency index in a Palm file is saved and loaded, but a loaded index
* is not stored in the image object as there is no support for transparency information of
* any kind in PixelImage yet.
* The RGB transparency color that is present in a file only in direct color mode
* is read but not written.
*
* Bounds
* The bounds concept of ImageCodec is supported so that you can load or save
* only part of an image.
*
* Open questions on the Palm file format
*
*
*
* Known problems
*
*
*
* Usage examples
* Load an image from a Palm image file:
*
* PalmCodec codec = new PalmCodec();
* codec.setFile("test.palm", CodecMode.LOAD);
* codec.process();
* PixelImage image = codec.getImage();
* codec.close();
*
* Save an image to a Palm file using RLE compression:
*
* PalmCodec codec = new PalmCodec();
* codec.setImage(image);
* codec.setCompression(PalmCodec.COMPRESSION_RLE);
* codec.setFile("out.palm", CodecMode.SAVE);
* codec.process();
* codec.close();
*
*
* Background
* The code is based on:
*
*
* I also received helpful feedback and test images from Bill Janssen.
*
* @author Marco Schmidt
*/
public class PalmCodec extends ImageCodec
{
/**
* Constant for compression type Uncompressed.
*/
public static final int COMPRESSION_NONE = 255;
/**
* Constant for compression type Packbits.
*/
public static final int COMPRESSION_PACKBITS = 2;
/**
* Constant for compression type RLE (run length encoding).
*/
public static final int COMPRESSION_RLE = 1;
/**
* Constant for compression type Scanline.
*/
public static final int COMPRESSION_SCANLINE = 0;
private static final int FLAG_COMPRESSED = 0x8000;
private static final int FLAG_COLOR_TABLE = 0x4000;
private static final int FLAG_TRANSPARENCY = 0x2000;
//private static final int FLAG_INDIRECT = 0x1000;
//private static final int FLAG_FOR_SCREEN = 0x0800;
private static final int FLAG_DIRECT_COLOR = 0x0400;
//private static final int FLAG_4_BYTE_FIELD = 0x0200;
// following the Palm OS default palettes
// instead of short we could use byte but that would require converting
// all values > 127 to byte representation (-128 .. 128)
private static final short[][] PALM_SYSTEM_PALETTE_4_GRAY = new short[][]
{
{ 255, 255, 255}, { 192, 192, 192}, { 128, 128, 128 }, { 0, 0, 0 }
};
private static final short[][] PALM_SYSTEM_PALETTE_16_COLOR = new short[][]
{
{ 255, 255, 255}, { 128, 128, 128 }, { 128, 0, 0 }, { 128, 128, 0 },
{ 0, 128, 0}, { 0, 128, 128 }, { 0, 0, 128 }, { 128, 0, 128 },
{ 255, 0, 255}, { 192, 192, 192 }, { 255, 0, 0 }, { 255, 255, 0 },
{ 0, 255, 0}, { 0, 255, 255 }, { 0, 0, 255 }, { 0, 0, 0 }
};
private static final short[][] PALM_SYSTEM_PALETTE_16_GRAY = new short[][]
{
{ 255, 255, 255}, { 238, 238, 238 }, { 221, 221, 221 }, { 204, 204, 204 },
{ 187, 187, 187}, { 170, 170, 170 }, { 153, 153, 153 }, { 136, 136, 136 },
{ 119, 119, 119}, { 102, 102, 102 }, { 85, 85, 85 }, { 68, 68, 68 },
{ 51, 51, 51}, { 34, 34, 34 }, { 17, 17, 17 }, { 0, 0, 0 }
};
private static final short[][] PALM_SYSTEM_PALETTE_256 = new short[][]
{
{ 255, 255, 255 }, { 255, 204, 255 }, { 255, 153, 255 }, { 255, 102, 255 },
{ 255, 51, 255 }, { 255, 0, 255 }, { 255, 255, 204 }, { 255, 204, 204 },
{ 255, 153, 204 }, { 255, 102, 204 }, { 255, 51, 204 }, { 255, 0, 204 },
{ 255, 255, 153 }, { 255, 204, 153 }, { 255, 153, 153 }, { 255, 102, 153 },
{ 255, 51, 153 }, { 255, 0, 153 }, { 204, 255, 255 }, { 204, 204, 255 },
{ 204, 153, 255 }, { 204, 102, 255 }, { 204, 51, 255 }, { 204, 0, 255 },
{ 204, 255, 204 }, { 204, 204, 204 }, { 204, 153, 204 }, { 204, 102, 204 },
{ 204, 51, 204 }, { 204, 0, 204 }, { 204, 255, 153 }, { 204, 204, 153 },
{ 204, 153, 153 }, { 204, 102, 153 }, { 204, 51, 153 }, { 204, 0, 153 },
{ 153, 255, 255 }, { 153, 204, 255 }, { 153, 153, 255 }, { 153, 102, 255 },
{ 153, 51, 255 }, { 153, 0, 255 }, { 153, 255, 204 }, { 153, 204, 204 },
{ 153, 153, 204 }, { 153, 102, 204 }, { 153, 51, 204 }, { 153, 0, 204 },
{ 153, 255, 153 }, { 153, 204, 153 }, { 153, 153, 153 }, { 153, 102, 153 },
{ 153, 51, 153 }, { 153, 0, 153 }, { 102, 255, 255 }, { 102, 204, 255 },
{ 102, 153, 255 }, { 102, 102, 255 }, { 102, 51, 255 }, { 102, 0, 255 },
{ 102, 255, 204 }, { 102, 204, 204 }, { 102, 153, 204 }, { 102, 102, 204 },
{ 102, 51, 204 }, { 102, 0, 204 }, { 102, 255, 153 }, { 102, 204, 153 },
{ 102, 153, 153 }, { 102, 102, 153 }, { 102, 51, 153 }, { 102, 0, 153 },
{ 51, 255, 255 }, { 51, 204, 255 }, { 51, 153, 255 }, { 51, 102, 255 },
{ 51, 51, 255 }, { 51, 0, 255 }, { 51, 255, 204 }, { 51, 204, 204 },
{ 51, 153, 204 }, { 51, 102, 204 }, { 51, 51, 204 }, { 51, 0, 204 },
{ 51, 255, 153 }, { 51, 204, 153 }, { 51, 153, 153 }, { 51, 102, 153 },
{ 51, 51, 153 }, { 51, 0, 153 }, { 0, 255, 255 }, { 0, 204, 255 },
{ 0, 153, 255 }, { 0, 102, 255 }, { 0, 51, 255 }, { 0, 0, 255 },
{ 0, 255, 204 }, { 0, 204, 204 }, { 0, 153, 204 }, { 0, 102, 204 },
{ 0, 51, 204 }, { 0, 0, 204 }, { 0, 255, 153 }, { 0, 204, 153 },
{ 0, 153, 153 }, { 0, 102, 153 }, { 0, 51, 153 }, { 0, 0, 153 },
{ 255, 255, 102 }, { 255, 204, 102 }, { 255, 153, 102 }, { 255, 102, 102 },
{ 255, 51, 102 }, { 255, 0, 102 }, { 255, 255, 51 }, { 255, 204, 51 },
{ 255, 153, 51 }, { 255, 102, 51 }, { 255, 51, 51 }, { 255, 0, 51 },
{ 255, 255, 0 }, { 255, 204, 0 }, { 255, 153, 0 }, { 255, 102, 0 },
{ 255, 51, 0 }, { 255, 0, 0 }, { 204, 255, 102 }, { 204, 204, 102 },
{ 204, 153, 102 }, { 204, 102, 102 }, { 204, 51, 102 }, { 204, 0, 102 },
{ 204, 255, 51 }, { 204, 204, 51 }, { 204, 153, 51 }, { 204, 102, 51 },
{ 204, 51, 51 }, { 204, 0, 51 }, { 204, 255, 0 }, { 204, 204, 0 },
{ 204, 153, 0 }, { 204, 102, 0 }, { 204, 51, 0 }, { 204, 0, 0 },
{ 153, 255, 102 }, { 153, 204, 102 }, { 153, 153, 102 }, { 153, 102, 102 },
{ 153, 51, 102 }, { 153, 0, 102 }, { 153, 255, 51 }, { 153, 204, 51 },
{ 153, 153, 51 }, { 153, 102, 51 }, { 153, 51, 51 }, { 153, 0, 51 },
{ 153, 255, 0 }, { 153, 204, 0 }, { 153, 153, 0 }, { 153, 102, 0 },
{ 153, 51, 0 }, { 153, 0, 0 }, { 102, 255, 102 }, { 102, 204, 102 },
{ 102, 153, 102 }, { 102, 102, 102 }, { 102, 51, 102 }, { 102, 0, 102 },
{ 102, 255, 51 }, { 102, 204, 51 }, { 102, 153, 51 }, { 102, 102, 51 },
{ 102, 51, 51 }, { 102, 0, 51 }, { 102, 255, 0 }, { 102, 204, 0 },
{ 102, 153, 0 }, { 102, 102, 0 }, { 102, 51, 0 }, { 102, 0, 0 },
{ 51, 255, 102 }, { 51, 204, 102 }, { 51, 153, 102 }, { 51, 102, 102 },
{ 51, 51, 102 }, { 51, 0, 102 }, { 51, 255, 51 }, { 51, 204, 51 },
{ 51, 153, 51 }, { 51, 102, 51 }, { 51, 51, 51 }, { 51, 0, 51 },
{ 51, 255, 0 }, { 51, 204, 0 }, { 51, 153, 0 }, { 51, 102, 0 },
{ 51, 51, 0 }, { 51, 0, 0 }, { 0, 255, 102 }, { 0, 204, 102 },
{ 0, 153, 102 }, { 0, 102, 102 }, { 0, 51, 102 }, { 0, 0, 102 },
{ 0, 255, 51 }, { 0, 204, 51 }, { 0, 153, 51 }, { 0, 102, 51 },
{ 0, 51, 51 }, { 0, 0 , 51 }, { 0, 255, 0 }, { 0, 204, 0 },
{ 0, 153, 0 }, { 0, 102, 0 }, { 0, 51, 0 }, { 17, 17, 17 },
{ 34, 34, 34 }, { 68, 68, 68 }, { 85, 85, 85 }, { 119, 119, 119 },
{ 136, 136, 136 }, { 170, 170, 170 }, { 187, 187, 187 }, { 221, 221, 221 },
{ 238, 238, 238 }, { 192, 192, 192 }, { 128, 0, 0 }, { 128, 0, 128 },
{ 0, 128, 0 }, { 0, 128, 128 }, { 0, 0, 0 }, { 0, 0, 0 },
{ 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 },
{ 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 },
{ 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 },
{ 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 },
{ 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 },
{ 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }
};
private int bitsPerPixel;
private int blueBits;
private int bytesPerRow;
private int compression;
private long compressedDataOffset;
private int flags;
private int greenBits;
private int height;
private Palette palette;
//private int nextImageOffset;
private int redBits;
private byte[] rgb;
private byte[] transColor;
private int transparencyIndex = -1;
private int version;
private int width;
private static Palette createPalette(short[][] data)
{
Palette result = new Palette(data.length);
for (int i = 0; i < data.length; i++)
{
result.put(i, data[i][0], data[i][1], data[i][2]);
}
return result;
}
/**
* Creates the 2 bits per pixel Palm system palette with grayscale values.
* This palette is used when no custom palette is defined in a 2 bpp image.
* @return Palm's default palette for 2 bits per pixel (grayscale), with 4 entries
*/
public static Palette createSystem2BitGrayscalePalette()
{
return createPalette(PALM_SYSTEM_PALETTE_4_GRAY);
}
/**
* Creates the 4 bits per pixel Palm system palette with color values.
* This palette (or the 4 bpp grayscale palette) is used when no custom palette is defined in a 4 bpp image.
* @return Palm's default palette for 4 bits per pixel (color), with 16 entries
*/
public static Palette createSystem4BitColorPalette()
{
return createPalette(PALM_SYSTEM_PALETTE_16_COLOR);
}
/**
* Creates the 4 bits per pixel Palm system palette with grayscale values.
* This palette (or the 4 bpp color palette) is used when no custom palette is defined in a 4 bpp image.
* @return Palm's default palette for 4 bits per pixel (grayscale), with 16 entries
*/
public static Palette createSystem4BitGrayscalePalette()
{
return createPalette(PALM_SYSTEM_PALETTE_16_GRAY);
}
/**
* Creates the 8 bits per pixel Palm system palette.
* This palette is used when no custom palette is defined in an 8 bpp image.
* @return Palm's default palette for 8 bits per pixel, with 256 entries
*/
public static Palette createSystem8BitPalette()
{
return createPalette(PALM_SYSTEM_PALETTE_256);
}
/**
* Returns the Palm compression method.
* This should be one of the COMPRESSION_xyz constants of this class.
* @return integer value with the compression method (found in a file when
* loading or to be used for saving)
* @see #setCompression
*/
public int getCompression()
{
return compression;
}
public String getFormatName()
{
return "Palm image file format";
}
public String[] getMimeTypes()
{
return null;
}
/**
* Returns the transpareny index if one is available ({@link #hasTransparencyIndex}
* returns pnmtopalm
and
* palmtopnm
that are part of the
* Netpbm package,true
) or an undefined value otherwise.
* @see #hasTransparencyIndex
* @see #removeTransparencyIndex
* @see #setTransparencyIndex
*/
public int getTransparencyIndex()
{
return transparencyIndex;
}
/**
* Returns whether a transpareny index is available and can be
* retrieved via {@link #getTransparencyIndex}.
* @return transparency index, a positive value that is a valid index into the palette
* @see #getTransparencyIndex
* @see #removeTransparencyIndex
* @see #setTransparencyIndex
*/
public boolean hasTransparencyIndex()
{
return transparencyIndex >= 0;
}
private void invertBilevelData(byte[] row)
{
if (row != null)
{
for (int i = 0; i < row.length; i++)
{
row[i] = (byte)~row[i];
}
}
}
private static boolean isEqualPalette(Palette palette, short[][] data)
{
if (palette == null || data == null)
{
return false;
}
if (palette.getNumEntries() != data.length)
{
return false;
}
for (int i = 0; i < data.length; i++)
{
int red = palette.getSample(RGBIndex.INDEX_RED, i);
int green = palette.getSample(RGBIndex.INDEX_GREEN, i);
int blue = palette.getSample(RGBIndex.INDEX_BLUE, i);
short[] color = data[i];
if (color[0] != red || color[1] != green || color[2] != blue)
{
return false;
}
}
return true;
}
public boolean isLoadingSupported()
{
return true;
}
/**
* Returns if the argument palette is the Palm system grayscale palette
* with 4 entries.
* @param palette to be checked
* @see #createSystem2BitGrayscalePalette
*/
public static boolean isPalmSystemPaletteGray4(Palette palette)
{
return isEqualPalette(palette, PALM_SYSTEM_PALETTE_4_GRAY);
}
/**
* Returns if the argument palette is the Palm system grayscale palette
* with 16 entries.
* @param palette to be checked
* @see #createSystem4BitGrayscalePalette
*/
public static boolean isPalmSystemPaletteGray16(Palette palette)
{
return isEqualPalette(palette, PALM_SYSTEM_PALETTE_16_GRAY);
}
/**
* Returns if the argument palette is the Palm system color palette
* with 16 entries.
* @param palette to be checked
* @see #createSystem4BitColorPalette
*/
public static boolean isPalmSystemPaletteColor16(Palette palette)
{
return isEqualPalette(palette, PALM_SYSTEM_PALETTE_16_COLOR);
}
/**
* Returns if the argument palette is the Palm system palette
* with 256 colors.
* @param palette to be checked
* @see #createSystem8BitPalette
* @return if the argument is an 8 bits per pixel Palm system palette
*/
public static boolean isPalmSystemPalette256(Palette palette)
{
return isEqualPalette(palette, PALM_SYSTEM_PALETTE_256);
}
public boolean isSavingSupported()
{
return true;
}
private void load() throws
InvalidFileStructureException,
IOException,
OperationFailedException,
UnsupportedTypeException,
WrongFileFormatException
{
DataInput in = getInputAsDataInput();
loadHeader(in);
loadPalette(in);
loadImage(in);
}
private void loadHeader(DataInput in) throws
InvalidFileStructureException,
IOException,
UnsupportedTypeException,
WrongFileFormatException
{
width = in.readShort() & 0xffff;
height = in.readShort() & 0xffff;
bytesPerRow = in.readShort() & 0xffff;
flags = in.readShort() & 0xffff;
bitsPerPixel = in.readUnsignedByte();
version = in.readUnsignedByte();
//nextImageOffset = in.readShort() & 0xffff;
in.readShort();
transparencyIndex = in.readUnsignedByte() & 0xffff;
compression = in.readUnsignedByte() & 0xffff;
in.skipBytes(2); // reserved
if ((flags & FLAG_COMPRESSED) == 0)
{
compression = COMPRESSION_NONE;
}
boolean unsupportedDirectColor = false;
if ((flags & FLAG_DIRECT_COLOR) != 0)
{
// read direct color information (8 bytes)
redBits = in.readUnsignedByte();
greenBits = in.readUnsignedByte();
blueBits = in.readUnsignedByte();
unsupportedDirectColor = redBits != 5 || greenBits != 6 || blueBits != 5;
in.skipBytes(2);
transColor = new byte[3];
in.readFully(transColor);
}
if (width < 1 || height < 1 ||
unsupportedDirectColor ||
(bitsPerPixel != 1 && bitsPerPixel != 2 && bitsPerPixel != 4 && bitsPerPixel != 8 && bitsPerPixel != 16) ||
(compression != COMPRESSION_NONE && compression != COMPRESSION_RLE && compression != COMPRESSION_SCANLINE))
{
throw new WrongFileFormatException("Not a file in Palm image file format.");
}
/*System.out.println("width=" + width + ", height=" + height + ", bytes per row=" +
bytesPerRow + ", flags=" + flags + ", bpp=" + bitsPerPixel + ", version=" +
version + ", palette=" + (((flags & FLAG_COLOR_TABLE) != 0) ? "y" : "n") +
", transparent=" + transparencyIndex + ", compression=" + compression);*/
}
private void loadImage(DataInput in) throws
InvalidFileStructureException,
IOException,
UnsupportedTypeException,
WrongFileFormatException,
WrongParameterException
{
setBoundsIfNecessary(width, height);
checkBounds(width, height);
PixelImage image = getImage();
/* if there is no image to be reused (image == null), create one;
otherwise check if the provided image is of the right type
and throw an exception if not */
if (palette != null)
{
// paletted image
if (image == null)
{
image = new MemoryPaletted8Image(getBoundsWidth(), getBoundsHeight(), palette);
}
else
{
if (!(image instanceof Paletted8Image))
{
throw new WrongParameterException("Image to be used for loading must be paletted for this file.");
}
((Paletted8Image)image).setPalette(palette);
}
}
else
{
switch(bitsPerPixel)
{
case(1): // bilevel image (black and white)
{
if (image == null)
{
image = new MemoryBilevelImage(getBoundsWidth(), getBoundsHeight());
}
else
{
if (!(image instanceof BilevelImage))
{
throw new WrongParameterException("Image to be used for " +
"loading must implement BilevelImage for this file.");
}
}
break;
}
case(16): // RGB direct color
{
if (image == null)
{
image = new MemoryRGB24Image(getBoundsWidth(), getBoundsHeight());
}
else
{
if (!(image instanceof RGB24Image))
{
throw new WrongParameterException("Image to be used for " +
"loading must implement RGB24Image.");
}
}
rgb = new byte[width * 3];
break;
}
default: // grayscale, 2, 4 or 8 bits per pixel
{
if (image == null)
{
image = new MemoryGray8Image(getBoundsWidth(), getBoundsHeight());
}
else
{
if (!(image instanceof Gray8Image))
{
throw new WrongParameterException("Image to be used for " +
"loading must implement Gray8Image for this file.");
}
}
}
}
}
setImage(image);
// check if image has the correct pixel resolution
if (image.getWidth() != getBoundsWidth() || image.getHeight() != getBoundsHeight())
{
throw new WrongParameterException("Image to be reused has wrong resolution (must have " +
getBoundsWidth() + " x " + getBoundsHeight() + " pixels).");
}
loadImageData(in);
}
private void loadImageData(DataInput in) throws
InvalidFileStructureException,
IOException
{
PixelImage image = getImage();
// if compression is used, read a short with the compressed data size
if (compression != COMPRESSION_NONE)
{
//int compressedDataSize = in.readShort() & 0xffff;
in.readShort();
}
byte[] row = new byte[bytesPerRow];
final int NUM_ROWS = getBoundsY2() + 1;
for (int y = 0; y < NUM_ROWS; y++)
{
switch(compression)
{
case(COMPRESSION_NONE):
{
in.readFully(row, 0, bytesPerRow);
break;
}
case(COMPRESSION_RLE):
{
int index = 0;
do
{
int num = in.readUnsignedByte();
if (num < 1 || index + num > bytesPerRow)
{
String message = "At index=" + index + ", y=" + y + " there is a run length of " + num;
System.err.println("ERROR decoding RLE: " + message);
throw new InvalidFileStructureException(message);
}
byte value = in.readByte();
while (num-- > 0)
{
row[index++] = value;
}
}
while (index < bytesPerRow);
break;
}
case(COMPRESSION_SCANLINE):
{
int index = 0;
int pixelMask = 0;
int mask = 0;
do
{
if (mask == 0)
{
pixelMask = in.readUnsignedByte();
mask = 0x80;
}
if ((pixelMask & mask) == 0)
{
index++;
}
else
{
row[index++] = in.readByte();
}
mask >>= 1;
}
while (index < bytesPerRow);
break;
}
case(COMPRESSION_PACKBITS):
{
// compression algorithm unknown, thus not implemented
// this statement cannot be reached, the codec makes
// sure that an exception gets thrown when the packbits
// algorithm is actually encountered in a file;
// if you have a description of the algorithm, please
// contact the JIU maintainers
break;
}
}
store(image, y, row);
setProgress(y, NUM_ROWS);
}
}
private void loadPalette(DataInput in) throws
InvalidFileStructureException,
IOException,
UnsupportedTypeException,
WrongFileFormatException
{
if ((flags & FLAG_COLOR_TABLE) == 0)
{
switch(bitsPerPixel)
{
case(2):
{
palette = createSystem2BitGrayscalePalette();
break;
}
case(4):
{
palette = createSystem4BitGrayscalePalette(); // or color?
break;
}
case(8):
{
palette = createSystem8BitPalette();
break;
}
}
return;
}
int numEntries = in.readShort() & 0xffff;
if (numEntries < 1 || numEntries > 256)
{
throw new WrongFileFormatException("Not a Palm image file, invalid number of palette entries: " + numEntries);
}
palette = new Palette(numEntries, 255);
for (int i = 0; i < numEntries; i++)
{
//int reserved = in.readUnsignedByte();
in.readUnsignedByte();
int red = in.readUnsignedByte();
int green = in.readUnsignedByte();
int blue = in.readUnsignedByte();
palette.putSample(RGBIndex.INDEX_RED, i, red);
palette.putSample(RGBIndex.INDEX_GREEN, i, green);
palette.putSample(RGBIndex.INDEX_BLUE, i, blue);
}
}
public void process() throws
InvalidFileStructureException,
MissingParameterException,
OperationFailedException,
WrongParameterException
{
try
{
initModeFromIOObjects();
if (getMode() == CodecMode.LOAD)
{
load();
}
else
if (getMode() == CodecMode.SAVE)
{
save();
}
else
{
throw new WrongParameterException("Could find neither objects for loading nor for saving.");
}
}
catch (IOException ioe)
{
throw new OperationFailedException("I/O error in Palm codec: " + ioe.toString());
}
}
/**
* Removes the transparency index if one has been set.
* @see #getTransparencyIndex
* @see #hasTransparencyIndex
* @see #setTransparencyIndex
*/
public void removeTransparencyIndex()
{
transparencyIndex = -1;
}
private void save() throws
IOException,
OperationFailedException,
UnsupportedTypeException
{
// get image, set bounds if necessary and check existing bounds
PixelImage image = getImage();
if (image == null)
{
throw new MissingParameterException("Need image to save.");
}
setBoundsIfNecessary(image.getWidth(), image.getHeight());
checkBounds(image.getWidth(), image.getHeight());
// get output object
DataOutput out = getOutputAsDataOutput();
if (out == null)
{
throw new MissingParameterException("Could not get DataOutput object when saving in Palm file format.");
}
// initialize fields to be written to the header
width = getBoundsWidth();
height = getBoundsHeight();
flags = 0;
if (hasTransparencyIndex())
{
flags |= FLAG_TRANSPARENCY;
}
if (compression != COMPRESSION_NONE)
{
flags |= FLAG_COMPRESSED;
}
version = 0;
if (bitsPerPixel > 1)
{
version = 1;
}
if (hasTransparencyIndex() || compression != COMPRESSION_NONE)
{
version = 2;
}
//nextImageOffset = 0;
compressedDataOffset = 0;
// check image types
if (image instanceof BilevelImage)
{
save(out, (BilevelImage)image);
}
else
if (image instanceof Gray8Image)
{
save(out, (Gray8Image)image);
}
else
if (image instanceof Paletted8Image)
{
save(out, (Paletted8Image)image);
}
else
if (image instanceof RGB24Image)
{
save(out, (RGB24Image)image);
}
else
{
throw new UnsupportedTypeException("Unsupported image type: " + image.getClass().getName());
}
}
private void save(DataOutput out, BilevelImage image) throws IOException
{
bytesPerRow = (width + 7) / 8;
if ((bytesPerRow % 2) == 1)
{
bytesPerRow++;
}
bitsPerPixel = 1;
setCorrectVersion();
saveHeader(out);
byte[] row = new byte[bytesPerRow];
byte[] prev = null;
if (compression == COMPRESSION_SCANLINE)
{
prev = new byte[row.length];
}
final int X1 = getBoundsX1();
final int Y1 = getBoundsY1();
for (int y = 0; y < height; y++)
{
image.getPackedBytes(X1, y + Y1, width, row, 0, 0);
invertBilevelData(row);
saveRow(out, y == 0, row, prev);
if (compression == COMPRESSION_SCANLINE)
{
System.arraycopy(row, 0, prev, 0, row.length);
}
setProgress(y, height);
}
saveFinalCompressedSize(out);
}
private void save(DataOutput out, Gray8Image image) throws IOException
{
bytesPerRow = width;
if ((bytesPerRow % 2) == 1)
{
bytesPerRow++;
}
bitsPerPixel = 8;
flags |= FLAG_COLOR_TABLE;
setCorrectVersion();
saveHeader(out);
out.writeShort(256); // palette length
for (int i = 0; i < 256; i++)
{
out.writeByte(0); // reserved
out.writeByte(i); // red
out.writeByte(i); // green
out.writeByte(i); // blue
}
compressedDataOffset += 2 + 4 * 256;
saveInitialCompressedSize(out);
byte[] row = new byte[width];
byte[] prev = null;
if (compression == COMPRESSION_SCANLINE)
{
prev = new byte[width];
}
final int X1 = getBoundsX1();
final int Y1 = getBoundsY1();
for (int y = 0; y < height; y++)
{
image.getByteSamples(0, X1, y + Y1, width, 1, row, 0);
saveRow(out, y == 0, row, prev);
if (compression == COMPRESSION_SCANLINE)
{
System.arraycopy(row, 0, prev, 0, row.length);
}
setProgress(y, height);
}
saveFinalCompressedSize(out);
}
private void save(DataOutput out, Paletted8Image image) throws IOException
{
Palette palette = image.getPalette();
boolean system256Palette = isPalmSystemPalette256(palette);
boolean system16GrayPalette = isPalmSystemPaletteGray16(palette);
boolean system16ColorPalette = isPalmSystemPaletteColor16(palette);
boolean system4GrayPalette = isPalmSystemPaletteGray4(palette);
boolean customPalette = !(system256Palette || system16GrayPalette || system16ColorPalette || system4GrayPalette);
if (customPalette)
{
flags |= FLAG_COLOR_TABLE;
}
// determine bits per pixel, bytesPerRow
if (palette.getNumEntries() <= 4)
{
bitsPerPixel = 2;
bytesPerRow = (width + 3) / 4;
}
else
if (palette.getNumEntries() <= 16)
{
bitsPerPixel = 4;
bytesPerRow = (width + 1) / 2;
}
else
{
bitsPerPixel = 8;
bytesPerRow = width;
}
//System.out.println("initial bytesPerRow=" + bytesPerRow);
// make sure number of bytes per row is even
if ((bytesPerRow % 2) == 1)
{
bytesPerRow++;
}
setCorrectVersion();
saveHeader(out);
// write the custom palette if necessary
if (customPalette)
{
savePalette(out, palette);
}
// if compression type != uncompressed write two bytes with compressed size to output
saveInitialCompressedSize(out);
// initialize row buffers
byte[] row = new byte[width];
byte[] prev = null;
if (compression == COMPRESSION_SCANLINE)
{
prev = new byte[row.length];
}
byte[] temp = null;
if (bitsPerPixel < 8)
{
temp = new byte[width];
}
// get position of upper left corner of image part to be written
final int X1 = getBoundsX1();
final int Y1 = getBoundsY1();
// write all rows to file, top to bottom
for (int y = 0; y < height; y++)
{
switch(bitsPerPixel)
{
case(2):
{
image.getByteSamples(0, X1, y + Y1, width, 1, temp, 0);
ArrayConverter.encodePacked2Bit(temp, 0, row, 0, width);
break;
}
case(4):
{
image.getByteSamples(0, X1, y + Y1, width, 1, temp, 0);
ArrayConverter.encodePacked4Bit(temp, 0, row, 0, width);
break;
}
case(8):
{
image.getByteSamples(0, X1, y + Y1, width, 1, row, 0);
break;
}
}
saveRow(out, y == 0, row, prev);
if (compression == COMPRESSION_SCANLINE)
{
System.arraycopy(row, 0, prev, 0, row.length);
}
setProgress(y, height);
}
saveFinalCompressedSize(out);
}
private void save(DataOutput out, RGB24Image image) throws IOException
{
bytesPerRow = width * 2;
bitsPerPixel = 16;
flags |= FLAG_DIRECT_COLOR;
setCorrectVersion();
saveHeader(out);
// write 8 bytes for direct color information to file
out.write(5); // red bits
out.write(6); // green bits
out.write(5); // blue bits
int i = 5;
while (i-- > 0)
{
out.write(0);
}
compressedDataOffset += 8;
// allocate row buffer(s)
byte[] row = new byte[width * 2];
byte[] prev = null;
if (compression == COMPRESSION_SCANLINE)
{
prev = new byte[row.length];
}
byte[] red = new byte[width];
byte[] green = new byte[width];
byte[] blue = new byte[width];
final int X1 = getBoundsX1();
final int Y1 = getBoundsY1();
for (int y = 0; y < height; y++)
{
// get samples for each channel of the row to be written out
image.getByteSamples(RGBIndex.INDEX_RED, X1, y + Y1, width, 1, red, 0);
image.getByteSamples(RGBIndex.INDEX_GREEN, X1, y + Y1, width, 1, green, 0);
image.getByteSamples(RGBIndex.INDEX_BLUE, X1, y + Y1, width, 1, blue, 0);
// encode row as 16 bit samples, big endian, 5-6-5
ArrayConverter.encodeRGB24ToPackedRGB565BigEndian(
red, 0,
green, 0,
blue, 0,
row, 0,
width);
saveRow(out, y == 0, row, prev);
if (compression == COMPRESSION_SCANLINE)
{
System.arraycopy(row, 0, prev, 0, row.length);
}
setProgress(y, height);
}
saveFinalCompressedSize(out);
}
private void saveFinalCompressedSize(DataOutput out) throws IOException
{
if ((flags & FLAG_COMPRESSED) == 0)
{
return;
}
if (!(out instanceof RandomAccessFile || out instanceof SeekableByteArrayOutputStream))
{
return;
}
long pos = -1;
if (out instanceof RandomAccessFile)
{
RandomAccessFile raf = (RandomAccessFile)out;
pos = raf.length();
}
else
if (out instanceof SeekableByteArrayOutputStream)
{
SeekableByteArrayOutputStream sbaos = (SeekableByteArrayOutputStream)out;
pos = sbaos.getPosition();
}
long compressedSize = pos - compressedDataOffset;
compressedSize = Math.min(0xffff, compressedSize);
/*
System.out.println("compressed data offset=" + compressedDataOffset);
System.out.println("position after compression=" + pos);
System.out.println("compressed size=" + compressedSize + " / " + Integer.toHexString((int)compressedSize));
*/
if (out instanceof RandomAccessFile)
{
RandomAccessFile raf = (RandomAccessFile)out;
raf.seek(compressedDataOffset);
raf.writeShort((int)compressedSize);
}
else
if (out instanceof SeekableByteArrayOutputStream)
{
SeekableByteArrayOutputStream sbaos = (SeekableByteArrayOutputStream)out;
sbaos.seek((int)compressedDataOffset);
sbaos.write((int)(compressedSize >> 8) & 0xff);
sbaos.write((int)compressedSize & 0xff);
}
}
private void saveHeader(DataOutput out) throws IOException
{
out.writeShort(width);
out.writeShort(height);
out.writeShort(bytesPerRow);
out.writeShort(flags);
out.writeByte(bitsPerPixel);
out.writeByte(version);
out.writeShort(0); // next image offset
out.writeByte(transparencyIndex);
out.writeByte(compression);
out.writeShort(0); // reserved
compressedDataOffset = 16;
}
private void saveInitialCompressedSize(DataOutput out) throws IOException
{
if ((flags & FLAG_COMPRESSED) == 0)
{
return;
}
out.writeShort(bytesPerRow * height); // just a guess
}
private void savePalette(DataOutput out, Palette palette) throws IOException
{
out.writeShort(palette.getNumEntries());
for (int i = 0; i < palette.getNumEntries(); i++)
{
out.writeByte(0); // reserved
out.writeByte(palette.getSample(RGBIndex.INDEX_RED, i));
out.writeByte(palette.getSample(RGBIndex.INDEX_GREEN, i));
out.writeByte(palette.getSample(RGBIndex.INDEX_BLUE, i));
}
compressedDataOffset += 2 + 4 * palette.getNumEntries();
}
private void saveRow(DataOutput out, boolean firstRow, byte[] row, byte[] prev) throws IOException
{
switch(compression)
{
case(COMPRESSION_NONE):
{
out.write(row, 0, bytesPerRow);
break;
}
case(COMPRESSION_RLE):
{
saveRowRLE(out, row);
break;
}
case(COMPRESSION_SCANLINE):
{
saveRowScanLine(out, firstRow, row, prev);
break;
}
}
}
/* int srcOffset = 0; // points into uncompressed data array "row"
do
{
// determine length of next run, between 1 and 255
byte value = row[srcOffset];
int lookAheadOffset = srcOffset + 1;
int bytesLeft = bytesPerRow - lookAheadOffset;
if (bytesLeft > 255)
{
bytesLeft = 255;
}
while (bytesLeft != 0 && value == row[lookAheadOffset])
{
lookAheadOffset++;
bytesLeft--;
}
int runLength = lookAheadOffset - srcOffset;
if (runLength < 1)
{
System.err.println("FATAL: RUN LENGTH <0");
System.exit(1);
}
if (srcOffset + runLength > bytesPerRow)
{
System.err.println("FATAL: srcOffset=" + srcOffset+ " runLength=" + runLength + " bytesPerRow=" + bytesPerRow);
System.exit(1);
}
if (srcOffset == 13 && runLength == 2)
{
System.err.println("FATAL: 13 2 ");
System.exit(1);
}
// write pair (length-of-run, value) to output
out.writeByte(runLength);
out.writeByte(value & 0xff);
// update srcOffset to point to the next byte in row to be encoded
srcOffset += runLength;
}
while (srcOffset < bytesPerRow);*/
private void saveRowRLE(DataOutput out, byte[] row) throws IOException
{
int srcOffset = 0; // points into uncompressed data array "row"
do
{
// determine length of next run, between 1 and 255
int runLength = 1;
int bytesLeft = bytesPerRow - srcOffset;
byte value = row[srcOffset];
while (bytesLeft != 0 && srcOffset + runLength < row.length && value == row[srcOffset + runLength])
{
bytesLeft--;
runLength++;
if (runLength == 255)
{
bytesLeft = 0;
}
}
srcOffset += runLength;
out.writeByte(runLength);
out.writeByte(value & 0xff);
}
while (srcOffset < bytesPerRow);
}
private void saveRowScanLine(DataOutput out, boolean firstRow, byte[] row, byte[] prev) throws IOException
{
int bytesLeft = bytesPerRow;
int srcOffset = 0;
byte[] bytes = new byte[8];
do
{
int pixelMask = 0;
int bitMask = 128;
int numBytesToCheck = Math.min(8, bytesLeft);
int numOutputBytes = 0;
bytesLeft -= numBytesToCheck;
while (numBytesToCheck-- != 0)
{
if (row[srcOffset] != prev[srcOffset])
{
pixelMask |= bitMask;
bytes[numOutputBytes++] = row[srcOffset];
}
srcOffset++;
bitMask >>= 1;
}
out.writeByte(pixelMask);
out.write(bytes, 0, numOutputBytes);
}
while (bytesLeft != 0);
}
/**
* Sets the compression algorithm to be used for saving an image.
* @see #getCompression
* @param newCompressionType int value that is one of the COMPRESSION_xyz constants of this class
* @throws IllegalArgumentException if the compression type is unsupported
*/
public void setCompression(int newCompressionType)
{
if (newCompressionType != COMPRESSION_NONE &&
newCompressionType != COMPRESSION_RLE &&
newCompressionType != COMPRESSION_SCANLINE)
{
throw new IllegalArgumentException("Unsupported Palm compression type for writing.");
}
compression = newCompressionType;
}
private void setCorrectVersion()
{
version = 0;
if (bitsPerPixel > 1)
{
version = 1;
}
if (hasTransparencyIndex() || getCompression() == COMPRESSION_SCANLINE || getCompression() == COMPRESSION_RLE)
{
version = 2;
}
}
/**
* Reuses super.setFile when used for CodecMode.LOAD, but
* creates a RandomAccessFile instead of a FileOutputStream
* in write mode so that the compressed size can be written
* correcly (requires a seek operation).
* @param fileName name of the file to be opened
* @param codecMode defines whether this codec object is to be used for loading or saving
*/
public void setFile(String fileName, CodecMode codecMode) throws
IOException,
UnsupportedCodecModeException
{
if (codecMode == CodecMode.LOAD)
{
super.setFile(fileName, codecMode);
}
else
{
setRandomAccessFile(new RandomAccessFile(fileName, "rw"), CodecMode.SAVE);
}
}
/**
* Sets a new transparency index when saving an image.
* If this method is called, the argument value is used as an index
* into the palette for a color that is supposed to be transparent.
* When the resulting Palm image file is drawn onto some background,
* all pixels in the color pointed to by the transparency index are not
* supposed to be overdrawn so that the background is visisble at
* those places.
* @param newIndex the new transparency index, must be smaller than the number of entries in the palette
* @see #getTransparencyIndex
* @see #hasTransparencyIndex
* @see #removeTransparencyIndex
*/
public void setTransparencyIndex(int newIndex)
{
if (newIndex < 0)
{
throw new IllegalArgumentException("Transparency index must be 0 or larger.");
}
transparencyIndex = newIndex;
}
private void store(PixelImage image, int y, byte[] row)
{
if (!isRowRequired(y))
{
return;
}
y -= getBoundsY1();
switch(bitsPerPixel)
{
case(1):
{
BilevelImage bimage = (BilevelImage)image;
invertBilevelData(row);
bimage.putPackedBytes(0, y, getBoundsWidth(), row, getBoundsX1() / 8, getBoundsX1() % 8);
break;
}
case(2):
{
byte[] dest = new byte[bytesPerRow * 4];
ArrayConverter.decodePacked2Bit(row, 0, dest, 0, bytesPerRow);
ByteChannelImage bcimg = (ByteChannelImage)image;
bcimg.putByteSamples(0, 0, y, getBoundsWidth(), 1, dest, getBoundsX1());
break;
}
case(4):
{
byte[] dest = new byte[bytesPerRow * 2];
ArrayConverter.decodePacked4Bit(row, 0, dest, 0, bytesPerRow);
ByteChannelImage bcimg = (ByteChannelImage)image;
bcimg.putByteSamples(0, 0, y, getBoundsWidth(), 1, dest, getBoundsX1());
break;
}
case(8):
{
ByteChannelImage bcimg = (ByteChannelImage)image;
bcimg.putByteSamples(0, 0, y, getBoundsWidth(), 1, row, getBoundsX1());
break;
}
case(16):
{
ArrayConverter.decodePackedRGB565BigEndianToRGB24(
row, getBoundsX1() * 2,
rgb, 0,
rgb, width,
rgb, width * 2,
getBoundsWidth());
RGB24Image img = (RGB24Image)image;
img.putByteSamples(RGBIndex.INDEX_RED, 0, y, getBoundsWidth(), 1, rgb, 0);
img.putByteSamples(RGBIndex.INDEX_GREEN, 0, y, getBoundsWidth(), 1, rgb, width);
img.putByteSamples(RGBIndex.INDEX_BLUE, 0, y, getBoundsWidth(), 1, rgb, width * 2);
break;
}
}
}
public String suggestFileExtension(PixelImage image)
{
return ".palm";
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/codecs/InvalidFileStructureException.java 0000664 0000000 0000000 00000002432 07741250131 030120 0 ustar /*
* InvalidFileStructureException
*
* Copyright (c) 2000, 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.codecs;
import net.sourceforge.jiu.ops.OperationFailedException;
/**
* This exception is thrown during image loading, when the decoding
* process is made impossible by errors in the image file.
* If a codec has recognized the file format but finds irregularities in the
* data and cannot continue loading, it is supposed to throw an instance of this
* exception class.
* An unexpected end of the input stream also falls into this category.
* This typically means that the file is corrupt, but of course it could
* also be because of an error in the codec implementation.
* .psd
.
* @author Marco Schmidt
*/
public class PSDCodec extends ImageCodec
{
private final static int MAGIC_8BPS = 0x38425053;
private final static int COLOR_MODE_GRAYSCALE = 1;
private final static int COLOR_MODE_INDEXED = 2;
private final static int COLOR_MODE_RGB_TRUECOLOR = 3;
private final static short COMPRESSION_NONE = 0;
private final static short COMPRESSION_PACKBITS = 1;
private int magic;
private int channels;
private int height;
private int width;
private int depth;
private int colorMode;
private short compression;
private DataInput in;
private Gray8Image gray8Image;
private Palette palette;
private Paletted8Image paletted8Image;
private RGB24Image rgb24Image;
private void allocate()
{
gray8Image = null;
paletted8Image = null;
rgb24Image = null;
if (depth == 8 && colorMode == COLOR_MODE_RGB_TRUECOLOR)
{
rgb24Image = new MemoryRGB24Image(getBoundsWidth(), getBoundsHeight());
setImage(rgb24Image);
}
else
if (channels == 1 && depth == 8 && colorMode == 2)
{
paletted8Image = new MemoryPaletted8Image(width, height, palette);
setImage(paletted8Image);
}
else
if (channels == 1 && depth == 8 && colorMode == COLOR_MODE_GRAYSCALE)
{
gray8Image = new MemoryGray8Image(width, height);
setImage(gray8Image);
}
else
{
throw new IllegalArgumentException("Unknown image type in PSD file.");
}
}
private static String getColorTypeName(int colorMode)
{
switch(colorMode)
{
case(0): return "Black & white";
case(1): return "Grayscale";
case(2): return "Indexed";
case(3): return "RGB truecolor";
case(4): return "CMYK truecolor";
case(7): return "Multichannel";
case(8): return "Duotone";
case(9): return "Lab";
default: return "Unknown (" + colorMode + ")";
}
}
public String getFormatName()
{
return "Photoshop (PSD)";
}
public String[] getMimeTypes()
{
return new String[] {"image/psd", "image/x-psd"};
}
public boolean isLoadingSupported()
{
return true;
}
public boolean isSavingSupported()
{
return false;
}
/**
* Attempts to load an Image from argument stream in
(which
* could, as an example, be a RandomAccessFile
instance, it
* implements the DataInput
interface).
* Checks a magic byte sequence and then reads all chunks as they appear
* in the IFF file.
* Will return the resulting image or null if no image body chunk was
* encountered before end-of-stream.
* Will throw an exception if the file is corrupt, information is missing
* or there were reading errors.
*/
private void load() throws
InvalidFileStructureException,
IOException,
UnsupportedTypeException,
WrongFileFormatException
{
loadHeader();
//System.out.println(width + " x " + height + ", color=" + colorMode + ", channels=" + channels + ", depth=" + depth);
// check values
if (width < 1 || height < 1)
{
throw new InvalidFileStructureException("Cannot load image. " +
"Invalid pixel resolution in PSD file header (" + width +
" x " + height + ").");
}
if (colorMode != COLOR_MODE_RGB_TRUECOLOR &&
colorMode != COLOR_MODE_GRAYSCALE &&
colorMode != COLOR_MODE_INDEXED)
{
throw new UnsupportedTypeException("Cannot load image. Only RGB" +
" truecolor and indexed color are supported for PSD files. " +
"Found: " +getColorTypeName(colorMode));
}
if (depth != 8)
{
throw new UnsupportedTypeException("Cannot load image. Only a depth of 8 bits " +
"per channel is supported (found " + depth +
" bits).");
}
// COLOR MODE DATA
int colorModeSize = in.readInt();
//System.out.println("colorModeSize=" + colorModeSize);
byte[] colorMap = null;
if (colorMode == COLOR_MODE_INDEXED)
{
if (colorModeSize != 768)
{
throw new InvalidFileStructureException("Cannot load image." +
" Color map length was expected to be 768 (found " +
colorModeSize + ").");
}
colorMap = new byte[colorModeSize];
in.readFully(colorMap);
palette = new Palette(256, 255);
for (int index = 0; index < 256; index++)
{
palette.putSample(Palette.INDEX_RED, index, colorMap[index] & 0xff);
palette.putSample(Palette.INDEX_GREEN, index, colorMap[256 + index] & 0xff);
palette.putSample(Palette.INDEX_BLUE, index, colorMap[512 + index] & 0xff);
}
}
else
{
in.skipBytes(colorModeSize);
}
// IMAGE RESOURCES
int resourceLength = in.readInt();
in.skipBytes(resourceLength);
//System.out.println("resourceLength=" + resourceLength);
// LAYER AND MASK INFORMATION
int miscLength = in.readInt();
in.skipBytes(miscLength);
//System.out.println("miscLength=" + miscLength);
// IMAGE DATA
compression = in.readShort();
if (compression != COMPRESSION_NONE && compression != COMPRESSION_PACKBITS)
{
throw new UnsupportedTypeException("Cannot load image. Unsupported PSD " +
"compression type (" + compression + ")");
}
//System.out.println("compression=" + compression);
loadImageData();
}
/**
* Reads the PSD header to private members of this class instance.
* @throws IOException if there were reading errors
*/
private void loadHeader() throws
IOException,
WrongFileFormatException
{
magic = in.readInt();
if (magic != MAGIC_8BPS)
{
throw new WrongFileFormatException("Not a valid PSD file " +
"(wrong magic byte sequence).");
}
in.readShort(); // skip version short value
in.skipBytes(6);
channels = in.readShort();
height = in.readInt();
width = in.readInt();
depth = in.readShort();
colorMode = in.readShort();
}
private void loadPackbitsCompressedData(byte[] data, int offset, int num) throws
InvalidFileStructureException,
IOException
{
int x = offset;
int max = offset + num;
while (x < max)
{
byte n = in.readByte();
boolean compressed = false;
int count = -1;
try
{
if (n >= 0)
{
// copy next n + 1 bytes literally
in.readFully(data, x, n + 1);
x += (n + 1);
}
else
{
// if n == -128, nothing happens (stupid design decision)
if (n != -128)
{
compressed = true;
// otherwise, compute counter
count = -((int)n) + 1;
// read another byte
byte value = in.readByte();
// write this byte counter times to output
while (count-- > 0)
{
data[x++] = value;
}
}
}
}
catch (ArrayIndexOutOfBoundsException ioobe)
{
/* if the encoder did anything wrong, the above code
could potentially write beyond array boundaries
(e.g. if runs of data exceed line boundaries);
this would result in an IndexOutOfBoundsException
thrown by the virtual machine;
to give a more understandable error message to the
user, this exception is caught here and a
corresponding IOException is thrown */
throw new InvalidFileStructureException("Error: RLE-compressed image " +
"file seems to be corrupt (x=" + x +
", count=" + (compressed ? (-((int)n) + 1) : n) +
", compressed=" + (compressed ? "y" : "n") + ", array length=" + data.length + ").");
}
}
}
private void loadImageData() throws
InvalidFileStructureException,
IOException
{
setBoundsIfNecessary(width, height);
allocate();
if (compression == COMPRESSION_PACKBITS)
{
// skip counters
in.skipBytes(2 * channels * height);
}
byte[] data = new byte[width];
int totalScanLines = channels * height;
int currentScanLine = 0;
for (int c = 0; c < channels; c++)
{
for (int y = 0, destY = - getBoundsY1(); y < height; y++, destY++)
{
if (compression == COMPRESSION_PACKBITS)
{
loadPackbitsCompressedData(data, 0, width);
}
else
{
if (compression == COMPRESSION_PACKBITS)
{
in.readFully(data, 0, width);
}
}
setProgress(currentScanLine++, totalScanLines);
if (!isRowRequired(y))
{
continue;
}
if (rgb24Image != null)
{
int channelIndex = RGB24Image.INDEX_RED;
if (c == 1)
{
channelIndex = RGB24Image.INDEX_GREEN;
}
if (c == 2)
{
channelIndex = RGB24Image.INDEX_BLUE;
}
rgb24Image.putByteSamples(channelIndex, 0, destY, getBoundsWidth(), 1, data, getBoundsX1());
}
if (gray8Image != null)
{
gray8Image.putByteSamples(0, 0, destY, getBoundsWidth(), 1, data, getBoundsX1());
}
if (paletted8Image != null)
{
paletted8Image.putByteSamples(0, 0, destY, getBoundsWidth(), 1, data, getBoundsX1());
}
}
}
}
public void process() throws
OperationFailedException
{
initModeFromIOObjects();
try
{
if (getMode() == CodecMode.LOAD)
{
in = getInputAsDataInput();
if (in == null)
{
throw new MissingParameterException("Input stream / file missing.");
}
load();
}
else
{
throw new OperationFailedException("Only loading is supported in PSD codec.");
}
}
catch (IOException ioe)
{
throw new OperationFailedException("I/O error: " + ioe.toString());
}
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/ops/ 0000775 0000000 0000000 00000000000 10546532075 020636 5 ustar java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/ops/OperationFailedException.java 0000664 0000000 0000000 00000001244 07741250134 026422 0 ustar /*
* OperationFailedException
*
* Copyright (c) 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.ops;
/**
* Exception class to indicate that an operation failed during
* the execution of the method {@link Operation#process}.
* Note that a failure due to missing or wrong parameters must
* lead to the dedicated exception classes
* {@link WrongParameterException} or {@link MissingParameterException}
* being thrown.
*
* @since 0.7.0
* @author Marco Schmidt
*/
public class OperationFailedException extends Exception
{
public OperationFailedException(String message)
{
super(message);
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/ops/ImageToImageOperation.java 0000664 0000000 0000000 00000016440 07741250134 025653 0 ustar /*
* ImageToImageOperation
*
* Copyright (c) 2001, 2002 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.ops;
import net.sourceforge.jiu.data.PixelImage;
import net.sourceforge.jiu.ops.MissingParameterException;
import net.sourceforge.jiu.ops.Operation;
import net.sourceforge.jiu.ops.WrongParameterException;
/**
* An operation that acesses an input image and produces data for an output image.
* This abstract class only provides methods to get and set those images.
*
*
* null
.
*/
public ImageToImageOperation(PixelImage in)
{
this(in, null);
}
/**
* Creates an object of this class and sets both input image
* and output image to null
.
*/
public ImageToImageOperation()
{
this(null, null);
}
/**
* Returns if input and output image are allowed to be the same object.
* @see #setCanInputAndOutputBeEqual
*/
public boolean canInputAndOutputBeEqual()
{
return canInAndOutBeEqual;
}
/**
* If both an input and an output image have been specified (both non-null),
* this method compares their width and height properties and throws
* an exception if the two images do not have the same resolution.
* @throws WrongParameterException if input and output images exist and their
* resolutions differ
*/
public void ensureImagesHaveSameResolution() throws WrongParameterException
{
PixelImage in = getInputImage();
PixelImage out = getOutputImage();
if (in != null && out != null)
{
if (in.getWidth() != out.getWidth())
{
throw new WrongParameterException("Input and output image must have the same width.");
}
if (in.getHeight() != out.getHeight())
{
throw new WrongParameterException("Input and output image must have the same height.");
}
}
}
/**
* If {@link #getInputImage} returns null
this
* method throws a {@link net.sourceforge.jiu.ops.MissingParameterException}
* complaining that an input image is missing.
* @throws MissingParameterException if no input image is available
*/
public void ensureInputImageIsAvailable() throws MissingParameterException
{
if (getInputImage() == null)
{
throw new MissingParameterException("Input image missing.");
}
}
/**
* If an output image has been specified this method will compare
* its resolution with the argument resolution and throw an exception if the
* resolutions differ.
* If no output image has been specified nothing happens.
* @param width the horizontal pixel resolution that the output image must have
* @param height the vertical pixel resolution that the output image must have
* @throws WrongParameterException if the resolutions differ
*/
public void ensureOutputImageResolution(int width, int height) throws WrongParameterException
{
PixelImage out = getOutputImage();
if (out != null)
{
if (out.getWidth() != width)
{
throw new WrongParameterException("Output image must have width " + width + " (got: " + out.getWidth() + ").");
}
if (out.getHeight() != height)
{
throw new WrongParameterException("Output image must have height " + height + " (got: " + out.getHeight() + ").");
}
}
}
/**
* Returns the input image stored in this object.
* @return input image, possibly null
*/
public PixelImage getInputImage()
{
return inputImage;
}
/**
* Returns the output image stored in this object.
* @return output image, possibly null
*/
public PixelImage getOutputImage()
{
return outputImage;
}
/**
* Specify if input and output image are allowed to be the same object.
* @see #canInputAndOutputBeEqual
*/
public void setCanInputAndOutputBeEqual(boolean newValue)
{
canInAndOutBeEqual = newValue;
}
/**
* Sets the input image stored in this object to the argument.
* Argument can be null
.
* @param in the new input image of this object
*/
public void setInputImage(PixelImage in)
{
inputImage = in;
}
/**
* Sets the output image stored in this object to the argument.
* Argument can be null
.
* @param out the new output image of this object
*/
public void setOutputImage(PixelImage out)
{
outputImage = out;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/ops/LookupTableOperation.java 0000664 0000000 0000000 00000013425 10324334037 025600 0 ustar /*
* LookupTableOperation
*
* Copyright (c) 2001, 2002, 2003, 2004, 2005 Marco Schmidt
* All rights reserved.
*/
package net.sourceforge.jiu.ops;
import net.sourceforge.jiu.data.PixelImage;
import net.sourceforge.jiu.data.IntegerImage;
import net.sourceforge.jiu.ops.ImageToImageOperation;
import net.sourceforge.jiu.ops.MissingParameterException;
import net.sourceforge.jiu.ops.WrongParameterException;
/**
* An operation that replaces samples with values taken from a lookup table.
* Operations where each pixel is treated independently from its neighbors
* and where a pixel value is always mapped to the same new pixel value
* can be implemented this way.
*
* @author Marco Schmidt
* @since 0.6.0
*/
public abstract class LookupTableOperation extends ImageToImageOperation
{
private int[][] intTables;
private int numTables;
/**
* Creates a LookupTableOperation for one lookup table.
*/
public LookupTableOperation()
{
this(1);
}
/**
* Creates an object of this class, calling the super constructor with two null
* arguments and allocates space for the argument number of lookup tables.
* @param numTables number of tables to be used in this operation
*/
public LookupTableOperation(int numTables)
{
super(null, null);
if (numTables < 1)
{
throw new IllegalArgumentException("The number of tables must be at least 1; got " + numTables);
}
intTables = new int[numTables][];
this.numTables = numTables;
}
/**
* Returns the number of tables in this operation.
* @return number of tables
*/
public int getNumTables()
{
return numTables;
}
/**
* Returns one of the internal int
lookup tables.
* @param channelIndex the zero-based index of the table to be returned;
* from 0 to getNumTables() - 1
* @return the channelIndex'th table
*/
public int[] getTable(int channelIndex)
{
return intTables[channelIndex];
}
public void prepareImages() throws
MissingParameterException,
WrongParameterException
{
ensureInputImageIsAvailable();
PixelImage in = getInputImage();
if (!(in instanceof IntegerImage))
{
throw new WrongParameterException("Input image must be of type IntegerImage.");
}
PixelImage out = getOutputImage();
if (out == null)
{
out = in.createCompatibleImage(in.getWidth(), in.getHeight());
setOutputImage(out);
}
else
{
if (in.getNumChannels() != out.getNumChannels())
{
throw new WrongParameterException("Output image must have same number of channels as input image.");
}
ensureImagesHaveSameResolution();
}
}
public void process() throws
MissingParameterException,
WrongParameterException
{
prepareImages();
process((IntegerImage)getInputImage(), (IntegerImage)getOutputImage());
}
private void process(IntegerImage in, IntegerImage out)
{
boolean useFirstTableOnly = getNumTables() < in.getNumChannels();
final int TOTAL_ITEMS = in.getHeight() * in.getNumChannels();
int processedItems = 0;
for (int channelIndex = 0; channelIndex < in.getNumChannels(); channelIndex++)
{
int tableIndex;
if (useFirstTableOnly)
{
tableIndex = 0;
}
else
{
tableIndex = channelIndex;
}
process(in, out, channelIndex, tableIndex, processedItems, TOTAL_ITEMS);
processedItems += in.getHeight();
}
}
private void process(IntegerImage in, IntegerImage out, final int CHANNEL_INDEX,
int tableIndex, int processedItems, final int TOTAL_ITEMS)
{
final int[] TABLE = getTable(tableIndex);
final int WIDTH = in.getWidth();
final int HEIGHT = in.getHeight();
for (int y = 0; y < HEIGHT; y++)
{
for (int x = 0; x < WIDTH; x++)
{
out.putSample(CHANNEL_INDEX, x, y, TABLE[in.getSample(CHANNEL_INDEX, x, y)]);
}
setProgress(processedItems++, TOTAL_ITEMS);
}
}
/**
* Resets the number of tables to be used in this operation to the
* argument and drops all actual table data initialized so far.
* After a call to this method, {@link #getTable} will return
* null
as long as no new table data is provided
* via {@link #setTable} or {@link #setTables}.
* @param numberOfTables the new number of tables for this operation, must be 1
or larger
* @throws IllegalArgumentException if the number is zero or smaller
*/
public void setNumTables(int numberOfTables)
{
if (numberOfTables < 1)
{
throw new IllegalArgumentException("Number of tables argument must be larger than zero.");
}
numTables = numberOfTables;
intTables = new int[numTables][];
}
/**
* Provides a new lookup table for one of the channels.
* @param channelIndex the index of the channel for which a table is provided; must be at least 0
and smaller than {@link #getNumTables}
* @param tableData the actual table to be used for lookup
* @throws IllegalArgumentException if the channel index is not in the valid interval (see above)
*/
public void setTable(int channelIndex, int[] tableData)
{
if (channelIndex < 0)
{
throw new IllegalArgumentException("The channelIndex argument must be at least 0; got " + channelIndex);
}
if (channelIndex >= getNumTables())
{
throw new IllegalArgumentException("The channelIndex argument must be smaller than the number of tables " +
getNumTables() + "; got " + channelIndex);
}
intTables[channelIndex] = tableData;
}
/**
* Sets the tables for all channels to the argument table.
* Useful when the same table can be used for all channels.
* @param tableData the data that will be used as lookup table for all channels
*/
public void setTables(int[] tableData)
{
for (int i = 0; i < getNumTables(); i++)
{
setTable(i, tableData);
}
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/ops/ProgressListener.java 0000664 0000000 0000000 00000003267 07741250134 025017 0 ustar /*
* ProgressListener
*
* Copyright (c) 2000, 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.ops;
/**
* This interface must be implemented by classes that want to be notified
* about progress of an image operation.
*
* @author Marco Schmidt
*/
public interface ProgressListener
{
/**
* Set the progress level to a new value, which must be between 0.0f and 1.0f
* (including both of these values).
* You should not call this method with a value lower than any value you've set
* before.
* However, this is not checked.
* @param progress the degree of progress as a value between 0.0f and 1.0f
* @throws IllegalArgumentException if the float argument is not in the mentioned interval
*/
void setProgress(float progress);
/**
* Sets a new progress level.
* If an operation consists of totalItems steps, which are numbered from 0 to
* totalItems - 1, this method can be called after the completion of each step.
* (float)(zeroBasedIndex + 1) / (float)totalItems
and calls
* {@link #setProgress(float)} with that value.
*
* @param zeroBasedIndex the index of the step that was just completed
* @param totalItems the number of steps in this operation
* @throws IllegalArgumentException if the parameters don't match the above criteria
*/
void setProgress(int zeroBasedIndex, int totalItems);
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/ops/ImagesToImageOperation.java 0000664 0000000 0000000 00000010555 07741250134 026037 0 ustar /*
* ImagesToImageOperation
*
* Copyright (c) 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.ops;
import java.util.Vector;
import net.sourceforge.jiu.data.PixelImage;
import net.sourceforge.jiu.ops.Operation;
import net.sourceforge.jiu.ops.WrongParameterException;
/**
* An operation that takes several input images and produces one output image.
*
* @author Marco Schmidt
* @since 0.11.0
*/
public abstract class ImagesToImageOperation extends Operation
{
private Vector inputImages = new Vector();
private PixelImage outputImage;
/**
* Constructs a new ImagesToImageOperation and initializes
* input images and output image to null.
*/
public ImagesToImageOperation()
{
this(null, null);
}
/**
* Constructs a new ImagesToImageOperation and initializes
* input images and output image to the arguments.
*/
public ImagesToImageOperation(Vector in, PixelImage out)
{
if (in != null)
{
for (int i = 0; i < in.size(); i++)
{
addInputImage((PixelImage)in.elementAt(i));
}
}
setOutputImage(out);
}
/**
* Adds an image to the end of the internal list of
* input images.
*/
public void addInputImage(PixelImage in)
{
inputImages.addElement(in);
}
/**
* Checks if all images have the same resolution as given by their
* getWidth and getHeight methods.
* This method will not complain if input and / or output images are not
* available.
* @throws WrongParameterException if input and output images exist and their
* resolutions differ
*/
public void ensureImagesHaveSameResolution() throws WrongParameterException
{
if (inputImages == null || inputImages.size() < 1)
{
return;
}
PixelImage in = getInputImage(0);
int width = in.getWidth();
int height = in.getHeight();
int index = 1;
while (index < inputImages.size())
{
in = getInputImage(index);
if (in.getWidth() != width)
{
throw new WrongParameterException("Width of images #0 and #" + index + " are not equal.");
}
if (in.getHeight() != height)
{
throw new WrongParameterException("Height of images #0 and #" + index + " are not equal.");
}
index++;
}
PixelImage out = getOutputImage();
if (out != null)
{
if (out.getWidth() != width)
{
throw new WrongParameterException("Width of input images #0 and output image are not equal.");
}
if (out.getHeight() != height)
{
throw new WrongParameterException("Height of input images #0 and output image are not equal.");
}
}
}
/**
* If an output image has been specified this method will compare
* its resolution with the argument resolution and throw an exception if the
* resolutions differ.
* If no output image has been specified nothing happens.
* @param width the horizontal pixel resolution that the output image must have
* @param height the vertical pixel resolution that the output image must have
* @throws WrongParameterException if the resolutions differ
*/
public void ensureOutputImageResolution(int width, int height) throws WrongParameterException
{
PixelImage out = getOutputImage();
if (out != null)
{
if (out.getWidth() != width)
{
throw new WrongParameterException("Output image must have width " + width + " (got: " + out.getWidth() + ").");
}
if (out.getHeight() != height)
{
throw new WrongParameterException("Output image must have height " + height + " (got: " + out.getHeight() + ").");
}
}
}
/**
* Returns the input image stored in this object.
* @return input image, possibly null
*/
public PixelImage getInputImage(int index)
{
return (PixelImage)inputImages.elementAt(index);
}
/**
* Return the number of input images currently stored in this operation.
* @return number of images
*/
public int getNumInputImages()
{
return inputImages.size();
}
/**
* Returns the output image stored in this object.
* @return output image, possibly null
*/
public PixelImage getOutputImage()
{
return outputImage;
}
/**
* Sets the output image stored in this object to the argument.
* Argument can be null
.
* @param out the new output image of this object
*/
public void setOutputImage(PixelImage out)
{
outputImage = out;
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/ops/MissingParameterException.java 0000664 0000000 0000000 00000001120 10324334065 026615 0 ustar /*
* MissingParameterException
*
* Copyright (c) 2001, 2002, 2003, 2004, 2005 Marco Schmidt
* All rights reserved.
*/
package net.sourceforge.jiu.ops;
import net.sourceforge.jiu.ops.OperationFailedException;
/**
* Exception class to indicate that an operation's parameter is missing
* (has not been specified by caller and there was no default value that
* could be used).
*
* @author Marco Schmidt
*/
public class MissingParameterException extends OperationFailedException
{
public MissingParameterException(String message)
{
super(message);
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/ops/package.html 0000664 0000000 0000000 00000000601 07741250134 023110 0 ustar
true
,
* the operation should terminate and return control to the caller.
* The abort state can be modified using {@link #setAbort(boolean)}.
* true
, a running operation should terminate what it is doing
* (return from {@link #process()}).
* @return abort status
* @see #setAbort
*/
public boolean getAbort()
{
return abort;
}
/**
* This method does the actual work of the operation.
* It must be called after all parameters have been given to the operation object.
* @throws WrongParameterException if at least one of the input parameters was
* not initialized appropriately (values out of the valid interval, etc.)
* @throws MissingParameterException if any mandatory parameter was not given to the operation
* @throws OperationFailedException
*/
public void process() throws
MissingParameterException,
OperationFailedException,
WrongParameterException
{
}
/**
* Removes the argument progress listener from the internal list of
* progress listeners.
* @param progressListener the progress listener to be removed
*/
public void removeProgressListener(ProgressListener progressListener)
{
progressListeners.removeElement(progressListener);
}
/**
* Sets a new abort status.
* @param newAbortStatus the new status
* @see #getAbort
*/
public void setAbort(boolean newAbortStatus)
{
abort = newAbortStatus;
}
/**
* This method will notify all registered progress listeners
* about a new progress level.
* The argument must be from 0.0f to 1.0f where 0.0f marks the
* beginning and 1.0f completion.
* The progress value should not be smaller than any value that
* was previously set.
* @param progress new progress value, from 0.0 to 1.0
*/
public void setProgress(float progress)
{
if (progress < 0.0f || progress > 1.0f)
{
throw new IllegalArgumentException("Progress values must be from" +
" 0.0f to 1.0f; got " + progress);
}
int index = 0;
while (index < progressListeners.size())
{
ProgressListener pl =
(ProgressListener)progressListeners.elementAt(index++);
if (pl != null)
{
pl.setProgress(progress);
}
}
}
/**
* This method will notify all registered progress listeners
* about a new progress level.
* Simply checks the arguments and calls setProgress((float)zeroBasedIndex / (float)totalItems);
.
* @param zeroBasedIndex the index of the item that was just processed, zero-based
* @param totalItems the number of items that will be processed
*/
public void setProgress(int zeroBasedIndex, int totalItems)
{
if (zeroBasedIndex < 0 || zeroBasedIndex >= totalItems ||
totalItems < 1)
{
throw new IllegalArgumentException("No valid arguments " +
" zeroBasedIndex=" + zeroBasedIndex + ", totalItems=" +
totalItems);
}
setProgress((float)zeroBasedIndex / (float)totalItems);
}
}
java-imaging-utilities-0.14.2+3.orig/net/sourceforge/jiu/ops/BatchProcessorOperation.java 0000664 0000000 0000000 00000015051 07741250134 026301 0 ustar /*
* BatchProcessorOperation
*
* Copyright (c) 2003 Marco Schmidt.
* All rights reserved.
*/
package net.sourceforge.jiu.ops;
import java.io.File;
import java.util.Vector;
/**
* Small data class for names of directories that are to be
* processed.
* @author Marco Schmidt
*/
class DirectoryTree
{
/**
* Input directory name, as found in the file system.
*/
String input;
/**
* Corresponding output directory name, may not yet be in the file system.
*/
String output;
}
/**
* Abstract base class to do batch processing on files and complete directory trees.
* For a non-abstract extension of this operation, you must implement {@link #processFile}.
* @author Marco Schmidt
* @since 0.11.0
*/
public abstract class BatchProcessorOperation extends Operation
{
private boolean collectErrors;
private Vector directoryTrees = new Vector();
private Vector errorMessages = new Vector();
private Vector inputFileNames = new Vector();
private String outputDirectory;
private boolean overwrite;
/**
* Adds the argument to the list of directories to be completely
* processed.
* @param rootDirectoryName name of the root of the directory tree, can be any valid directory name
*/
public void addDirectoryTree(String rootDirectoryName)
{
addDirectoryTree(rootDirectoryName, null);
}
/**
* Adds the first argument to the list of directories to be completely
* processed, writes all output files to the directory tree specified by
* the second argument.
* @param rootDirectoryName name of the root of the directory tree, can be any valid directory name
* @param outputRootDirectoryName name of the root of the directory tree, can be any valid directory name
*/
public void addDirectoryTree(String rootDirectoryName, String outputRootDirectoryName)
{
DirectoryTree tree = new DirectoryTree();
tree.input = rootDirectoryName;
tree.output = outputRootDirectoryName;
directoryTrees.addElement(tree);
}
/**
* Adds a single name to the list of file names to be processed.
* @param fileName name to be added to list
*/
public void addInputFileName(String fileName)
{
inputFileNames.addElement(fileName);
}
/**
* Adds a number of file names to the internal list of file names to be processed.
* @param fileNameList list of file names, each object in the list must be a String
*/
public void addInputFileNames(Vector fileNameList)
{
int index = 0;
while (index < fileNameList.size())
{
String fileName = (String)fileNameList.elementAt(index++);
inputFileNames.addElement(fileName);
}
}
/**
* Returns a list of error messages collected during the execution of {@link #process}.
* @return list of error messages, each object is a String
*/
public Vector getErrorMessages()
{
return errorMessages;
}
/**
* Returns the current overwrite setting.
* @return whether existing files are to be overwritten
*/
public boolean getOverwrite()
{
return overwrite;
}
/**
* Processes all directory trees and files given to this operation,
* calling {@link #processFile} on each file name.
*/
public void process()
{
// process directory trees
int index = 0;
while (index < directoryTrees.size())
{
DirectoryTree tree = (DirectoryTree)directoryTrees.elementAt(index++);
String output = tree.output;
if (output == null)
{
output = outputDirectory;
}
processDirectoryTree(tree.input, output);
}
// process single files
index = 0;
while (index < inputFileNames.size())
{
String fileName = (String)inputFileNames.elementAt(index++);
File file = new File(fileName);
if (!file.isFile())
{
if (collectErrors)
{
errorMessages.addElement("Cannot process \"" + fileName + "\" (not a file).");
}
}
String inDir = file.getParent();
String outDir = outputDirectory;
if (outDir == null)
{
outDir = inDir;
}
processFile(inDir, file.getName(), outDir);
}
}
private void processDirectoryTree(String fromDir, String toDir)
{
File fromDirFile = new File(fromDir);
String[] entries = fromDirFile.list();
for (int i = 0; i < entries.length; i++)
{
String name = entries[i];
File entry = new File(fromDir, name);
if (entry.isFile())
{
processFile(fromDir, name, toDir);
}
else
if (entry.isDirectory())
{
File inSubDir = new File(fromDir, name);
File outSubDir = new File(toDir, name);
if (outSubDir.exists())
{
if (outSubDir.isFile())
{
if (collectErrors)
{
errorMessages.addElement("Cannot create output directory \"" +
outSubDir.getAbsolutePath() + "\" because a file of that name already exists.");
}
continue;
}
}
else
{
if (!outSubDir.mkdir())
{
if (collectErrors)
{
errorMessages.addElement("Could not create output directory \"" +
outSubDir.getAbsolutePath() + "\".");
}
continue;
}
}
processDirectoryTree(inSubDir.getAbsolutePath(), outSubDir.getAbsolutePath());
}
}
}
/**
* Method to be called on each file given to this operation.
* Non-abstract heirs of this class must implement this method to add functionality.
* @param inputDirectory name of directory where the file to be processed resides
* @param inputFileName name of file to be processed
* @param outputDirectory output directory for that file, need not necessarily be used
*/
public abstract void processFile(String inputDirectory, String inputFileName, String outputDirectory);
/**
* Specifies whether error messages are supposed to be collected
* during the execution of {@link #process}.
* @param collectErrorMessages if true, error messages will be collected, otherwise not
* @see #getErrorMessages
*/
public void setCollectErrorMessages(boolean collectErrorMessages)
{
collectErrors = collectErrorMessages;
}
/**
* Specifies the output directory for all single files.
* Note that you can specify different output directories when dealing
* with directory trees.
* @param outputDirectoryName name of output directory
*/
public void setOutputDirectory(String outputDirectoryName)
{
outputDirectory = outputDirectoryName;
}
/**
* Specify whether existing files are to be overwritten.
* @param newValue if true, files are overwritten, otherwise not
* @see #getOverwrite
*/
public void setOverwrite(boolean newValue)
{
overwrite = newValue;
}
}
java-imaging-utilities-0.14.2+3.orig/packages 0000664 0000000 0000000 00000001215 10104724764 015633 0 ustar net.sourceforge.jiu.apps
net.sourceforge.jiu.codecs
net.sourceforge.jiu.codecs.jpeg
net.sourceforge.jiu.codecs.tiff
net.sourceforge.jiu.color
net.sourceforge.jiu.color.data
net.sourceforge.jiu.color.adjustment
net.sourceforge.jiu.color.analysis
net.sourceforge.jiu.color.conversion
net.sourceforge.jiu.color.dithering
net.sourceforge.jiu.color.io
net.sourceforge.jiu.color.promotion
net.sourceforge.jiu.color.quantization
net.sourceforge.jiu.color.reduction
net.sourceforge.jiu.data
net.sourceforge.jiu.filters
net.sourceforge.jiu.geometry
net.sourceforge.jiu.gui.awt
net.sourceforge.jiu.gui.awt.dialogs
net.sourceforge.jiu.ops
net.sourceforge.jiu.util
java-imaging-utilities-0.14.2+3.orig/resources/ 0000775 0000000 0000000 00000000000 10546531771 016151 5 ustar java-imaging-utilities-0.14.2+3.orig/resources/lang/ 0000775 0000000 0000000 00000000000 10546531776 017077 5 ustar java-imaging-utilities-0.14.2+3.orig/resources/lang/en.txt 0000664 0000000 0000000 00000011372 10404064673 020234 0 ustar Error loading image
The format of the file is unknown.
Load image file
Screen resolution
Could not create histogram.
Number of used colors
Count colors used...
Close
Help
About...
System
System information...
Color
Invert
Convert to grayscale
File
Open...
Save as
Exit
Java Runtime Environment version
Java Runtime Environment vendor
Java vendor URL
Java installation directory
Java Virtual Machine specification version
Java Virtual Machine specification vendor
Java Virtual Machine specification name
Java Virtual Machine implementation version
Java Virtual Machine implementation vendor
Java Virtual Machine implementation name
Java Runtime Environment specification version
Java Runtime Environment specification vendor
Java Runtime Environment specification name
Java class format version number
Java class path
Operating system name
Operating system architecture
Operating system version
Homepage
Feedback
Median Cut...
Error message
The number of colors in the image is already small enough.
CPU endianness
CPU isalist
Free memory
Used memory
Total memory
Save as
Geometry
Flip
Mirror
Median Cut + contour removal
Promote to RGB
Reduce to bilevel (threshold)...
Reduce to bilevel (Bayer dithering)...
Rotate left (90)
Rotate right (90)
Rotate (180)
Rotate (other)...
Scale...
Scale image
New width
New height
Maintain aspect ratio
OK
Cancel
Number of colors
Median Cut color quantization
Output color type
Average
Weighted average
Median
Paletted
RGB truecolor
Representative color method
Contour removal
Method
Filters
Sharpen
Blur
Emboss
Psychedelic Distillation
Lithograph
Save as
Portable Bitmap (PBM)...
Portable Graymap (PGM)...
Portable Pixmap (PPM)...
Uniform palette...
Number of bits, red
Number of bits, green
Number of bits, blue
Ordered dithering
None
Dithering method
Uniform palette color quantization
Save image as...
Error - too many bits.
Total number of bits, colors
Edge detection
Reduce number of shades of gray
Reduce number of shades of gray...
Number of bits
Number of shades of gray
Sun Raster (RAS)...
Adjust
Contrast...
Brightness...
Gamma...
Adjust contrast
Please enter the change of contrast as a percentage value (-100 to 100):
Adjust brightness
Please enter the change of brightness as a percentage value (-100 to 100):
Adjust gamma
Please enter the gamma value (0.0 to 10.0):
Crop image
Left column
Top row
Right column
Bottom row
Crop...
Convert to minimum color type
Histogram
Reduce to bilevel using a threshold value
Please enter the threshold value:
Floyd-Steinberg error diffusion
Stucki error diffusion
Burkes error diffusion
Sierra error diffusion
Jarvice, Judice and Ninke error diffusion
Stevenson-Arce error diffusion
Output quality improvement algorithm
None
Error diffusion
Color image quantization
Horizontal Sobel
Vertical Sobel
Horizontal Prewitt
Vertical Prewitt
Shear...
Shear image
Please enter the angle (> -90.0, < 90.0):
Hue, saturation, value...
Adjust hue, saturation and value
Set hue
Hue (0..359)
Saturation (-100..100)
Value (-100..100)
Mean...
Median...
Oil...
Apply mean filter
Apply median filter
Apply oil filter
Window width (odd number >= 1)
Window height (odd number >= 1)
Please enter the window size!
Contour removal; number of passes
Contour removal; tau distance
Palette
Save as...
Map to arbitrary palette...
Save palette
Load palette
Choose dithering method
Websafe palette
Palette from file
Please choose the palette type!
Map to arbitrary palette
Equalize
Normalize
Octree...
Octree color image quantization
Save co-occurrence matrix
Save co-occurrence matrix as...
Save co-occurrence frequency matrix
Save co-occurrence frequency matrix as...
Windows Bitmap (BMP)...
Promote
Promote to paletted
Promote to grayscale (8 bits)
Promote to grayscale (16 bits)
Promote to RGB (24 bits)
Promote to RGB (48 bits)
Reduce
Save histogram as...
Save histogram
Edit
Undo
Redo
Texture properties...
Contrast
Energy
Entropy
Homogeneity
Texture properties
Correlation
Dissimilarity
Minimum...
Maximum...
Apply minimum filter
Apply maximum filter
View
Zoom in
Zoom out
Set original size
Interpolation type
Nearest neighbor (fast)
Bilinear (slower)
Bicubic (slowest)
Palm...
Palm OS system palette (256 colors)
Palm OS system palette (16 colors)
Palm OS system palette (16 shades of gray)
Palm OS system palette (4 shades of gray)
The image was changed. Do you want to quit without saving?
Exit program
Yes
No
Do you really want to close without saving?
Close file
Bits per pixel
bilevel
grayscale
RGB truecolor
unknown
Image type
paletted
Pixels
Portable Network Graphics (PNG)...
Memory
Disk space
Graphics Interchange Format (GIF)...
image1.jpg
java-imaging-utilities-0.14.2+3.orig/resources/lang/fr.txt 0000664 0000000 0000000 00000013400 10404065631 020226 0 ustar Erreur lors du chargement de l'image
Le format de ce fichier est inconnu.
Chargement de l'image
Résolution de l'écran
Impossible de créer l'histogramme.
Nombre de couleurs utilisées
Comptage des couleurs utilisées...
Fermer
Aide
A propos...
Système
Information système...
Couleur
Inversion de couleurs
Convertir en niveaux de gris
Fichier
Ouvrir...
Enregistrer sous...
Quitter
Version du JRE (Java Runtime Environment)
Fournisseur du JRE
URL du fournisseur de Java
Répertoire d'installation de Java
Version des spécifications de la JVM (machine virtuelle Java)
Fournisseur des spécifications de la JVM
Nom des spécifications de la JVM
Version de l'implémentation de la JVM
Fournisseur de l'implémentation de la JVM
Nom de l'implémentation de la JVM
Version des spécifications du JRE
Fournisseur des spécifications du JRE
Nom des spécifications du JRE
Numéro de version du format des classes Java
Class path Java
Système d'exploitation
Architecture du système d'exploitation
Version du système d'exploitation
Page d'accueil
Retour d'expérience
Median Cut...
Message d'erreur
Le nombre de couleurs dans l'image est déjà au minimum.
CPU endianness (boutisme)
CPU isalist (jeux d'instructions)
Mémoire libre
Mémoire utilisée
Mémoire totale
Enregistrer sous...
Géométrie
Renverser
Miroir
Median Cut + suppression du contour
Convertir en RGB
Reduire en monochrome (Seuil)...
Reduire en monochrome (Diffusion Bayer)...
Rotation à gauche (90°)
Rotation à droite (90°)
Rotation (180°)
Rotation (personnalisée)...
Echelle...
Redimensionner l'image
Nouvelle largeur
Nouvelle hauteur
Garder le ratio hauteur/largeur
OK
Annuler
Nombre de couleurs
Quantification de la couleur (Algorithme Median Cut)
Type de couleur de sortie
Moyenne
Moyenne pondérée
Médiane
Palette de couleurs
RGB vraies couleurs
Méthode pour la couleur représentative
Suppression du contour
Méthode
Filtres
Accentuer
Flou
Relief
Distillation psychédélique
Lithograph
Enregistrer sous...
Portable Bitmap (PBM)...
Portable Graymap (PGM)...
Portable Pixmap (PPM)...
Palette uniforme...
Nombre de bits, rouge
Nombre de bits, vert
Nombre de bits, bleu
Diffusion ordonnée
Aucun
Méthode de diffusion
Quantification de la couleur de la palette uniforme
Enregistrer l'image sous...
Erreur - Trop de bits.
Nombre total de bits, couleurs
Détection des bordures
Réduire le nombre de niveaux de gris
Réduire le nombre de niveaux de gris
Nombre de bits
Nombre de niveaux de gris
Sun Raster (RAS)...
Ajuster
Contraste...
Luminosité...
Gamma...
Ajuster le contraste
Veuillez saisir le pourcentage de changement de constraste (-100 à 100):
Ajuster la luminosité
Veuillez saisir le pourcentage de changement de luminosité (-100 à 100):
Ajuster le gamma
Veuillez saisir la valeur du gamma (0.0 à 10.0):
Découper l'image
Colonne de gauche
Ligne du haut
Colonne de droite
Ligne du bas
Découper...
Convertir en monochrome
Histogramme
Réduire en monochrome en utilisant une valeur seuil
Veuillez entrer la valeur seuil:
Floyd-Steinberg error diffusion
Stucki error diffusion
Burkes error diffusion
Sierra error diffusion
Jarvice, Judice and Ninke error diffusion
Stevenson-Arce error diffusion
Algorithme d'amélioration de la qualité de sortie
Aucun
Error diffusion
Quantification de la couleur de l'image
Sobel (horizontal)
Sobel (vertical)
Prewitt (horizontal)
Prewitt (vertical)
Cisailler...
Cisailler l'image
Veuillez entrer l'angle (> -90.0, < 90.0):
Tonalité, saturation, luminosité...
Ajuster la tonalité, la saturation et la luminosité
Fixer la tonalité
Tonalité (0 à 359)
Saturation (-100 à 100)
Luminosité (-100 à 100)
Moyenne...
Médiane...
Huile...
Appliquer le filtre moyen
Appliquer le filtre médiane
Appliquer le filtre huile
Largeur de la fenêtre (Nombre impair >= 1)
Hauteur de la fenêtre (Nombre impair >= 1)
Veuillez entrer la taille de la fenêtre!
Suppression du contour; nombre de passes
Suppression du contour; distance tau
Palette
Enregistrer sous...
Map to arbitrary palette... (???)
Enregistrer une palette
Charger une palette
Choisir la méthode de diffusion
Palette optimisée pour le web
Palette depuis un fichier
Veuillez choisir le type de palette!
Map to arbitrary palette... (???)
Egaliser
Normaliser
Octree...
Quantification de la couleur de l'image (Algorithme Octree)
Enregistrer la matrice de co-occurrence
Enregistrer la matrice de co-occurrence sous...
Enregistrer la matrice de fréquence de co-occurrence
Enregistrer la matrice de fréquence de co-occurrence sous...
Windows Bitmap (BMP)...
Convertir
Convertir en palette
Convertir en niveaux de gris (8 bits)
Convertir en niveaux de gris (16 bits)
Convertir en RGB (24 bits)
Convertir en RGB (48 bits)
Réduire
Enregistrer l'histogramme sous...
Enregistrer l'histogramme
Edition
Défaire
Refaire
Propriétés de la texture...
Contraste
Energie
Entropie
Homogénéité
Propriétés de la texture
Corrélation
Dissimilitude
Minimum...
Maximum...
Appliquer le filtre minimum
Appliquer le filtre maximum
Vue
Zoom +
Zoom -
Revenir à la taille originale
Type d'interpolation
Voisin le plus proche (rapide)
Bilinéaire (lent)
Bi-cubique (plus lent)
Palm...
Palette système Palm OS (256 couleurs)
Palette système Palm OS (16 couleurs)
Palette système Palm OS (16 niveaux de gris)
Palette système Palm OS (4 niveaux de gris)
L'image a été modifiée. Voulez-vous quitter l'application sans enregistrer?
Quitter l'application
Oui
Non
Voulez-vous réellement quitter l'application sans enregistrer les modifications?
Fermer le fichier
Bits par pixel
Monochrome
Niveaux de gris
RGB vraies couleurs
Inconnu
Type d'image
Palette de couleurs
Pixels
Portable Network Graphics (PNG)...
Mémoire
Espace disque
Graphics Interchange Format (GIF)...
image1.jpg
java-imaging-utilities-0.14.2+3.orig/resources/lang/es.txt 0000664 0000000 0000000 00000012742 10404065626 020242 0 ustar Error cargando imagen
El formato del archivo es desconocido.
Cargar archivo de imagen
Resolución del monitor
No se puede crear histograma.
Número de colores usado
Contar colores usados...
Cerrar
Ayuda
Acerca de...
Sistema
Información del sistema...
Color
Invertir
Convertir a escala de grises
Archivo
Abrir...
Guardar como
Salir
Versión del Java Runtime Environment -JRE-
Proveedor del Java Runtime Environment
URL proveedor Java,
Directorio de la instalación Java
Especificación de máquina virtual Java (Virtual Machine -JVM-)
Especificación del proveedor de Java Virtual Machine
Especificación del nombre de Java Virtual Machine
Versión de la implementación de Java Virtual Machine
Proveedor de la implementación de Java Virtual Machine
Nombre de la implementación de Java Virtual Machine
Especificación de la Versión de Java Runtime Environment
Especificación del vendedor de Java Runtime Environment
Especificación del nombre de Java Runtime Environment
Número de versión del formato de clases Java
Java class path
Nombre del Sistema Operativo
Arquitectura del Systema Operativo
Versión del Sistema Operativo
Homepage
Contactar
Corte mediana...
Mensaje de error
El número de colores de la imagen ya es mínimo.
CPU endianness
CPU isalist
Memoria libre
Memoria usada
Memoria total
Guardar como
Transformaciones
Flip (espejo/horizontal)
Espejo
Median Corte + eliminación de contorno
Promover a RGB
Reducir a monocromo (umbral)...
Reducir a monocromo (Bayer dithering)...
Rotar a la izquierda (90)
Rotar a la derecha (90)
Rotar (180)
Rotar (otras magnitudes)...
Escala...
Escala de imagen
Nuevo ancho
Nueva altura
Mantener relación alto-ancho
OK
Cancelar
Número de colores
Cuantización de color a través de Corte mediana
Tipo de color de la salida
Media
Media ponderada
Mediana
Usando paleta
RGB color verdadero
Método de color representativo
Eliminación de contorno
Método
Filtros
Enfocar
Desenfocar
Bajo relieve
Destilación psicodélica
Litografía
Guardar como
Portable Bitmap (PBM)...
Portable Graymap (PGM)...
Portable Pixmap (PPM)...
Uniform palette...
Número de bits, rojo
Número de bits, verde
Número de bits, azul
Dithering ordenado
Ningún
Método Dithering
Cuantización de color por paleta uniforme
Guardar imagen como...
Error - demasiados bits.
Número total de bits, colores
Detección de bordes
Reducir número de tonos de gris
Reducir número de tonos de gris...
Número de bits
Número de tonos de gris
Sun Raster (RAS)...
Ajustar
Contraste...
Brillo...
Gamma...
Ajustar contraste
Por favor ingrese el cambio de contraste como un valor porcentual (-100 to 100):
Ajustar brillo
Por favor ingrese el cambio de brillo como un valor en porcentaje(-100 to 100):
Ajustar gamma
Por favor ingrese el valor gamma (0.0 to 10.0):
Cortar imagen
Columna izquierda
Fila al tope
Columna derecha
Fila izquierda
Cortar...
Convertir al mínimo tipo de color
Histograma
Reducir a bilevel usando un valor umbral
Por favor ingrese el valor umbral:
Difusión de error Floyd-Steinberg
Difusión de error Stucki
DIfusión de error Burkes
Difusión de error Sierra
Difusión de error Jarvice, Judice and Ninke
Difusion de error Stevenson-Arce
Algoritmo de mejoramiento de calidad salida
Ningún
Difusión del error
Cuantización de imagen color
Sobel horizontal
Sobel vertical
Prewitt horizontal
Prewitt vertical
Sesgar...
Sesgar imagen
Por favor ingrese el ángulo (> -90.0, < 90.0):
tono, saturación, valor...
Ajustar tono, saturación y valor
colocar tono
Tono (0..359)
Saturación (-100..100)
Valor (-100..100)
Media...
Mediana...
Óleo...
Aplicar filtro media
Aplicar filtro mediana,
Aplicar filtro aceite
Ancho de ventana (número impar >= 1)
Alto de ventana (número impar >= 1)
Por favor ingrese tamaño de ventana!
Eliminación de Contorno; número de pasadas
Eliminación de contorno ; distancia tau,
Paleta
Guardar como...
Mapa de paleta arbitraria...
Salvar paleta
Cargar paleta
Escoger método de dithering
Paleta Websafe (colores web)
Paleta desde archivo
Por favor, escoja el tipo de paleta
Mapa de paleta arbitraria
Ecualizar
Normalizar
Octree...
Cuantización de imagen color por Octree
Guardar matriz de coocurrencia
Guardar matriz de coocurrencia como...
Guardar matriz de frecuencia de coocurrencia
Guardar matriz de frecuencia de coocurrencia como...
Windows Bitmap (BMP)...
Promover
Promover a definido por paleta
Promover a escala de grises (8 bits)
Promover a escala de grises (16 bits)
Promover a RGB (24 bits)
Promover a RGB (48 bits)
Reducir
Guardar histograma como...
Guardar histograma
Modificar
Deshacer
Rehacer
Propiedades de textura...
Contraste
Energía
Entropía
Homogeneidad
Propiedades de textura
Correlación
Disimilaridad
Mínimo...
Máximo...
Aplicar filtro mínimo
Aplicar filtro máximo
Ver
Ampliar
Reducir
Tamaño original
Tipo de Interpolación
Vecino mas cercano (rápido)
Bilinear (lento)
Bicúbico (mas lento)
Palm...
Paleta del sistema de Palm OS (256 colores)
Paleta del sistema de Palm OS (16 colores)
Paleta del sistema de Palm OS (16 tonos de gris)
Paleta del sistema de Palm OS (4 tonos de gris)
La imagen ha cambiado. ¿Desea salir sin Grabar?
Salir del programa
Si
No
¿Seguro que quiere cerrar sin grabar los cambios?
Cerrar fichero
bits por píxel
monocroma
tonos de gris
Millones de colores (Rojo Verde Azul)
desconocido
Tipo
con paleta
Píxeles
Portable Network Graphics (PNG)...
memoria
espacio en disco
Graphics Interchange Format (GIF)...
image1.jpg
java-imaging-utilities-0.14.2+3.orig/resources/lang/de.txt 0000664 0000000 0000000 00000012370 10404065622 020214 0 ustar Fehler beim Laden eines Bildes
Das Dateiformat ist unbekannt.
Bilddatei laden
Bildschirmauflösung
Konnte Histogramm nicht erstellen.
Anzahl benutzter Farben
Anzahl benutzter Farben ermitteln...
Schließen
Hilfe
Über dieses Programm...
System
Systeminformation...
Farbe
Invertieren
In Graustufen umwandeln
Datei
Öffnen...
Speichern unter
Beenden
Version der Java-Laufzeitumgebung
Anbieter Java-Laufzeitumgebung
URL des Javaanbieters
Java-Installationsverzeichnis
Version der Spezifikation der JVM
Anbieter der Spezifikation der Java-Laufzeitumgebung
Name der Spezifikation der Java-Laufzeitumgebung
Implementationsversion der JVM
Anbieter der JVM-Implementation
Name der JVM-Implementation
Version der Spezifikation der Java-Laufzeitumgebung
Anbieter der Spezifikation der Java-Laufzeitumgebung
Name der Spezifikation der Java-Laufzeitumgebung
Versionsnummer des Java-Class-Formats
Java classpath
Name des Betriebssystems
Architektur des Betriebssystems
Version des Betriebssystems
Homepage
Feedback
Median Cut...
Fehlermeldung
Anzahl Farben ist bereits ausreichend klein.
CPU endianness
CPU isalist
Freier Speicher
Benutzter Speicher
Speicher gesamt
Speichern unter
Geometrie
Vertikal spiegeln
Horizontal spiegeln
Median Cut + Konturenentfernung
Erweitern zu RGB
Reduzieren zu Schwarz-Weiß (Schwellwert)...
Reduzieren zu Schwarz-Weiß (Bayer-Dithering)
Rotation (90 links)
Rotation (90 rechts)
Rotation (180)
Rotation (frei)...
Skalieren...
Bild skalieren
Neue Breite
Neue Höhe
Seitenverhältnis beibehalten
OK
Abbrechen
Anzahl Farben
Median Cut Farbquantisierung
Ausgabefarbtyp
Durchschnitt
Gewichteter Durchschnitt
Median
Farbpalette
RGB Echtfarbe
Methode für repräsentative Farbe
Konturenentfernung
Verfahren
Filter
Schärfen
Verwischen
Relief
Psychedelic Distillation
Lithograph
Speichern unter
Portable Bitmap (PBM)...
Portable Graymap (PGM)...
Portable Pixmap (PPM)...
Einheitlich verteilte Palette...
Anzahl Bit, rot
Anzahl Bit, grün
Anzahl Bit, blau
Ordered Dithering
Kein Dithering
Ditheringverfahren
Farbquantisierung (einheitliche Palette)
Bild speichern als
Fehler - Bitsumme zu groß.
Bit gesamt, Anzahl Farben
Kanten ermitteln
Anzahl Graustufen verringern
Anzahl Graustufen verringern...
Anzahl Bit
Anzahl Graustufen
Sun Raster (RAS)...
Anpassen
Kontrast...
Helligkeit...
Gamma...
Kontrast anpassen
Bitte die Kontraständerung als Prozentwert eingeben (-100 bis 100):
Helligkeit anpassen
Bitte die Helligkeitsänderung als Prozentwert eingeben (-100 bis 100):
Gammawert anpassen
Bitte den Gammawert eingeben (0.0 bis 10.0):
Bild ausschneiden
Linke Spalte
Oberste Zeile
Rechte Spalte
Unterste Zeile
Ausschneiden...
Umwandeln in minimalen Farbtyp
Histogramm
Zu Schwarz-Weiß reduzieren (Schwellwert)
Bitte den Schwellwert eingeben:
Floyd-Steinberg-Fehlerdiffusion
Stucki-Fehlerdiffusion
Burkes-Fehlerdiffusion
Sierra-Fehlerdiffusion
Jarvice-Judice-und-Ninke-Fehlerdiffusion
Stevenson-Arce-Fehlerdiffusion
Methode für Qualitätsverbesserung
Keine
Fehlerdiffusion
Farbbildquantisierung
Sobel (horizontal)
Sobel (vertikal)
Prewitt (horizontal)
Prewitt (vertikal)
Scheren...
Bild scheren
Bitte den Winkel eingeben (> -90.0, < 90.0):
Farbton, Sättigung, Helligkeit...
Farbton, Sättigung Helligkeit
Farbton setzen
Farbton (0..359)
Sättigung (-100..100)
Helligkeit (-100..100)
Mittelwert...
Median...
Öl...
Mittelwertfilter
Medianfilter
Ölfilter
Fensterbreite (ungerade Zahl >= 1)
Fensterhöhe (ungerade Zahl >= 1)
Bitte die Fenstergröße eingeben!
Konturenentfernung; Anzahl Durchgänge
Konturenentfernung; Abstand tau
Palette
Speichern unter...
Auf beliebige Palette abbilden...
Palette speichern
Palette laden
Ditheringverfahren auswählen
Websafe-Palette
Palette aus Datei
Bitte den Palettentyp angeben!
Auf beliebige Palette abbilden
Ausgleichen
Normalisieren
Octree...
Octree-Farbbildquantisierer
Co-occurrence-Matrix speichern
Co-occurrence-Matrix speichern unter...
Co-occurrence-Frequency-Matrix speichern
Co-occurrence-Frequency-Matrix speichern unter...
Windows Bitmap (BMP)...
Farbtiefe erhöhen
In Palettenbild umwandeln
In Graustufen umwandeln (8 Bit)
In Graustufen umwandeln (16 Bit)
In RGB umwandeln (24 Bit)
In RGB umwandeln (48 Bit)
Farbtiefe reduzieren
Histogramm speichern unter...
Histogramm speichern
Bearbeiten
Rückgängig
Wiederherstellen
Textureigenschaften...
Kontrast
Energie
Entropie
Homogenität
Textureigenschaften
Korrelation
Verschiedenartigkeit
Minimum...
Maximum...
Minimumfilter anwenden
Maximumfilter anwenden
Ansicht
Vergrößern
Verkleinern
Originalgröße
Interpolationstyp
Pixelreplikation (schnell)
Bilinear (langsamer)
Bikubisch (am langsamsten)
Palm...
Palm OS Systempalette (256 Farben)
Palm OS Systempalette (16 Farben)
Palm OS Systempalette (16 Graustufen)
Palm OS Systempalette (4 Graustufen)
Das Bild wurde geändert. Wollen Sie das Programm beenden, ohne Änderungen zu speichern?
Programm beenden
Ja
Nein
Wollen Sie die Datei wirklich schließen ohne die Veränderungen zu speichern?
Datei schließen
Bits pro Pixel
Schwarz-Weiß
Graustufen
RGB Echtfarbe
unbekannt
Bildtyp
Palette
Pixel
Portable Network Graphics (PNG)...
Arbeitsspeicher
Festplatte
Graphics Interchange Format (GIF)...
image1.jpg
java-imaging-utilities-0.14.2+3.orig/resources/images/ 0000775 0000000 0000000 00000000000 10404072055 017402 5 ustar java-imaging-utilities-0.14.2+3.orig/resources/images/image1.jpg 0000664 0000000 0000000 00000174254 10404072055 021264 0 ustar ÿØÿà JFIF H H ÿþ =Copyright (c) 2005 Marco Schmidt http://schmidt.devlib.org/ÿÛ C
$.' ",#(7),01444'9=82<.342ÿÛ C
2!!22222222222222222222222222222222222222222222222222ÿÀ @ " ÿÄ ÿÄ H !1AQa"q‘2¡#±ÁðBRÑá3bñ$r‚’¢²CS&4%csÒtƒÂÿÄ ÿÄ + !1A"Q2aqB‘ð#R±ÿÚ ? ú[…s—ÕâÛŸJÏž@dÀã
¸]`¢8Î;³“ ’ã'#xŽ@E—v4޲cœ˜° 1ã¬X'Œ©†75Ó*2_\ÒD$œ½GMåÊÔ0ÁfÞ2k/¾CÌäHG9h9œ0,߆fÐqy"øÁ[-ŒÎÊV–ÑéƒW€G¦EäÇ€02Y’œÉG·–UŒ°‘ÆGîq…¼ÑÖ:É…ÇXuãà\\° {rKŒÍ‚5†;Ã@ÞXr)
‹\©˜öÍ·ò<œÚhË(K~ù?.Ï\»`QÆyÆBŒí
àR¿Ã›H tʉ³U…6( !ôȲœÐA†}²äJ2rN1·+y §¶Ca¾™T…Ú>zb›J¨Åj3Y™¤bhO¦[Équ¼<Ð;årlR Gl…zcgR2àq‘!d»ñÓ+t<›ã˜£+iÅ_LÚLÍ”NJü³+ÒÏ¿)eçŒíœ‡ÂàæÏ8×1Új°ÜXúaÆÈ¥FÃ7•6£Ó+9È8°¢ŠÛ$Òß|†ã‘¬yªF-‹q8V’Êë<2QlU€F±ä‘“^FK-:±ÖF±U†J±V «ð¬+%…`¬+%…`
°¬u† VÃ U,U§ENK*
’Ýž*=c'“’0£%Î+ÉŒ–¬WÎZF@ŠÊ§,^rÔrÕqŠ·ˆôȆÁÌÐ*pNfx‰6
fúdJf”¨”dŒ‘ÁËy¬Ÿ•Íâ"‡9«TÇ o<剋9¢n8ÖC–4VxÈÚq¢+œ¹\æq×,Wç2ÑQqsYüáÔeg¯¦DŠiW÷ÉÌ ‘’ßYEš/$dó+¾Ie®øÅ‹6Á²…—Œ–üÍ2ØÈç$¹
Ù Ø Z0ÈÇy ŽG"°@Ôe€qe€æX
¬Dä²
‚…â-‘9ÙhÉ;¼D2XŒCŒw€càwÊÙ²§–²¨¶,¼ºúáÁ…¥èyËV[¬œq*ó‡®ḐŒbËe¬o¦Dš„‹Y|$K!#ó•—㌱¨‹ÊöŽÇ:£¥Ù²–÷¼¾A]ó;Α2Äg#¾Eµ•ý2·ÙÓbÙažò<žùQ94kʕɨcÀÇEzŒàZò‹Py¼|`qxF[ìXë Xcà +
°¬ Ã:ÀV:ÈTF±ãÃ!EXñá€,1Ö€*²U…`†B†Ž°ÊAa 2U,2ˆ*°¬…
Å’Ã Ó#Žë