deweese 02/03/07 14:07:45
Modified: sources/org/apache/batik/ext/awt/image/codec/tiff
TIFFImageEncoder.java
sources/org/apache/batik/gvt AbstractGraphicsNode.java
sources/org/apache/batik/gvt/filter
GraphicsNodeRable8Bit.java
sources/org/apache/batik/gvt/font AWTGVTGlyphVector.java
GVTLineMetrics.java SVGGVTGlyphVector.java
sources/org/apache/batik/gvt/renderer
StrokingTextPainter.java
sources/org/apache/batik/gvt/text GlyphLayout.java
sources/org/apache/batik/transcoder/image
ImageTranscoder.java PNGTranscoder.java
TIFFTranscoder.java
Added: sources/org/apache/batik/gvt/font MultiGlyphVector.java
test-references/samples/tests/spec/scripting .cvsignore
Log:
1) XResolution/YResolution/ResolutionUnits tags are now written
based on users dpi request.
2) Added support for FORCE_TRANSPARENT_WHITE hint to TIFF.
3) GlyphVector implementations now support getting glyph position for
one more than numGyphs, which is the total advance for GV.
4) Fixed a small bug in lineOffsets for scaled fonts.
5) Added preliminary implementation of 1.1 text wrapping (currently
no bridge for the functionality).
Revision Changes Path
1.2 +39 -37
xml-batik/sources/org/apache/batik/ext/awt/image/codec/tiff/TIFFImageEncoder.java
Index: TIFFImageEncoder.java
===================================================================
RCS file:
/home/cvs/xml-batik/sources/org/apache/batik/ext/awt/image/codec/tiff/TIFFImageEncoder.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- TIFFImageEncoder.java 16 May 2001 12:33:35 -0000 1.1
+++ TIFFImageEncoder.java 7 Mar 2002 22:07:44 -0000 1.2
@@ -192,7 +192,7 @@
}
IndexColorModel icm = null;
int sizeOfColormap = 0;
- int colormap[] = null;
+ char colormap[] = null;
// Set image type.
int imageType = TIFF_UNSUPPORTED;
@@ -343,11 +343,11 @@
int redIndex = 0, greenIndex = sizeOfColormap;
int blueIndex = 2 * sizeOfColormap;
- colormap = new int[sizeOfColormap * 3];
+ colormap = new char[sizeOfColormap * 3];
for (int i=0; i<sizeOfColormap; i++) {
- colormap[redIndex++] = (r[i] << 8) & 0xffff;
- colormap[greenIndex++] = (g[i] << 8) & 0xffff;
- colormap[blueIndex++] = (b[i] << 8) & 0xffff;
+ colormap[redIndex++] = (char)(((r[i] << 8) | r[i]) & 0xffff);
+ colormap[greenIndex++] = (char)(((g[i] << 8) | g[i]) & 0xffff);
+ colormap[blueIndex++] = (char)(((b[i] << 8) | b[i]) & 0xffff);
}
sizeOfColormap *= 3;
@@ -486,18 +486,21 @@
TIFFField.TIFF_LONG, 1,
new long[] {(long)height}));
+ char [] shortSampleSize = new char[numBands];
+ for (int i=0; i<numBands; i++)
+ shortSampleSize[i] = (char)sampleSize[i];
fields.add(new TIFFField(TIFFImageDecoder.TIFF_BITS_PER_SAMPLE,
TIFFField.TIFF_SHORT, numBands,
- sampleSize));
+ shortSampleSize));
fields.add(new TIFFField(TIFFImageDecoder.TIFF_COMPRESSION,
TIFFField.TIFF_SHORT, 1,
- new int[] {compression}));
+ new char[] {(char)compression}));
fields.add(
new TIFFField(TIFFImageDecoder.TIFF_PHOTOMETRIC_INTERPRETATION,
TIFFField.TIFF_SHORT, 1,
- new int[] {photometricInterpretation}));
+ new char[] {(char)photometricInterpretation}));
if(!isTiled) {
fields.add(new TIFFField(TIFFImageDecoder.TIFF_STRIP_OFFSETS,
@@ -507,7 +510,7 @@
fields.add(new TIFFField(TIFFImageDecoder.TIFF_SAMPLES_PER_PIXEL,
TIFFField.TIFF_SHORT, 1,
- new int[] {numBands}));
+ new char[] {(char)numBands}));
if(!isTiled) {
fields.add(new TIFFField(TIFFImageDecoder.TIFF_ROWS_PER_STRIP,
@@ -544,9 +547,9 @@
}
if(numExtraSamples > 0) {
- int[] extraSamples = new int[numExtraSamples];
+ char[] extraSamples = new char[numExtraSamples];
for(int i = 0; i < numExtraSamples; i++) {
- extraSamples[i] = extraSampleType;
+ extraSamples[i] = (char)extraSampleType;
}
fields.add(new TIFFField(TIFFImageDecoder.TIFF_EXTRA_SAMPLES,
TIFFField.TIFF_SHORT, numExtraSamples,
@@ -556,7 +559,7 @@
// Data Sample Format Extension fields.
if(dataType != DataBuffer.TYPE_BYTE) {
// SampleFormat
- int[] sampleFormat = new int[numBands];
+ char[] sampleFormat = new char[numBands];
if(dataType == DataBuffer.TYPE_FLOAT) {
sampleFormat[0] = 3;
} else if(dataType == DataBuffer.TYPE_USHORT) {
@@ -635,20 +638,20 @@
if(imageType == TIFF_YCBCR) {
// YCbCrSubSampling: 2 is the default so we must write 1 as
// we do not (yet) do any subsampling.
- int subsampleH = 1;
- int subsampleV = 1;
+ char subsampleH = 1;
+ char subsampleV = 1;
// If JPEG, update values.
if(compression == COMP_JPEG_TTN2) {
// Determine maximum subsampling.
- subsampleH = jep.getHorizontalSubsampling(0);
- subsampleV = jep.getVerticalSubsampling(0);
+ subsampleH = (char)jep.getHorizontalSubsampling(0);
+ subsampleV = (char)jep.getVerticalSubsampling(0);
for(int i = 1; i < numBands; i++) {
- int subH = jep.getHorizontalSubsampling(i);
+ char subH = (char)jep.getHorizontalSubsampling(i);
if(subH > subsampleH) {
subsampleH = subH;
}
- int subV = jep.getVerticalSubsampling(i);
+ char subV = (char)jep.getVerticalSubsampling(i);
if(subV > subsampleV) {
subsampleV = subV;
}
@@ -657,7 +660,7 @@
fields.add(new TIFFField(TIFF_YCBCR_SUBSAMPLING,
TIFFField.TIFF_SHORT, 2,
- new int[] {subsampleH, subsampleV}));
+ new char[] {subsampleH, subsampleV}));
// YCbCr positioning.
@@ -1461,28 +1464,22 @@
// unsigned 8 bits
case TIFFField.TIFF_BYTE:
byte bytes[] = field.getAsBytes();
-
- for (int i=0; i<count; i++) {
+ if (count > 4) count =4;
+ for (int i=0; i<count; i++)
output.write(bytes[i]);
- }
- for (int i = 0; i < (4 - count); i++) {
+ for (int i = 0; i < (4 - count); i++)
output.write(0);
- }
-
break;
// unsigned 16 bits
case TIFFField.TIFF_SHORT:
- int shorts[] = field.getAsInts();
-
- for (int i=0; i<count; i++) {
- writeUnsignedShort(shorts[i]);
- }
-
- for (int i = 0; i < (2 - count); i++) {
- writeUnsignedShort(0);
- }
+ char chars[] = field.getAsChars();
+ if (count > 2) count=2;
+ for (int i=0; i<count; i++)
+ writeUnsignedShort(chars[i]);
+ for (int i = 0; i < (2 - count); i++)
+ writeUnsignedShort(0);
break;
@@ -1517,8 +1514,13 @@
// unsigned 16 bits
case TIFFField.TIFF_SHORT:
+ char chars[] = field.getAsChars();
+ for (int i=0; i<count; i++) {
+ writeUnsignedShort(chars[i]);
+ }
+ break;
case TIFFField.TIFF_SSHORT:
- int shorts[] = field.getAsInts();
+ short shorts[] = field.getAsShorts();
for (int i=0; i<count; i++) {
writeUnsignedShort(shorts[i]);
}
@@ -1545,8 +1547,8 @@
double[] doubles = field.getAsDoubles();
for (int i=0; i<count; i++) {
long longBits = Double.doubleToLongBits(doubles[i]);
- writeLong((int)(longBits >> 32));
- writeLong((int)(longBits & 0xffffffff));
+ writeLong(longBits >>> 32);
+ writeLong(longBits & 0xffffffff);
}
break;
1.38 +5 -5 xml-batik/sources/org/apache/batik/gvt/AbstractGraphicsNode.java
Index: AbstractGraphicsNode.java
===================================================================
RCS file:
/home/cvs/xml-batik/sources/org/apache/batik/gvt/AbstractGraphicsNode.java,v
retrieving revision 1.37
retrieving revision 1.38
diff -u -r1.37 -r1.38
--- AbstractGraphicsNode.java 6 Mar 2002 09:06:39 -0000 1.37
+++ AbstractGraphicsNode.java 7 Mar 2002 22:07:44 -0000 1.38
@@ -54,7 +54,7 @@
* @author <a href="mailto:[EMAIL PROTECTED]">Thierry Kormann</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Emmanuel Tissandier</a>
* @author <a href="mailto:[EMAIL PROTECTED]">Thomas DeWeese</a>
- * @version $Id: AbstractGraphicsNode.java,v 1.37 2002/03/06 09:06:39 vhardy Exp $
+ * @version $Id: AbstractGraphicsNode.java,v 1.38 2002/03/07 22:07:44 deweese Exp $
*/
public abstract class AbstractGraphicsNode implements GraphicsNode {
@@ -793,12 +793,12 @@
}
/**
- * Returns the bounds of this node's primitivePaint after applying the input
- * transform (if any), concatenated with this node's transform (if any).
+ * Returns the bounds of this node's primitivePaint after applying
+ * the input transform (if any), concatenated with this node's
+ * transform (if any).
*
* @param txf the affine transform with which this node's transform should
- * be concatenated. Should not be null.
- */
+ * be concatenated. Should not be null. */
public Rectangle2D getTransformedPrimitiveBounds(AffineTransform txf) {
Rectangle2D tpBounds = getPrimitiveBounds();
if (tpBounds == null) {
1.17 +4 -7
xml-batik/sources/org/apache/batik/gvt/filter/GraphicsNodeRable8Bit.java
Index: GraphicsNodeRable8Bit.java
===================================================================
RCS file:
/home/cvs/xml-batik/sources/org/apache/batik/gvt/filter/GraphicsNodeRable8Bit.java,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -r1.16 -r1.17
--- GraphicsNodeRable8Bit.java 19 Feb 2002 18:01:29 -0000 1.16
+++ GraphicsNodeRable8Bit.java 7 Mar 2002 22:07:44 -0000 1.17
@@ -40,7 +40,7 @@
* createRendering methods.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Vincent Hardy</a>
- * @version $Id: GraphicsNodeRable8Bit.java,v 1.16 2002/02/19 18:01:29 deweese Exp $
+ * @version $Id: GraphicsNodeRable8Bit.java,v 1.17 2002/03/07 22:07:44 deweese Exp $
*/
public class GraphicsNodeRable8Bit
extends AbstractRable
@@ -152,12 +152,10 @@
public Rectangle2D getBounds2D(){
if (usePrimitivePaint){
Rectangle2D primitiveBounds = node.getPrimitiveBounds();
- if(primitiveBounds != null){
- return (Rectangle2D)(primitiveBounds.clone());
- }
- else{
+ if(primitiveBounds == null)
return new Rectangle2D.Double(0, 0, 0, 0);
- }
+
+ return (Rectangle2D)(primitiveBounds.clone());
}
// When not using Primitive paint we return out bounds in our
@@ -174,7 +172,6 @@
if (at != null){
bounds = at.createTransformedShape(bounds).getBounds2D();
}
-
return bounds;
}
1.17 +15 -6
xml-batik/sources/org/apache/batik/gvt/font/AWTGVTGlyphVector.java
Index: AWTGVTGlyphVector.java
===================================================================
RCS file:
/home/cvs/xml-batik/sources/org/apache/batik/gvt/font/AWTGVTGlyphVector.java,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -r1.16 -r1.17
--- AWTGVTGlyphVector.java 13 Dec 2001 16:55:02 -0000 1.16
+++ AWTGVTGlyphVector.java 7 Mar 2002 22:07:44 -0000 1.17
@@ -34,7 +34,7 @@
* This is a wrapper class for a java.awt.font.GlyphVector instance.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Bella Robinson</a>
- * @version $Id: AWTGVTGlyphVector.java,v 1.16 2001/12/13 16:55:02 tkormann Exp $
+ * @version $Id: AWTGVTGlyphVector.java,v 1.17 2002/03/07 22:07:44 deweese Exp $
*/
public class AWTGVTGlyphVector implements GVTGlyphVector {
@@ -94,7 +94,7 @@
outline = null;
logicalBounds = null;
int numGlyphs = glyphVector.getNumGlyphs();
- glyphPositions = new Point2D.Float[numGlyphs];
+ glyphPositions = new Point2D.Float[numGlyphs+1];
glyphTransforms = new AffineTransform[numGlyphs];
glyphOutlines = new Shape[numGlyphs];
glyphVisualBounds = new Shape[numGlyphs];
@@ -584,7 +584,8 @@
visualBounds = null;
logicalBounds = null;
float shiftLeft = 0;
- for (int i = 0; i < getNumGlyphs(); i++) {
+ int i=0;
+ for (; i < getNumGlyphs(); i++) {
glyphTransforms [i] = null;
glyphVisualBounds [i] = null;
glyphLogicalBounds[i] = null;
@@ -602,6 +603,12 @@
shiftLeft += getGlyphMetrics(i).getHorizontalAdvance();
}
}
+
+ // Need glyph pos for point after last char...
+ Point2D glyphPos = defaultGlyphPositions[i];
+ glyphPositions[i] = new Point2D.Float
+ ((float)((glyphPos.getX() * scaleFactor)-shiftLeft),
+ (float) (glyphPos.getY() * scaleFactor));
}
/**
@@ -613,9 +620,11 @@
outline = null;
logicalBounds = null;
visualBounds = null;
- glyphVisualBounds[glyphIndex] = null;
- glyphLogicalBounds[glyphIndex] = null;
- glyphOutlines[glyphIndex] = null;
+ if (glyphIndex != getNumGlyphs()) {
+ glyphVisualBounds[glyphIndex] = null;
+ glyphLogicalBounds[glyphIndex] = null;
+ glyphOutlines[glyphIndex] = null;
+ }
}
/**
1.5 +4 -1 xml-batik/sources/org/apache/batik/gvt/font/GVTLineMetrics.java
Index: GVTLineMetrics.java
===================================================================
RCS file: /home/cvs/xml-batik/sources/org/apache/batik/gvt/font/GVTLineMetrics.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- GVTLineMetrics.java 17 Sep 2001 16:28:27 -0000 1.4
+++ GVTLineMetrics.java 7 Mar 2002 22:07:44 -0000 1.5
@@ -14,7 +14,7 @@
* GVTLineMetrics is a GVT version of java.awt.font.LineMetrics.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Bella Robinson</a>
- * @version $Id: GVTLineMetrics.java,v 1.4 2001/09/17 16:28:27 tkormann Exp $
+ * @version $Id: GVTLineMetrics.java,v 1.5 2002/03/07 22:07:44 deweese Exp $
*/
public class GVTLineMetrics {
@@ -67,6 +67,9 @@
this.ascent = lineMetrics.getAscent() * scaleFactor;
this.baselineIndex = lineMetrics.getBaselineIndex();
this.baselineOffsets = lineMetrics.getBaselineOffsets();
+ for (int i=0; i<baselineOffsets.length; i++) {
+ this.baselineOffsets[i] *= scaleFactor;
+ }
this.descent = lineMetrics.getDescent() * scaleFactor;
this.height = lineMetrics.getHeight() * scaleFactor;
this.leading = lineMetrics.getLeading();
1.10 +33 -11
xml-batik/sources/org/apache/batik/gvt/font/SVGGVTGlyphVector.java
Index: SVGGVTGlyphVector.java
===================================================================
RCS file:
/home/cvs/xml-batik/sources/org/apache/batik/gvt/font/SVGGVTGlyphVector.java,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- SVGGVTGlyphVector.java 20 Sep 2001 19:36:05 -0000 1.9
+++ SVGGVTGlyphVector.java 7 Mar 2002 22:07:44 -0000 1.10
@@ -29,17 +29,18 @@
* A GVTGlyphVector class for SVG fonts.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Bella Robinson</a>
- * @version $Id: SVGGVTGlyphVector.java,v 1.9 2001/09/20 19:36:05 deweese Exp $
+ * @version $Id: SVGGVTGlyphVector.java,v 1.10 2002/03/07 22:07:44 deweese Exp $
*/
public final class SVGGVTGlyphVector implements GVTGlyphVector {
- private GVTFont font;
- private Glyph[] glyphs;
+ private GVTFont font;
+ private Glyph[] glyphs;
private FontRenderContext frc;
- private GeneralPath outline;
- private Rectangle2D logicalBounds;
- private Shape[] glyphLogicalBounds;
- private boolean[] glyphVisible;
+ private GeneralPath outline;
+ private Rectangle2D logicalBounds;
+ private Shape[] glyphLogicalBounds;
+ private boolean[] glyphVisible;
+ private Point2D endPos;
/**
* Constructs an SVGGVTGlyphVector.
@@ -49,7 +50,8 @@
* glyph vector.
* @param frc The current font render context.
*/
- public SVGGVTGlyphVector(GVTFont font, Glyph[] glyphs, FontRenderContext frc) {
+ public SVGGVTGlyphVector(GVTFont font, Glyph[] glyphs,
+ FontRenderContext frc) {
this.font = font;
this.glyphs = glyphs;
this.frc = frc;
@@ -60,6 +62,11 @@
for (int i = 0; i < glyphs.length; i++) {
glyphVisible[i] = true;
}
+
+ endPos = glyphs[glyphs.length-1].getPosition();
+ endPos = new Point2D.Float
+ ((float)(endPos.getX()+glyphs[glyphs.length-1].getHorizAdvX()),
+ (float)endPos.getY());
}
/**
@@ -474,6 +481,9 @@
* Returns the position of the specified glyph within this GlyphVector.
*/
public Point2D getGlyphPosition(int glyphIndex) {
+ if (glyphIndex == glyphs.length)
+ return endPos;
+
if (glyphIndex < 0 || (glyphIndex > glyphs.length-1)) {
throw new IndexOutOfBoundsException("glyphIndex: " + glyphIndex
+ ", is out of bounds. Should be between 0 and " + (glyphs.length-1) +
".");
@@ -496,7 +506,7 @@
+ " is out of bounds, should be between 0 and "
+ (glyphs.length-1));
}
- if ((beginGlyphIndex+numEntries) > glyphs.length) {
+ if ((beginGlyphIndex+numEntries) > glyphs.length+1) {
throw new IndexOutOfBoundsException("beginGlyphIndex + numEntries ("
+ beginGlyphIndex + "+" + numEntries
+ ") exceeds the number of glpyhs in this GlyphVector");
@@ -504,9 +514,15 @@
if (positionReturn == null) {
positionReturn = new float[numEntries*2];
}
+ if ((beginGlyphIndex+numEntries) == glyphs.length+1) {
+ numEntries--;
+ positionReturn[numEntries*2] = (float)endPos.getX();
+ positionReturn[numEntries*2+1] = (float)endPos.getY();
+ }
for (int i = beginGlyphIndex; i < (beginGlyphIndex+numEntries); i++) {
- Point2D glyphPos = glyphs[i].getPosition();
- positionReturn[(i-beginGlyphIndex)*2] = (float)glyphPos.getX();
+ Point2D glyphPos;
+ glyphPos = glyphs[i].getPosition();
+ positionReturn[(i-beginGlyphIndex)*2] = (float)glyphPos.getX();
positionReturn[(i-beginGlyphIndex)*2 + 1] = (float)glyphPos.getY();
}
return positionReturn;
@@ -615,6 +631,7 @@
logicalBounds = null;
outline = null;
}
+ endPos = new Point2D.Float(currentX, currentY);
}
/**
@@ -622,6 +639,11 @@
*/
public void setGlyphPosition(int glyphIndex, Point2D newPos)
throws IndexOutOfBoundsException {
+ if (glyphIndex == glyphs.length) {
+ endPos = (Point2D)newPos.clone();
+ return;
+ }
+
if (glyphIndex < 0 || (glyphIndex > glyphs.length-1)) {
throw new IndexOutOfBoundsException("glyphIndex: " + glyphIndex
+ ", is out of bounds. Should be between 0 and " + (glyphs.length-1) +
".");
1.1
xml-batik/sources/org/apache/batik/gvt/font/MultiGlyphVector.java
Index: MultiGlyphVector.java
===================================================================
/*****************************************************************************
* Copyright (C) The Apache Software Foundation. All rights reserved. *
* ------------------------------------------------------------------------- *
* This software is published under the terms of the Apache Software License *
* version 1.1, a copy of which has been included with this distribution in *
* the LICENSE file. *
*****************************************************************************/
package org.apache.batik.gvt.font;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphJustificationInfo;
import java.awt.font.GlyphMetrics;
import java.awt.font.GlyphVector;
import java.awt.font.TextAttribute;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.text.AttributedCharacterIterator;
import java.text.CharacterIterator;
import org.apache.batik.gvt.text.AttributedCharacterSpanIterator;
import java.util.List;
import java.util.Iterator;
public class MultiGlyphVector implements GVTGlyphVector {
GVTGlyphVector [] gvs;
int [] nGlyphs;
int [] off;
int nGlyph;
public MultiGlyphVector(List gvs) {
this.gvs = new GVTGlyphVector[gvs.size()];
this.nGlyphs = new int[gvs.size()];
this.off = new int[gvs.size()];
Iterator iter = gvs.iterator();
int i=0;
while (iter.hasNext()) {
off[i] = nGlyph;
GVTGlyphVector gv = (GVTGlyphVector)iter.next();
this.gvs[i] = gv;
nGlyphs[i] = gv.getNumGlyphs();
nGlyph += nGlyphs[i];
i++;
}
nGlyphs[i-1]++;
}
/**
* Returns the number of glyphs in this GlyphVector.
*/
public int getNumGlyphs() {
return nGlyph;
}
int getGVIdx(int glyphIdx) {
if (glyphIdx > nGlyph) return -1;
if (glyphIdx == nGlyph) return gvs.length-1;
for (int i=0; i<nGlyphs.length; i++)
if (glyphIdx-off[i] < nGlyphs[i]) return i;
return -1;
}
/**
* Returns the Font associated with this GlyphVector.
*/
public GVTFont getFont() {
throw new IllegalArgumentException("Can't be correctly Implemented");
}
/**
* Returns the FontRenderContext associated with this GlyphVector.
*/
public FontRenderContext getFontRenderContext() {
return gvs[0].getFontRenderContext();
}
/**
* Returns the glyphcode of the specified glyph.
*/
public int getGlyphCode(int glyphIndex) {
int idx = getGVIdx(glyphIndex);
return gvs[idx].getGlyphCode(glyphIndex-off[idx]);
}
/**
* Returns the justification information for the glyph at the specified
* index into this GlyphVector.
*/
public GlyphJustificationInfo getGlyphJustificationInfo(int glyphIndex) {
int idx = getGVIdx(glyphIndex);
return gvs[idx].getGlyphJustificationInfo(glyphIndex-off[idx]);
}
/**
* Returns the logical bounds of the specified glyph within this
* GlyphVector.
*/
public Shape getGlyphLogicalBounds(int glyphIndex) {
int idx = getGVIdx(glyphIndex);
return gvs[idx].getGlyphLogicalBounds(glyphIndex-off[idx]);
}
/**
* Returns the metrics of the glyph at the specified index into this
* GlyphVector.
*/
public GVTGlyphMetrics getGlyphMetrics(int glyphIndex) {
int idx = getGVIdx(glyphIndex);
return gvs[idx].getGlyphMetrics(glyphIndex-off[idx]);
}
/**
* Returns a Shape whose interior corresponds to the visual representation
* of the specified glyph within this GlyphVector.
*/
public Shape getGlyphOutline(int glyphIndex) {
int idx = getGVIdx(glyphIndex);
return gvs[idx].getGlyphOutline(glyphIndex-off[idx]);
}
/**
* Returns the position of the specified glyph within this GlyphVector.
*/
public Point2D getGlyphPosition(int glyphIndex) {
int idx = getGVIdx(glyphIndex);
return gvs[idx].getGlyphPosition(glyphIndex-off[idx]);
}
/**
* Gets the transform of the specified glyph within this GlyphVector.
*/
public AffineTransform getGlyphTransform(int glyphIndex) {
int idx = getGVIdx(glyphIndex);
return gvs[idx].getGlyphTransform(glyphIndex-off[idx]);
}
/**
* Returns the visual bounds of the specified glyph within the GlyphVector.
*/
public Shape getGlyphVisualBounds(int glyphIndex) {
int idx = getGVIdx(glyphIndex);
return gvs[idx].getGlyphVisualBounds(glyphIndex-off[idx]);
}
/**
* Sets the position of the specified glyph within this GlyphVector.
*/
public void setGlyphPosition(int glyphIndex, Point2D newPos) {
int idx = getGVIdx(glyphIndex);
// System.out.println("setting: " + idx + " - " + (glyphIndex-off[idx]) +
// " -> " + newPos);
gvs[idx].setGlyphPosition(glyphIndex-off[idx], newPos);
}
/**
* Sets the transform of the specified glyph within this GlyphVector.
*/
public void setGlyphTransform(int glyphIndex, AffineTransform newTX) {
int idx = getGVIdx(glyphIndex);
gvs[idx].setGlyphTransform(glyphIndex-off[idx], newTX);
}
/**
* Tells the glyph vector whether or not to draw the specified glyph.
*/
public void setGlyphVisible(int glyphIndex, boolean visible) {
int idx = getGVIdx(glyphIndex);
gvs[idx].setGlyphVisible(glyphIndex-off[idx], visible);
}
/**
* Returns an array of glyphcodes for the specified glyphs.
*/
public int[] getGlyphCodes(int beginGlyphIndex, int numEntries,
int[] codeReturn) {
int [] ret = codeReturn;
if (ret == null)
ret = new int[numEntries];
int [] tmp = null;
int gvIdx = getGVIdx(beginGlyphIndex);
int gi = beginGlyphIndex-off[gvIdx];
int i=0;
GVTGlyphVector gv;
while (numEntries != 0) {
int len = numEntries;
if (gi+len > nGlyphs[gvIdx])
len = nGlyphs[gvIdx]-gi;
gv = gvs[gvIdx];
if (i == 0) {
gv.getGlyphCodes(gi, len, ret);
} else {
if ((tmp == null) || (tmp.length < len))
tmp = new int[len];
gv.getGlyphCodes(gi, len, tmp);
for (int j=0; j<len; j++)
ret[i+j] = tmp[j];
}
gi=0;
gvIdx++;
numEntries -= len;
i+=len;
}
return ret;
}
/**
* Returns an array of glyph positions for the specified glyphs
*/
public float[] getGlyphPositions(int beginGlyphIndex,
int numEntries,
float[] positionReturn) {
float [] ret = positionReturn;
if (ret == null)
ret = new float[numEntries*2];
float [] tmp = null;
int gvIdx = getGVIdx(beginGlyphIndex);
int gi = beginGlyphIndex-off[gvIdx];
int i=0;
GVTGlyphVector gv;
while (numEntries != 0) {
int len = numEntries;
if (gi+len > nGlyphs[gvIdx])
len = nGlyphs[gvIdx]-gi;
gv = gvs[gvIdx];
if (i == 0) {
gv.getGlyphPositions(gi, len, ret);
} else {
if ((tmp == null) || (tmp.length < len*2))
tmp = new float[len*2];
gv.getGlyphPositions(gi, len, tmp);
for (int j=0; j<len*2; j++)
ret[i+j] = tmp[j];
}
gi=0;
gvIdx++;
numEntries -= len;
i+=len*2;
}
return ret;
}
/**
* Returns the logical bounds of this GlyphVector.
*/
public Rectangle2D getLogicalBounds() {
Rectangle2D ret = null;
for (int idx=0; idx<gvs.length; idx++) {
Rectangle2D b = gvs[idx].getLogicalBounds();
if (ret == null) ret = b;
else ret = ret.createUnion(b);
}
return ret;
}
/**
* Returns a Shape whose interior corresponds to the visual representation
* of this GlyphVector.
*/
public Shape getOutline() {
GeneralPath ret = null;
for (int idx=0; idx<gvs.length; idx++) {
Shape s = gvs[idx].getOutline();
if (ret == null) ret = new GeneralPath(s);
else ret.append(s, false);
}
return ret;
}
/**
* Returns a Shape whose interior corresponds to the visual representation
* of this GlyphVector, offset to x, y.
*/
public Shape getOutline(float x, float y) {
Shape outline = getOutline();
AffineTransform tr = AffineTransform.getTranslateInstance(x,y);
outline = tr.createTransformedShape(outline);
return outline;
}
/**
* Returns the visual bounds of this GlyphVector The visual bounds is the
* tightest rectangle enclosing all non-background pixels in the rendered
* representation of this GlyphVector.
*/
public Rectangle2D getVisualBounds() {
Rectangle2D ret = null;
for (int idx=0; idx<gvs.length; idx++) {
Rectangle2D b = gvs[idx].getVisualBounds();
if (ret == null) ret = b;
else ret = ret.createUnion(b);
}
return ret;
}
public void performDefaultLayout() {
for (int idx=0; idx<gvs.length; idx++) {
gvs[idx].performDefaultLayout();
}
}
/**
* Returns the number of chars represented by the glyphs within the
* specified range.
*
* @param startGlyphIndex The index of the first glyph in the range.
* @param endGlyphIndex The index of the last glyph in the range.
* @return The number of chars.
*/
public int getCharacterCount(int startGlyphIndex, int endGlyphIndex) {
int idx1 = getGVIdx(startGlyphIndex);
int idx2 = getGVIdx(endGlyphIndex);
int ret=0;
for (int idx=idx1; idx<=idx2; idx++) {
int gi1 = startGlyphIndex-off[idx];
int gi2 = endGlyphIndex-off[idx];
if (gi2 >= nGlyphs[idx]) {
gi2 = nGlyphs[idx]-1;
}
ret += gvs[idx].getCharacterCount(gi1, gi2);
startGlyphIndex += (gi2-gi1+1);
}
return ret;
}
/**
* Draws the glyph vector.
*/
public void draw(Graphics2D g2d,
AttributedCharacterIterator aci) {
int begin = aci.getBeginIndex();
for (int idx=0; idx<gvs.length; idx++) {
GVTGlyphVector gv = gvs[idx];
int end = gv.getCharacterCount(0, gv.getNumGlyphs())+1;
gv.draw(g2d, new AttributedCharacterSpanIterator(aci, begin, end));
begin = end;
}
}
}
1.29 +30 -1
xml-batik/sources/org/apache/batik/gvt/renderer/StrokingTextPainter.java
Index: StrokingTextPainter.java
===================================================================
RCS file:
/home/cvs/xml-batik/sources/org/apache/batik/gvt/renderer/StrokingTextPainter.java,v
retrieving revision 1.28
retrieving revision 1.29
diff -u -r1.28 -r1.29
--- StrokingTextPainter.java 29 Jan 2002 16:19:00 -0000 1.28
+++ StrokingTextPainter.java 7 Mar 2002 22:07:44 -0000 1.29
@@ -61,7 +61,7 @@
* @see org.apache.batik.gvt.text.GVTAttributedCharacterIterator
*
* @author <a href="[EMAIL PROTECTED]>Bill Haneman</a>
- * @version $Id: StrokingTextPainter.java,v 1.28 2002/01/29 16:19:00 deweese Exp $
+ * @version $Id: StrokingTextPainter.java,v 1.29 2002/03/07 22:07:44 deweese Exp $
*/
public class StrokingTextPainter extends BasicTextPainter {
@@ -221,6 +221,35 @@
currentChunk++;
} while (chunk != null && currentChunk < chunkACIs.length);
+
+
+ if (false) {
+ // When doing text wrapping there should only ever be
+ // one text chunk (as chunks are caused by use of
+ // the 'x' and 'y' attributes which aren't allowed in
+ // the 'textFlow' element.
+ Iterator i = textRuns.iterator();
+ List layouts = new ArrayList();
+ while (i.hasNext()) {
+ TextRun tr = (TextRun)i.next();
+ layouts.add(tr.getLayout());
+ }
+
+ List rects = new ArrayList();
+ rects.add(new Rectangle2D.Float( 17, 80, 200, 400));
+ rects.add(new Rectangle2D.Float(233, 80, 200, 400));
+
+ List brLocs = new ArrayList();
+ brLocs.add(new Integer(292));
+ brLocs.add(new Integer(476));
+ List pLocs = new ArrayList();
+ pLocs.add(new Integer(96));
+ pLocs.add(new Integer(175));
+
+ org.apache.batik.gvt.text.GlyphLayout.textWrapTextChunk
+ (chunkACIs[0], layouts, rects, brLocs, pLocs, 3);
+ }
+
// t1 = System.currentTimeMillis();
// layoutTime += t1-t0;
// System.out.println("Reorder: " + reorderTime + " FontMatching: " +
fontMatchingTime + " Layout: " + layoutTime);
1.36 +676 -58 xml-batik/sources/org/apache/batik/gvt/text/GlyphLayout.java
Index: GlyphLayout.java
===================================================================
RCS file: /home/cvs/xml-batik/sources/org/apache/batik/gvt/text/GlyphLayout.java,v
retrieving revision 1.35
retrieving revision 1.36
diff -u -r1.35 -r1.36
--- GlyphLayout.java 29 Jan 2002 16:19:01 -0000 1.35
+++ GlyphLayout.java 7 Mar 2002 22:07:44 -0000 1.36
@@ -23,14 +23,19 @@
import java.awt.geom.Rectangle2D;
import java.text.AttributedCharacterIterator;
import java.text.CharacterIterator;
-import java.util.Set;
+
import java.util.HashSet;
+import java.util.Set;
+import java.util.List;
+import java.util.LinkedList;
+import java.util.Iterator;
import org.apache.batik.gvt.TextNode;
import org.apache.batik.gvt.text.TextSpanLayout;
import org.apache.batik.gvt.text.GVTAttributedCharacterIterator;
import org.apache.batik.gvt.text.TextHit;
import org.apache.batik.gvt.font.GVTGlyphVector;
+import org.apache.batik.gvt.font.MultiGlyphVector;
import org.apache.batik.gvt.font.AltGlyphHandler;
import org.apache.batik.gvt.font.GVTLineMetrics;
import org.apache.batik.gvt.font.GVTFont;
@@ -42,7 +47,7 @@
* @see org.apache.batik.gvt.text.TextSpanLayout
*
* @author <a href="[EMAIL PROTECTED]>Bill Haneman</a>
- * @version $Id: GlyphLayout.java,v 1.35 2002/01/29 16:19:01 deweese Exp $
+ * @version $Id: GlyphLayout.java,v 1.36 2002/03/07 22:07:44 deweese Exp $
*/
public class GlyphLayout implements TextSpanLayout {
@@ -51,7 +56,6 @@
private GVTLineMetrics metrics;
private AttributedCharacterIterator aci;
private FontRenderContext frc;
- private AffineTransform transform;
private Point2D advance;
private Point2D offset;
private float xScale=1;
@@ -82,6 +86,9 @@
+ public static final AttributedCharacterIterator.Attribute
+ TEXT_COMPOUND_DELIMITER
+ = GVTAttributedCharacterIterator.TextAttribute.TEXT_COMPOUND_DELIMITER;
private static final AttributedCharacterIterator.Attribute X
= GVTAttributedCharacterIterator.TextAttribute.X;
@@ -118,6 +125,12 @@
runAtts.add(BASELINE_SHIFT);
}
+ static Set szAtts = new HashSet();
+
+ static {
+ szAtts.add(TextAttribute.SIZE);
+ }
+
/**
@@ -139,7 +152,6 @@
this.aci = aci;
this.frc = frc;
this.offset = offset;
- this.transform = null;
this.font = getFont();
this.charMap = charMap;
@@ -153,18 +165,28 @@
this.textPath = (TextPath) aci.getAttribute
(GVTAttributedCharacterIterator.TextAttribute.TEXTPATH);
- AltGlyphHandler altGlyphHandler = (AltGlyphHandler)this.aci.getAttribute(
- GVTAttributedCharacterIterator.TextAttribute.ALT_GLYPH_HANDLER);
+ AltGlyphHandler altGlyphHandler
+ = (AltGlyphHandler)this.aci.getAttribute
+ (GVTAttributedCharacterIterator.TextAttribute.ALT_GLYPH_HANDLER);
if (altGlyphHandler != null) {
- // this must be an altGlyph text element, try and create the alternate
glyphs
- this.gv = altGlyphHandler.createGlyphVector(frc, this.font.getSize(),
this.aci);
+ // this must be an altGlyph text element, try and create
+ // the alternate glyphs
+ this.gv = altGlyphHandler.createGlyphVector
+ (frc, this.font.getSize(), this.aci);
}
if (this.gv == null) {
- // either not an altGlyph or the altGlyphHandler failed to create a
glyph vector
+ // either not an altGlyph or the altGlyphHandler failed to
+ // create a glyph vector
this.gv = font.createGlyphVector(frc, this.aci);
}
}
+
+ GVTGlyphVector getGlyphVector() {
+ return this.gv;
+ }
+
+
/**
* Returns the current text position at the beginning
* of glyph layout, before the application of explicit
@@ -223,8 +245,8 @@
float dy = (float)(offset.getY()-this.offset.getY());
int numGlyphs = gv.getNumGlyphs();
- float [] gp = gv.getGlyphPositions(0, numGlyphs, null);
- for (int i=0; i<numGlyphs; i++) {
+ float [] gp = gv.getGlyphPositions(0, numGlyphs+1, null);
+ for (int i=0; i<=numGlyphs; i++) {
gv.setGlyphPosition(i, new Point2D.Float(gp[2*i]+dx,
gp[2*i+1]+dy));
}
@@ -234,7 +256,7 @@
// offset this will be factored in for any future layout
// operations.
this.offset = offset;
-
+
// We don't affect layoutApplied or spacingApplied since
// they both work off the offset value.
@@ -318,16 +340,7 @@
*/
public void draw(Graphics2D g2d) {
syncLayout();
-
- AffineTransform t;
- if (transform != null) {
- t = g2d.getTransform();
- g2d.transform(transform);
- gv.draw(g2d, aci);
- g2d.setTransform(t);
- } else {
- gv.draw(g2d, aci);
- }
+ gv.draw(g2d, aci);
}
/**
@@ -346,11 +359,7 @@
public Shape getOutline() {
syncLayout();
- Shape s = gv.getOutline();
- if (transform != null) {
- s = transform.createTransformedShape(s);
- }
- return s;
+ return gv.getOutline();
}
/**
@@ -373,9 +382,6 @@
if ((decorationType & DECORATION_OVERLINE) != 0) {
((GeneralPath) g).append(getOverlineShape(), false);
}
- if (transform != null) {
- g = transform.createTransformedShape(g);
- }
return g;
}
@@ -385,11 +391,7 @@
public Rectangle2D getBounds() {
syncLayout();
- Rectangle2D bounds = gv.getVisualBounds();
- if (transform != null) {
- bounds = transform.createTransformedShape(bounds).getBounds2D();
- }
- return bounds;
+ return gv.getVisualBounds();
}
/**
@@ -558,9 +560,6 @@
}
addPtsToPath(shape, topPts, botPts, ptIdx);
- if (transform != null) {
- return transform.createTransformedShape(shape);
- }
return shape;
}
@@ -842,17 +841,6 @@
TextHit textHit = null;
- // if this layout is transformed, need to apply the inverse
- // transform to the point
- if (transform != null) {
- try {
- Point2D p = new Point2D.Float(x, y);
- transform.inverseTransform(p, p);
- x = (float) p.getX();
- y = (float) p.getY();
- } catch (java.awt.geom.NoninvertibleTransformException nite) {;}
- }
-
int currentChar = 0;
for (int i = 0; i < gv.getNumGlyphs(); i++) {
Shape gbounds = gv.getGlyphLogicalBounds(i);
@@ -907,6 +895,12 @@
// not sure if this is correct behaviour or not
y += overlineThickness;
+ // Not certain what should be done here...
+ // aci.first();
+ // Float dy = (Float) aci.getAttribute(DY);
+ // if (dy != null)
+ // y += dy.floatValue();
+
Stroke overlineStroke =
new BasicStroke(overlineThickness);
Rectangle2D logicalBounds = gv.getLogicalBounds();
@@ -932,6 +926,12 @@
BasicStroke underlineStroke =
new BasicStroke(underlineThickness);
+ // Not certain what should be done here...
+ // aci.first();
+ // Float dy = (Float) aci.getAttribute(DY);
+ // if (dy != null)
+ // y += dy.floatValue();
+
Rectangle2D logicalBounds = gv.getLogicalBounds();
return underlineStroke.createStrokedShape(
@@ -950,6 +950,12 @@
Stroke strikethroughStroke =
new BasicStroke(strikethroughThickness);
+ // Not certain what should be done here...
+ // aci.first();
+ // Float dy = (Float) aci.getAttribute(DY);
+ // if (dy != null)
+ // y += dy.floatValue();
+
Rectangle2D logicalBounds = gv.getLogicalBounds();
return strikethroughStroke.createStrokedShape(
new java.awt.geom.Line2D.Double(
@@ -957,6 +963,7 @@
logicalBounds.getMaxX() - strikethroughThickness/2.0,
offset.getY()+y));
}
+
/**
* Explicitly lays out each of the glyphs in the glyph
* vector. This will handle any glyph position adjustments such as
@@ -977,9 +984,8 @@
int numGlyphs = gv.getNumGlyphs();
// System.out.println("NumGlyphs: " + numGlyphs);
- float[] gp = gv.getGlyphPositions(0, numGlyphs, null);
+ float[] gp = gv.getGlyphPositions(0, numGlyphs+1, null);
float verticalFirstOffset = 0f;
- float largestAdvanceY = 0;
boolean glyphOrientationAuto = isGlyphOrientationAuto();
int glyphOrientationAngle = 0;
@@ -989,6 +995,7 @@
int i=0, aciIndex = aci.getBeginIndex();
char ch = aci.first();
int runLimit = aciIndex;
+
Float x=null, y=null, dx=null, dy=null, rotation=null;
Object baseline=null;
@@ -1188,6 +1195,8 @@
ch = aci.setIndex(aciIndex);
i++;
}
+ // Update last glyph pos
+ gv.setGlyphPosition(i, new Point2D.Float(curr_x_pos,curr_y_pos));
offset = new Point2D.Float(init_x_pos, init_y_pos);
advance = new Point2D.Float(curr_x_pos - init_x_pos,
@@ -1272,7 +1281,7 @@
float dx = 0f;
float dy = 0f;
- Point2D newPositions[] = new Point2D[numGlyphs];
+ Point2D newPositions[] = new Point2D[numGlyphs+1];
Point2D prevPos = gv.getGlyphPosition(0);
float x = (float) prevPos.getX();
float y = (float) prevPos.getY();
@@ -1284,7 +1293,7 @@
try {
// do letter spacing first
if ((numGlyphs > 1) && (doLetterSpacing || !autoKern)) {
- for (int i=1; i<numGlyphs; ++i) {
+ for (int i=1; i<=numGlyphs; ++i) {
Point2D gpos = gv.getGlyphPosition(i);
dx = (float)gpos.getX()-(float)prevPos.getX();
dy = (float)gpos.getY()-(float)prevPos.getY();
@@ -1310,7 +1319,7 @@
prevPos = gpos;
}
- for (int i=1; i<numGlyphs; ++i) { // assign the new positions
+ for (int i=1; i<=numGlyphs; ++i) { // assign the new positions
if (newPositions[i] != null) {
gv.setGlyphPosition(i, newPositions[i]);
}
@@ -1395,8 +1404,12 @@
}
prevPos = gpos;
}
+ Point2D gPos = gv.getGlyphPosition(numGlyphs);
+ x += (float) (gPos.getX()-prevPos.getX());
+ y += (float) (gPos.getY()-prevPos.getY());
+ newPositions[numGlyphs] = new Point2D.Float(x, y);
- for (int i=1; i<numGlyphs; ++i) { // assign the new positions
+ for (int i=1; i<=numGlyphs; ++i) { // assign the new positions
if (newPositions[i] != null) {
gv.setGlyphPosition(i, newPositions[i]);
}
@@ -1434,16 +1447,16 @@
float initX = (float) bounds.getX();
float initY = (float) bounds.getY();
int numGlyphs = gv.getNumGlyphs();
- float [] gp = gv.getGlyphPositions(0, numGlyphs, null);
+ float [] gp = gv.getGlyphPositions(0, numGlyphs+1, null);
float dx = 0f;
float dy = 0f;
- for (int i = 0; i < numGlyphs; i++) {
+ for (int i = 0; i <= numGlyphs; i++) {
dx = gp[2*i] -initX;
dy = gp[2*i+1]-initY;
gv.setGlyphPosition(i, new Point2D.Float(initX+dx*xScale,
initY+dy*yScale));
- if (stretchGlyphs) {
+ if ((stretchGlyphs) && (i != numGlyphs)) {
// stretch the glyph
AffineTransform glyphTransform = gv.getGlyphTransform(i);
if (glyphTransform != null) {
@@ -1480,6 +1493,7 @@
return;
}
+
boolean horizontal = !isVertical();
boolean glyphOrientationAuto = isGlyphOrientationAuto();
@@ -1766,5 +1780,609 @@
}
}
return glyphOrientationAngle;
+ }
+
+
+ // Issues:
+ // Should the font size of non-printing chars affect line spacing?
+ // Does line breaking get done before/after ligatures?
+ // What should be done if the next glyph does not fit in the
+ // flow rect (very narrow flow rect).
+ // Print the one char anyway.
+ // Go to the next flow rect.
+ // Should dy be considered for line offsets? (super scripts)
+ // Should p's & br's carry over from flow rect to flow rect if
+ // so how much????
+ //
+ // For Full justification:
+ // Streach glyphs to fill line? (attribute?)
+ // What to do with partial line (last line in 'p', 'line'
+ // element, or 'div' element), still full justify, just left
+ // justify, attribute?
+ // What to do when only one glyph on line? left or center or stretch?
+ // For full to look good I think the line must be able to squeeze a
+ // bit as well as grow (pretty easy to add).
+ //
+ // This Only does horizontal languages.
+ // text-decoration won't work on this text.
+ // Soft hyphen isn't handled yet.
+ /**
+ * This will wrap the text associated with <tt>aci</tt> and
+ * <tt>layouts</tt>.
+ * @param aci The Attributed Charater Iterator for text to wrap.
+ * used exclusively to access font information.
+ * @param layouts A List of GlyphLayout objects that are to
+ * be wrapped as a whole.
+ * @param flowRects A List of Rectangle2D representing the regions
+ * to flow text into.
+ * @param brLocs A List of Integer. Each integer indicates the
+ * the aci index of the char after the end of a
+ * br/line element. Note that a particular value can
+ * be repeated several times for sequences of br/line
+ * elements without chars between them.
+ * @param pLocs A List of Integer. Each integer indicates the
+ * the aci index of the char after the end of a
+ * p element. Note that a particular value can be
+ * repeated several times for sequences of p
+ * elements without chars between them.
+ * @param justification an integer in the range: 0-3. 0 is left,
+ * 1 is center, 2 is right, and
+ * 3 is fully justified.
+ */
+ public static void textWrapTextChunk(AttributedCharacterIterator aci,
+ List layouts,
+ List flowRects,
+ List brLocs,
+ List pLocs,
+ int justification) {
+ int aciIndex = aci.getBeginIndex();
+ int aciEnd = aci.getEndIndex();
+
+ char ch = aci.first();
+
+ Iterator iter = layouts.iterator();
+
+ // Make a list of the GlyphVectors so we can construct a
+ // multiGlyphVector that makes them all look like one big
+ // glyphVector
+ List gvs = new LinkedList();
+ while (iter.hasNext()) {
+ GlyphLayout gl = (GlyphLayout)iter.next();
+ gvs.add(gl.getGlyphVector());
+ }
+
+ GVTGlyphVector gv = new MultiGlyphVector(gvs);
+
+ int numGlyphs = gv.getNumGlyphs();
+ float[] gp = gv.getGlyphPositions(0, numGlyphs+1, null);
+
+ if (numGlyphs == 0) return;
+
+ // Now pull the line break locations out into an array so
+ // I can jump around a bit easier.
+ int brIdx = 0;
+ int [] brLoc = new int[brLocs.size()+1];
+ iter = brLocs.iterator();
+ while (iter.hasNext())
+ brLoc[brIdx++] = ((Integer)iter.next()).intValue();
+ brLoc[brIdx] = aciEnd+1;
+ brIdx = 0;
+
+ // Now pull the paragraph break locations out into an array so
+ // I can jump around a bit easier.
+ int pIdx = 0;
+ int [] pLoc = new int[pLocs.size()+1];
+ iter = pLocs.iterator();
+ while (iter.hasNext())
+ pLoc[pIdx++] = ((Integer)iter.next()).intValue();
+ pLoc[pIdx] = aciEnd+1;
+ pIdx = 0;
+
+
+ // Get an iterator for the flow rects.
+ Iterator flowRectsIter = flowRects.iterator();
+ if (!flowRectsIter.hasNext()) {
+ // No place to flow into, hide all glyphs.
+ for (int i=0; i>numGlyphs; i++)
+ gv.setGlyphVisible(i, false);
+ return;
+ }
+
+ // Ok get the info for the first rectangle...
+ Rectangle2D cRect = (Rectangle2D)flowRectsIter.next();
+ float x0 = (float)cRect.getX();
+ float y0 = (float)cRect.getY();
+ float width = (float)cRect.getWidth();
+ float height = (float)cRect.getHeight();
+
+ // Get the font size at the start of the string...
+ float fontSize = 12;
+ Float fsFloat = (Float)aci.getAttributes().get(TextAttribute.SIZE);
+ if (fsFloat != null) {
+ fontSize = fsFloat.floatValue();
+ }
+ // Figure out where the font size might change again...
+ int runLimit = aci.getRunLimit(TEXT_COMPOUND_DELIMITER);
+
+ // This is our current max font size
+ float maxFontSize = fontSize;
+ // This is the font size of the last printing char.
+ float chFontSize = fontSize;
+
+ // Information for backing up to word Break (used when
+ // wrapping normal lines.
+
+ // Glyph index of last break char seen (-1 if no break char on line)
+ int wBreakIdx = -1;
+ // The ACI index of last break char seen.
+ int wBreakACI = -1;
+ // Glyph index of last 'printing' char before last space seen
+ // (needed to do visual justification on glyph bounds).
+ int wBreakChIdx = -1;
+ // The total advance for line including last non-space char.
+ float wBreakAdv = 0;
+ // The total advance for line including spaces at end of line.
+ float wBreakAdj = 0;
+ // The font size at last space seen.
+ float wBreakFontSize = fontSize;
+ // The runLimit (for fonts) at last space seen.
+ int wBreakRunLimit = runLimit;
+ // The max font size since last space seen (printable chars only).
+ float wBreakMaxFontSize = maxFontSize;
+
+ // Information for backing up to line start.
+ // This is needed when we reach the end of a
+ // line and realize it doesn't fit in the
+ // current rect.
+ // Glyph Index of first char on current line.
+ int lBreakIdx = -1;
+ // ACI Index of first char on current line.
+ int lBreakACI = -1;
+ // font size at start of line
+ float lBreakFontSize = fontSize;
+ // runLimit (for font size) at start of line.
+ int lBreakRunLimit = runLimit;
+ // The index into the brLoc array at start of line
+ int lBreakBrIdx = 0;
+ // The index into the pLoc array at start of line
+ int lBreakPIdx = 0;
+
+ // Offset from top of current rect for baseline.
+ float dy = 0;
+ // Printing char advance on line so far.
+ float adv = 0;
+ // Advance of current char plus any leading non-printing chars.
+ float chAdv = 0;
+ // GlyphIndex of last printing char seen
+ // (used for full justification on glyph bounds).
+ int lastChar = 0;
+ // The descent from previous line we need to incorporate
+ float prevDesc = 0;
+
+
+ // Used to know if we are doing the first glyph after line start.
+ int lineStart = 0;
+
+ // Per-line information lists. Used after line breaks have
+ // been decided upon.
+ List lineStarts = new LinkedList(); // glyph index of line starts
+ List lineLocs = new LinkedList(); // Point2D of line start.
+ List lineAdvs = new LinkedList(); // Visual width of line.
+ List lineAdjs = new LinkedList(); // x Offset for line
+ List lineLastCharW = new LinkedList(); // used in full justification.
+ List linePartial = new LinkedList(); // should line be justified?
+
+ lineStarts.add(new Integer(0));
+ int i;
+ boolean chIsSpace = isSpace(ch);
+ boolean partial = false;
+ float nextLineMult = 1.0f;
+ float lineMult = 1.0f;
+
+ // Let's start looking at glyphs....
+ for (i=0; i<numGlyphs; i++) {
+
+ // Update font size for this char if needed.
+ if (aciIndex >= runLimit) {
+ runLimit = aci.getRunLimit(TEXT_COMPOUND_DELIMITER);
+ fsFloat = (Float)aci.getAttributes().get(TextAttribute.SIZE);
+ if (fsFloat != null) {
+ fontSize = fsFloat.floatValue();
+ } else {
+ fontSize = 12;
+ }
+ // System.out.println("ACI: " + aciIndex +
+ // " runLimit: " + runLimit +
+ // " FS: " + fontSize);
+ }
+
+ // Get advance for this glyph...
+ float gmAdv = gp[2*i+2] - gp[2*i];
+
+ // Add to the 'Char adv' which includes any non printing
+ // chars before this char.
+ chAdv += gmAdv;
+
+ // System.out.println("Ch : '" + ch + "' Idx: " + aciIndex);
+
+ // If it's a space remeber it as a breaking location but
+ // don't check for line break yet (wait till non-space char).
+ if (chIsSpace) {
+ wBreakIdx = i;
+ wBreakChIdx = lastChar;
+ wBreakACI = aciIndex;
+ wBreakAdv = adv;
+ wBreakAdj = adv+chAdv;
+ wBreakFontSize = fontSize;
+ wBreakRunLimit = runLimit;
+
+ // New break loc so incorporate wBreakMaxFontSize
+ if (wBreakMaxFontSize > maxFontSize)
+ maxFontSize = wBreakMaxFontSize;
+
+ wBreakMaxFontSize = chFontSize;
+ }
+
+ if (!chIsSpace) {
+ // Ok we are a printing char so include all the
+ // advaces we have collected.
+ adv += chAdv;
+
+ // Remember the size of this char...
+ chFontSize = fontSize;
+ }
+
+ boolean doBreak = false;
+
+ // Don't break at first char in line
+ // (otherwise nothing will ever get drawn).
+ if (!chIsSpace &&
+ (lineStart != i) &&
+ (adv > width)
+ ) {
+
+ // Better logic for wrap (allow it to squeeze upto 1/2 as
+ // much as it would streatch if word wrapped).
+ // (((wBreakIdx == -1) && (adv > width)) || // no break avail
+ // (adv-width > (width-wBreakAdv)*.5))
+
+
+
+ if (wBreakIdx == -1) {
+ // Break in the middle of word. Back out gmAdv
+ // since it will be used on the next line.
+ wBreakAdv = adv-gmAdv;
+ wBreakAdj = adv-gmAdv;
+ wBreakChIdx = lastChar;
+
+ i--; // reconsider letter (will get inc'd later).
+
+ // Include max font since last break char in max calc.
+ if (wBreakMaxFontSize > maxFontSize)
+ maxFontSize = wBreakMaxFontSize;
+ } else {
+ // We have a break char to back up to.
+ // Reset state to just after breaking chars.
+ i = wBreakIdx;
+ aciIndex = wBreakACI;
+ fontSize = wBreakFontSize;
+ chFontSize = wBreakFontSize;
+ runLimit = wBreakRunLimit;
+
+ aciIndex += gv.getCharacterCount(i,i);
+ ch = aci.setIndex(aciIndex);
+ chIsSpace = isSpace(ch);
+ }
+
+ nextLineMult = 1.0f;
+ doBreak = true;
+ partial = false;
+ }
+
+ // Track how many p's and br's we hit here.
+ int pCount = 0;
+ int brCount = 0;
+ // did we just pass a p or br?
+ if ((aciIndex >= pLoc [pIdx]) ||
+ (aciIndex >= brLoc[brIdx])) {
+
+ // Count the P's here...
+ while (aciIndex >= pLoc[pIdx]) {
+ pIdx++;
+ pCount++;
+ nextLineMult += 1.5;
+ }
+
+ // Count the br's here...
+ while (aciIndex >= brLoc[brIdx]) {
+ brIdx++;
+ brCount++;
+ nextLineMult += 1.0;
+ }
+
+ if (doBreak) {
+ // If we were going to word wrap here anyway
+ // Don't double space...
+ nextLineMult -= 1.0f;
+ } else {
+ // We need to specify the break
+ if (chIsSpace) {
+ wBreakAdv = adv;
+ wBreakAdj = adv+(chAdv-gmAdv);
+ } else {
+ // If a char with prior spaces then keep
+ // spaces on prev line and char on this line...
+ wBreakAdv = adv-gmAdv;
+ wBreakAdj = adv-gmAdv;
+ }
+
+ wBreakChIdx = lastChar;
+
+ i--; // reconsider letter.
+
+ // Include max font since break as max.
+ if (wBreakMaxFontSize > maxFontSize)
+ maxFontSize = wBreakMaxFontSize;
+ }
+
+ doBreak = true;
+ partial = true;
+ }
+
+
+ if (doBreak) {
+ // We will now attempt to break the line just
+ // before the current char.
+
+ // Note we are trying to figure out where the current
+ // line is going to be placed (not the next line). We
+ // must wait until we have a potential line break so
+ // we know how tall the line is.
+
+ // Get the nomial line advance based on the
+ // largest font we encountered on line...
+ float ladv = (maxFontSize*.8f+prevDesc)*1.1f;
+
+ // This is modified by any p's or br's we hit at
+ // the end of the last line.
+ dy += ladv*lineMult;
+
+ // Remember the effect of p's br's at the end of this line.
+ lineMult = nextLineMult;
+
+ // Set ourself up for next line...
+ nextLineMult = 0.0f;
+
+ // System.out.println("Break L [" + lineStart + "," + i +
+ // "] Loc: " + (y0+dy) +
+ // " adv: " + wBreakAdv +
+ // " adj: " + wBreakAdj);
+
+ if ((dy + maxFontSize*.2f) <= height) {
+ // The line fits in the current flow rectangle.
+
+ // System.out.println("Fits: " + (dy + maxFontSize*.2f));
+
+
+ // Now remember info about start of next line.
+ // (needed so we can back up if that line doesn't
+ // fit in current rectangle).
+ lBreakIdx = i+1;
+ lBreakACI = aciIndex;
+ lBreakFontSize = fontSize;
+ lBreakRunLimit = runLimit;
+ lBreakPIdx = pIdx;
+ lBreakBrIdx = brIdx;
+
+ // Now we tweak line advance to account for
+ // visual bounds of last glyph.
+ Rectangle2D lastCharB = gv.getGlyphVisualBounds
+ (wBreakChIdx).getBounds2D();
+ Point2D lastCharL = gv.getGlyphPosition
+ (wBreakChIdx);
+ float charW = (float)
+ (lastCharB.getX()+lastCharB.getWidth()-
+ lastCharL.getX());
+ float charAdv = gp[2*wBreakChIdx+2]-gp[2*wBreakChIdx];
+ wBreakAdv -= charAdv-charW;
+
+ // Add all the info about the current line to lists.
+ lineLocs.add (new Point2D.Float(x0, y0+dy));
+ lineAdvs.add (new Float(wBreakAdv));
+ lineAdjs.add (new Float(wBreakAdj));
+ lineLastCharW.add (new Float(charW));
+ linePartial.add(new Boolean(partial));
+
+ // Remember where next line starts.
+ lineStart = i+1;
+ lineStarts.add (new Integer(lineStart));
+
+ // Remember how far down this line goes into
+ // next line.
+ prevDesc = maxFontSize*.2f;
+ } else {
+ // The current line doesn't fit in the current
+ // flow rectangle so we need to go move line to
+ // the next flow rectangle.
+
+ // System.out.println("Doesn't Fit: " +
+ // (dy + maxFontSize*.2f));
+
+
+ if (!flowRectsIter.hasNext())
+ break; // No flow rect stop layout here...
+
+ // Remember how wide this rectangle is...
+ float oldWidth = width;
+
+ // Get info for new flow rect.
+ cRect = (Rectangle2D)flowRectsIter.next();
+ x0 = (float)cRect.getX();
+ y0 = (float)cRect.getY();
+ width = (float)cRect.getWidth();
+ height = (float)cRect.getHeight();
+
+ // New rect so no previous row to consider...
+ dy = 0;
+ prevDesc = 0;
+ lineMult = 1.0f; // don't pile up lineMults from
+ // previous flows?
+
+ if (cRect.getWidth() >= oldWidth) {
+ // new rect is same width or wider so
+ // we can reuse our work on this line.
+
+ // Just undo anything we added in
+ if (!chIsSpace)
+ adv -= chAdv;
+
+ chAdv -= gmAdv;
+ // Unadvance p's and br's for this char...
+ pIdx -= pCount;
+ brIdx -= brCount;
+ continue;
+ }
+
+ // new rect is smaller so back up to line start
+ // and try with new flow rect.
+ i = lBreakIdx-1; // loop will inc...
+ aciIndex = lBreakACI;
+ fontSize = lBreakFontSize;
+ chFontSize = lBreakFontSize;
+ runLimit = lBreakRunLimit;
+ pIdx = lBreakPIdx;
+ brIdx = lBreakBrIdx;
+
+ ch = aci.setIndex(aciIndex);
+ chIsSpace = isSpace(ch);
+ }
+
+ // Set fontSize max's to last printing char size.
+ maxFontSize = chFontSize;
+ wBreakMaxFontSize = chFontSize;
+
+ // New line so reset line advance info.
+ adv=0;
+ chAdv=0;
+ wBreakIdx = -1;
+ continue;
+ }
+
+ if (!chIsSpace) {
+ // Don't include spaces in max font size calc.
+ if (chFontSize > wBreakMaxFontSize) {
+ wBreakMaxFontSize = chFontSize;
+ }
+
+ // Remember this as last non-space char...
+ lastChar = i;
+
+ // Reset char advance (incorporated into adv above).
+ chAdv = 0;
+ }
+
+ // Increment everything for ext char...
+ aciIndex += gv.getCharacterCount(i,i);
+ ch = aci.setIndex(aciIndex);
+ chIsSpace = isSpace(ch);
+ }
+
+ // Include max font since break char in max.
+ if (wBreakMaxFontSize > maxFontSize)
+ maxFontSize = wBreakMaxFontSize;
+ dy += (maxFontSize*.8f+prevDesc)*1.1f;
+ if ((dy + .2f*maxFontSize) >= height) {
+ // Last line of text didn't fit...
+ i = lineStart;
+ } else {
+ Rectangle2D lastCharB = gv.getGlyphVisualBounds
+ (lastChar).getBounds2D();
+ Point2D lastCharL = gv.getGlyphPosition(lastChar);
+ float charW = (float)
+ (lastCharB.getX()+lastCharB.getWidth()-
+ lastCharL.getX());
+ float charAdv = gp[2*lastChar+2]-gp[2*lastChar];
+
+ lineStarts.add (new Integer(i));
+ lineLocs.add (new Point2D.Float(x0, y0+dy));
+ lineAdvs.add (new Float(adv-(charAdv-charW)));
+ lineAdjs.add (new Float(adv+chAdv));
+ lineLastCharW.add (new Float(charW));
+ linePartial.add(new Boolean(true));
+ }
+
+ // ignore any glyphs i+ (didn't fit in rects.)
+ for (int j=i; j<numGlyphs; j++)
+ gv.setGlyphVisible(j, false);
+
+ // Limit ourselves to i glyphs...
+ numGlyphs = i;
+
+
+ Iterator lStartIter =lineStarts.iterator();
+ Iterator lLocIter =lineLocs.iterator();
+ Iterator lAdvIter =lineAdvs.iterator();
+ Iterator lAdjIter =lineAdjs.iterator();
+ Iterator lLastCharWIter=lineLastCharW.iterator();
+ Iterator lPartIter =linePartial.iterator();
+
+ lineStart = ((Integer)lStartIter.next()).intValue();
+ Point2D.Float lineLoc = null;
+ float lineAdv = 0;
+ float lineAdj = 0;
+
+ float xOrig=gp[0];
+ float yOrig=gp[1];
+
+ float xScale=1;
+ float xAdj=0;
+ float charW;
+
+ // This loop goes through and puts glyphs where they belong
+ // based on info collected in first trip through glyphVector...
+ i =0;
+ for (; i<numGlyphs; i++) {
+ if (i == lineStart) {
+ // Always comes through here on first char...
+
+ // Update offset for new line based on last line length
+ xOrig += lineAdj;
+
+ // Get new values for everything...
+ lineStart = ((Integer)lStartIter.next()).intValue();
+ lineLoc = (Point2D.Float)lLocIter.next();
+ lineAdv = ( (Float)lAdvIter.next()) .floatValue();
+ lineAdj = ( (Float)lAdjIter.next()) .floatValue();
+ charW = ( (Float)lLastCharWIter.next()) .floatValue();
+ partial = ((Boolean)lPartIter.next()) .booleanValue();
+
+ xAdj = 0;
+ xScale = 1;
+ // Recalc justification info.
+ switch (justification) {
+ case 0: default: break; // Left
+ case 1: xAdj = (width-lineAdv)/2; break; // Center
+ case 2: xAdj = width-lineAdv; break; // Right
+ case 3: // Full
+ if ((!partial) && (lineStart != i+1)) {
+ // More than one char on line...
+ // Scale char spacing to fill line.
+ xScale = (width-charW)/(lineAdv-charW);
+ }
+ break;
+ }
+ }
+ float x = lineLoc.x + (gp[2*i] -xOrig)*xScale+xAdj;
+ float y = lineLoc.y + (gp[2*i+1]-yOrig);
+ gv.setGlyphPosition(i, new Point2D.Float(x, y));
+ }
+
+ float x = lineLoc.x + (gp[2*i] -xOrig)*xScale+xAdj;
+ float y = lineLoc.y + (gp[2*i+1]-yOrig);
+ gv.setGlyphPosition(i, new Point2D.Float(x, y));
+ }
+
+ protected static boolean isSpace(char ch) {
+ return ((ch == ' ') || (ch == '\t'));
}
}
1.37 +41 -3
xml-batik/sources/org/apache/batik/transcoder/image/ImageTranscoder.java
Index: ImageTranscoder.java
===================================================================
RCS file:
/home/cvs/xml-batik/sources/org/apache/batik/transcoder/image/ImageTranscoder.java,v
retrieving revision 1.36
retrieving revision 1.37
diff -u -r1.36 -r1.37
--- ImageTranscoder.java 6 Mar 2002 17:14:45 -0000 1.36
+++ ImageTranscoder.java 7 Mar 2002 22:07:44 -0000 1.37
@@ -101,7 +101,7 @@
* millimeter conversion factor.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Thierry Kormann</a>
- * @version $Id: ImageTranscoder.java,v 1.36 2002/03/06 17:14:45 tkormann Exp $
+ * @version $Id: ImageTranscoder.java,v 1.37 2002/03/07 22:07:44 deweese Exp $
*/
public abstract class ImageTranscoder extends XMLAbstractTranscoder {
@@ -247,8 +247,8 @@
Px.preConcatenate(Mx);
}
// prepare the image to be painted
- int w = (int)width;
- int h = (int)height;
+ int w = (int)(width+0.5);
+ int h = (int)(height+0.5);
// paint the SVG document using the bridge package
// create the appropriate renderer
@@ -751,4 +751,42 @@
public static final TranscodingHints.Key KEY_BACKGROUND_COLOR
= new PaintKey();
+ /**
+ * The forceTransparentWhite key.
+ *
+ * <TABLE BORDER="0" CELLSPACING="0" CELLPADDING="1">
+ * <TR>
+ * <TH VALIGN="TOP" ALIGN="RIGHT"><P ALIGN="RIGHT">Key: </TH>
+ * <TD VALIGN="TOP">KEY_FORCE_TRANSPARENT_WHITE</TD></TR>
+ * <TR>
+ * <TH VALIGN="TOP" ALIGN="RIGHT"><P ALIGN="RIGHT">Value: </TH>
+ * <TD VALIGN="TOP">Boolean</TD></TR>
+ * <TR>
+ * <TH VALIGN="TOP" ALIGN="RIGHT"><P ALIGN="RIGHT">Default: </TH>
+ * <TD VALIGN="TOP">false</TD></TR>
+ * <TR>
+ * <TH VALIGN="TOP" ALIGN="RIGHT"><P ALIGN="RIGHT">Required: </TH>
+ * <TD VALIGN="TOP">No</TD></TR>
+ * <TR>
+ * <TH VALIGN="TOP" ALIGN="RIGHT"><P ALIGN="RIGHT">Description: </TH>
+
+ * <TD VALIGN="TOP">It controls whether the encoder should force
+ * the image's fully transparent pixels to be fully transparent
+ * white instead of fully transparent black. This is usefull when
+ * the encoded file is displayed in a browser which does not
+ * support transparency correctly and lets the image display with
+ * a white background instead of a black background. <br />
+ *
+ * However, note that the modified image will display differently
+ * over a white background in a viewer that supports
+ * transparency.<br/>
+ *
+ * Not all Transcoders use this key (in particular some formats
+ * can't preserve the alpha channel at all in which case this
+ * is not used.
+ * </TD></TR>
+ * </TABLE>
+ */
+ public static final TranscodingHints.Key KEY_FORCE_TRANSPARENT_WHITE
+ = new BooleanKey();
}
1.12 +2 -2
xml-batik/sources/org/apache/batik/transcoder/image/PNGTranscoder.java
Index: PNGTranscoder.java
===================================================================
RCS file:
/home/cvs/xml-batik/sources/org/apache/batik/transcoder/image/PNGTranscoder.java,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -r1.11 -r1.12
--- PNGTranscoder.java 11 Feb 2002 18:03:42 -0000 1.11
+++ PNGTranscoder.java 7 Mar 2002 22:07:44 -0000 1.12
@@ -26,7 +26,7 @@
* This class is an <tt>ImageTranscoder</tt> that produces a PNG image.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Thierry Kormann</a>
- * @version $Id: PNGTranscoder.java,v 1.11 2002/02/11 18:03:42 deweese Exp $
+ * @version $Id: PNGTranscoder.java,v 1.12 2002/03/07 22:07:44 deweese Exp $
*/
public class PNGTranscoder extends ImageTranscoder {
@@ -158,7 +158,7 @@
* </TABLE>
*/
public static final TranscodingHints.Key KEY_FORCE_TRANSPARENT_WHITE
- = new BooleanKey();
+ = ImageTranscoder.KEY_FORCE_TRANSPARENT_WHITE;
/**
* The gamma correction key.
1.2 +111 -30
xml-batik/sources/org/apache/batik/transcoder/image/TIFFTranscoder.java
Index: TIFFTranscoder.java
===================================================================
RCS file:
/home/cvs/xml-batik/sources/org/apache/batik/transcoder/image/TIFFTranscoder.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- TIFFTranscoder.java 16 May 2001 12:34:16 -0000 1.1
+++ TIFFTranscoder.java 7 Mar 2002 22:07:44 -0000 1.2
@@ -24,6 +24,8 @@
import org.apache.batik.transcoder.image.resources.Messages;
import org.apache.batik.ext.awt.image.codec.tiff.TIFFEncodeParam;
import org.apache.batik.ext.awt.image.codec.tiff.TIFFImageEncoder;
+import org.apache.batik.ext.awt.image.codec.tiff.TIFFImageDecoder;
+import org.apache.batik.ext.awt.image.codec.tiff.TIFFField;
import org.apache.batik.ext.awt.image.rendered.FormatRed;
import org.apache.batik.ext.awt.image.GraphicsUtil;
@@ -32,14 +34,16 @@
* This class is an <tt>ImageTranscoder</tt> that produces a TIFF image.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Thierry Kormann</a>
- * @version $Id: TIFFTranscoder.java,v 1.1 2001/05/16 12:34:16 deweese Exp $
+ * @version $Id: TIFFTranscoder.java,v 1.2 2002/03/07 22:07:44 deweese Exp $
*/
public class TIFFTranscoder extends ImageTranscoder {
/**
* Constructs a new transcoder that produces tiff images.
*/
- public TIFFTranscoder() { }
+ public TIFFTranscoder() {
+ hints.put(KEY_FORCE_TRANSPARENT_WHITE, Boolean.FALSE);
+ }
/**
* Creates a new ARGB image with the specified dimension.
@@ -64,41 +68,78 @@
throw new TranscoderException(
Messages.formatMessage("tiff.badoutput", null));
}
+
TIFFEncodeParam params = new TIFFEncodeParam();
+ float pixToMM = userAgent.getPixelToMM();
+ // Pixs in 100 Meters
+ int numPix = (int)(pixToMM*(1000*100)+0.5);
+ int denom = 100*100; // Centimeters per 100 Meters;
+ long [] rational = {(long)numPix, (long)denom};
+ TIFFField [] fields = {
+ new TIFFField(TIFFImageDecoder.TIFF_RESOLUTION_UNIT,
+ TIFFField.TIFF_SHORT, 1,
+ new char [] { (char)3 }),
+ new TIFFField(TIFFImageDecoder.TIFF_X_RESOLUTION,
+ TIFFField.TIFF_RATIONAL, 1,
+ new long [][] { rational }),
+ new TIFFField(TIFFImageDecoder.TIFF_Y_RESOLUTION,
+ TIFFField.TIFF_RATIONAL, 1,
+ new long [][] { rational })
+ };
+
+ params.setExtraFields(fields);
+
//
- // This is a trick so that viewers which do not support
- // the alpha channel will see a white background (and not
- // a black one).
+ // This is a trick so that viewers which do not support the alpha
+ // channel will see a white background (and not a black one).
//
- int w = img.getWidth(), h = img.getHeight();
- DataBufferInt biDB = (DataBufferInt)img.getRaster().getDataBuffer();
+ boolean forceTransparentWhite = false;
+
+ if (hints.containsKey(KEY_FORCE_TRANSPARENT_WHITE)) {
+ forceTransparentWhite =
+ ((Boolean)hints.get
+ (KEY_FORCE_TRANSPARENT_WHITE)).booleanValue();
+ }
+
+ int w = img.getWidth();
+ int h = img.getHeight();
SinglePixelPackedSampleModel sppsm;
sppsm = (SinglePixelPackedSampleModel)img.getSampleModel();
- int scanStride = sppsm.getScanlineStride();
- int dbOffset = biDB.getOffset();
- int pixels[] = biDB.getBankData()[0];
- int p = dbOffset;
- int adjust = scanStride - w;
- int a=0, r=0, g=0, b=0, pel=0;
- for(int i=0; i<h; i++){
- for(int j=0; j<w; j++){
- pel = pixels[p];
- a = (pel >> 24) & 0xff;
- r = (pel >> 16) & 0xff;
- g = (pel >> 8 ) & 0xff;
- b = pel & 0xff;
- r = (255*(255 -a) + a*r)/255;
- g = (255*(255 -a) + a*g)/255;
- b = (255*(255 -a) + a*b)/255;
- pixels[p++] =
- (a<<24 & 0xff000000) |
- (r<<16 & 0xff0000) |
- (g<<8 & 0xff00) |
- (b & 0xff);
- }
- p += adjust;
+
+ if (forceTransparentWhite) {
+ //
+ // This is a trick so that viewers which do not support
+ // the alpha channel will see a white background (and not
+ // a black one).
+ //
+ DataBufferInt biDB=(DataBufferInt)img.getRaster().getDataBuffer();
+ int scanStride = sppsm.getScanlineStride();
+ int dbOffset = biDB.getOffset();
+ int pixels[] = biDB.getBankData()[0];
+ int p = dbOffset;
+ int adjust = scanStride - w;
+ int a=0, r=0, g=0, b=0, pel=0;
+ for(int i=0; i<h; i++){
+ for(int j=0; j<w; j++){
+ pel = pixels[p];
+ a = (pel >> 24) & 0xff;
+ r = (pel >> 16) & 0xff;
+ g = (pel >> 8 ) & 0xff;
+ b = pel & 0xff;
+ r = (255*(255 -a) + a*r)/255;
+ g = (255*(255 -a) + a*g)/255;
+ b = (255*(255 -a) + a*b)/255;
+ pixels[p++] =
+ (a<<24 & 0xff000000) |
+ (r<<16 & 0xff0000) |
+ (g<<8 & 0xff00) |
+ (b & 0xff);
+ }
+ p += adjust;
+ }
}
+
try {
TIFFImageEncoder tiffEncoder =
new TIFFImageEncoder(ostream, params);
@@ -112,7 +153,47 @@
RenderedImage rimg = new FormatRed(GraphicsUtil.wrap(img), sm);
tiffEncoder.encode(rimg);
} catch (IOException ex) {
+ ex.printStackTrace();
throw new TranscoderException(ex);
}
}
+
+
+ // --------------------------------------------------------------------
+ // Keys definition
+ // --------------------------------------------------------------------
+
+ /**
+ * The forceTransparentWhite key.
+ *
+ * <TABLE BORDER="0" CELLSPACING="0" CELLPADDING="1">
+ * <TR>
+ * <TH VALIGN="TOP" ALIGN="RIGHT"><P ALIGN="RIGHT">Key: </TH>
+ * <TD VALIGN="TOP">KEY_FORCE_TRANSPARENT_WHITE</TD></TR>
+ * <TR>
+ * <TH VALIGN="TOP" ALIGN="RIGHT"><P ALIGN="RIGHT">Value: </TH>
+ * <TD VALIGN="TOP">Boolean</TD></TR>
+ * <TR>
+ * <TH VALIGN="TOP" ALIGN="RIGHT"><P ALIGN="RIGHT">Default: </TH>
+ * <TD VALIGN="TOP">false</TD></TR>
+ * <TR>
+ * <TH VALIGN="TOP" ALIGN="RIGHT"><P ALIGN="RIGHT">Required: </TH>
+ * <TD VALIGN="TOP">No</TD></TR>
+ * <TR>
+ * <TH VALIGN="TOP" ALIGN="RIGHT"><P ALIGN="RIGHT">Description: </TH>
+ * <TD VALIGN="TOP">It controls whether the encoder should
+ * force the image's fully transparent pixels to be fully transparent
+ * white instead of fully transparent black. This is usefull when the
+ * encoded TIFF is displayed in a viewer which does not support TIFF
+ * transparency and lets the image display with a white background instead
+ * of a black background. <br />
+ *
+ * However, note that the modified image will display differently
+ * over a white background in a viewer that supports
+ * transparency.</TD></TR>
+ * </TABLE>
+ */
+ public static final TranscodingHints.Key KEY_FORCE_TRANSPARENT_WHITE
+ = ImageTranscoder.KEY_FORCE_TRANSPARENT_WHITE;
+
}
1.1
xml-batik/test-references/samples/tests/spec/scripting/.cvsignore
Index: .cvsignore
===================================================================
accepted-variation
candidate-reference
candidate-variation
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]