Author: tilman
Date: Sat Feb 8 15:41:03 2014
New Revision: 1566032
URL: http://svn.apache.org/r1566032
Log:
PDFBOX-1887: Bugfixes + Optimization of Gouraud Shading
Modified:
pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/GouraudShadingContext.java
pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/GouraudTriangle.java
Modified:
pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/GouraudShadingContext.java
URL:
http://svn.apache.org/viewvc/pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/GouraudShadingContext.java?rev=1566032&r1=1566031&r2=1566032&view=diff
==============================================================================
---
pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/GouraudShadingContext.java
(original)
+++
pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/GouraudShadingContext.java
Sat Feb 8 15:41:03 2014
@@ -152,7 +152,7 @@ public abstract class GouraudShadingCont
*
* @throws IOException if something went wrong
*/
- protected Vertex readVertex(ImageInputStream input, byte flag, long
maxSrcCoord, long maxSrcColor,
+ protected Vertex readVertex(ImageInputStream input, byte flag, long
maxSrcCoord, long maxSrcColor,
PDRange rangeX, PDRange rangeY, PDRange[] colRangeTab) throws
IOException
{
float[] colorComponentTab = new float[numberOfColorComponents];
@@ -165,7 +165,7 @@ public abstract class GouraudShadingCont
{
int color = (int) input.readBits(bitsPerColorComponent);
colorComponentTab[n] = interpolate(color, maxSrcColor,
colRangeTab[n].getMin(), colRangeTab[n].getMax());
- LOG.debug("color[" + n + "]: " + color + "/" +
String.format("%02x", color)
+ LOG.debug("color[" + n + "]: " + color + "/" +
String.format("%02x", color)
+ "-> color[" + n + "]: " + colorComponentTab[n]);
}
return new Vertex(flag, new Point2D.Double(dstX, dstY),
colorComponentTab);
@@ -192,8 +192,6 @@ public abstract class GouraudShadingCont
// transform from shading to user space
ctm.createAffineTransform().transform(v.point, v.point);
// transform from user to device space
- // move the 0,0-reference including the y-translation from
user to device space
- v.point.setLocation(v.point.getX(), pageHeight -
v.point.getY());
xform.transform(v.point, v.point);
}
else
@@ -222,6 +220,7 @@ public abstract class GouraudShadingCont
/**
* {@inheritDoc}
*/
+ @Override
public void dispose()
{
triangleList = null;
@@ -234,6 +233,7 @@ public abstract class GouraudShadingCont
/**
* {@inheritDoc}
*/
+ @Override
public final ColorModel getColorModel()
{
return outputColorModel;
@@ -248,7 +248,7 @@ public abstract class GouraudShadingCont
* @param dstMax max dst value
* @return interpolated value
*/
- private float interpolate(float src, float srcMax, float dstMin, float
dstMax)
+ private float interpolate(float src, long srcMax, float dstMin, float
dstMax)
{
return dstMin + (src * (dstMax - dstMin) / srcMax);
}
@@ -256,71 +256,72 @@ public abstract class GouraudShadingCont
/**
* {@inheritDoc}
*/
+ @Override
public final Raster getRaster(int x, int y, int w, int h)
{
- float[] values = new float[numberOfColorComponents];
WritableRaster raster =
getColorModel().createCompatibleWritableRaster(w, h);
- if (!triangleList.isEmpty())
+ int[] data = new int[w * h * 4];
+ for (int row = 0; row < h; row++)
{
- int[] data = new int[w * h * 4];
- for (int row = 0; row < h; row++)
+ for (int col = 0; col < w; col++)
{
- for (int col = 0; col < w; col++)
+ Point2D p = new Point(x + col, y + row);
+ GouraudTriangle triangle = null;
+ for (GouraudTriangle tryTriangle : triangleList)
+ {
+ if (tryTriangle.contains(p))
+ {
+ triangle = tryTriangle;
+ break;
+ }
+ }
+ float[] values;
+ if (triangle != null)
{
- Point2D p = new Point(x + col, y + row);
+ double[] weights = triangle.getWeights(p);
+ values = new float[numberOfColorComponents];
+ for (int i = 0; i < numberOfColorComponents; ++i)
+ {
+ values[i] = (float) (triangle.colorA[i] * weights[0]
+ + triangle.colorB[i] * weights[1]
+ + triangle.colorC[i] * weights[2]);
+ }
+ }
+ else
+ {
+ if (background != null)
+ {
+ values = background;
+ }
+ else
+ {
+ continue;
+ }
+ }
- //TODO test optmization after ch14.pdf works:
- // check whether point is in combined java area
- for (GouraudTriangle triangle : triangleList)
+ //TODO handle function
+ // convert color values from shading colorspace to RGB
+ if (shadingColorSpace != null)
+ {
+ if (shadingTinttransform != null)
{
- if (triangle.contains(p))
- {
- double[] weights = triangle.getWeights(p);
- for (int i = 0; i < numberOfColorComponents; ++i)
- {
- values[i] = (float) (triangle.colorA[i] *
weights[0] + triangle.colorB[i] * weights[1]
- + triangle.colorC[i] * weights[2]);
- }
- //TODO optimize: quit loop when triangle is found
- }
- else
+ try
{
- if (background != null)
- {
- values = background;
- }
- else
- {
- continue;
- }
+ values = shadingTinttransform.eval(values);
}
-
- //TODO handle function
- // convert color values from shading colorspace to RGB
- if (shadingColorSpace != null)
+ catch (IOException exception)
{
- if (shadingTinttransform != null)
- {
- try
- {
- values = shadingTinttransform.eval(values);
- }
- catch (IOException exception)
- {
- LOG.error("error while processing a
function", exception);
- }
- }
- values = shadingColorSpace.toRGB(values);
+ LOG.error("error while processing a function",
exception);
}
-
- int index = (row * w + col) * 4;
- data[index] = (int) (values[0] * 255);
- data[index + 1] = (int) (values[1] * 255);
- data[index + 2] = (int) (values[2] * 255);
- data[index + 3] = 255;
}
-
+ values = shadingColorSpace.toRGB(values);
}
+
+ int index = (row * w + col) * 4;
+ data[index] = (int) (values[0] * 255);
+ data[index + 1] = (int) (values[1] * 255);
+ data[index + 2] = (int) (values[2] * 255);
+ data[index + 3] = 255;
}
raster.setPixels(0, 0, w, h, data);
}
Modified:
pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/GouraudTriangle.java
URL:
http://svn.apache.org/viewvc/pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/GouraudTriangle.java?rev=1566032&r1=1566031&r2=1566032&view=diff
==============================================================================
---
pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/GouraudTriangle.java
(original)
+++
pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/shading/GouraudTriangle.java
Sat Feb 8 15:41:03 2014
@@ -22,7 +22,7 @@ import java.awt.geom.Point2D;
/**
* Helper class to deal with Gouraud triangles for type 4 and 5 shading.
- *
+ *
* @author Tilman Hausherr
*/
public class GouraudTriangle
@@ -31,34 +31,45 @@ public class GouraudTriangle
* the polygon representing the triangle.
*/
protected final Polygon polygon = new Polygon();
- /**
+ /**
* point A of the triangle.
*/
protected final Point2D pointA;
- /**
+ /**
* point B of the triangle.
*/
protected final Point2D pointB;
- /**
+ /**
* point C of the triangle.
*/
protected final Point2D pointC;
- /**
+ /**
* the color of point A.
*/
protected final float[] colorA;
- /**
+ /**
* the color of point B.
*/
protected final float[] colorB;
- /**
+ /**
* the color of point C.
*/
protected final float[] colorC;
-
-
+
+ /*
+ * intermediate constants
+ */
+ private final double xBminusA;
+ private final double yBminusA;
+ private final double xCminusA;
+ private final double yCminusA;
+ private final double xCminusB;
+ private final double yCminusB;
+ private final double area;
+
/**
* Constructor for using 3 points and their colors.
+ *
* @param a point A of the triangle
* @param aColor color of point A
* @param b point B of the triangle
@@ -74,6 +85,16 @@ public class GouraudTriangle
colorA = aColor;
colorB = bColor;
colorC = cColor;
+
+ // calculate constants
+ xBminusA = pointB.getX() - pointA.getX();
+ yBminusA = pointB.getY() - pointA.getY();
+ xCminusA = pointC.getX() - pointA.getX();
+ yCminusA = pointC.getY() - pointA.getY();
+ xCminusB = pointC.getX() - pointB.getX();
+ yCminusB = pointC.getY() - pointB.getY();
+ area = getArea(pointA, pointB, pointC);
+
polygon.addPoint((int) Math.round(a.getX()), (int)
Math.round(a.getY()));
polygon.addPoint((int) Math.round(b.getX()), (int)
Math.round(b.getY()));
polygon.addPoint((int) Math.round(c.getX()), (int)
Math.round(c.getY()));
@@ -81,17 +102,36 @@ public class GouraudTriangle
/**
* Check whether the point is within the triangle.
- *
+ *
* @param p Point
- *
+ *
* @return true if yes, false if no
*/
public boolean contains(Point2D p)
{
- // if there is ever a need to optimize, go here
+ // inspiration:
// http://stackoverflow.com/a/9755252/535646
+ // see also:
// http://math.stackexchange.com/q/51326
- return polygon.contains(p);
+ //
http://www.gamedev.net/topic/295943-is-this-a-better-point-in-triangle-test-2d/
+ // java function can't be used because polygon takes integer
coordinates
+
+ double xPminusA = p.getX() - pointA.getX();
+ double yPminusA = p.getY() - pointA.getY();
+
+ boolean signAB = (xBminusA * yPminusA - yBminusA * xPminusA) > 0;
+
+ if ((xCminusA * yPminusA - yCminusA * xPminusA > 0) == signAB)
+ {
+ return false;
+ }
+
+ if ((xCminusB * (p.getY() - pointB.getY()) - yCminusB * (p.getX() -
pointB.getX()) > 0) != signAB)
+ {
+ return false;
+ }
+
+ return true;
}
/**
@@ -102,13 +142,13 @@ public class GouraudTriangle
{
// inspiration: http://stackoverflow.com/a/2145584/535646
// test: http://www.mathopenref.com/coordtrianglearea.html
- return Math.abs((a.getX() - c.getX()) * (b.getY() - a.getY()) -
(a.getX() - b.getX())
+ return Math.abs((a.getX() - c.getX()) * (b.getY() - a.getY()) -
(a.getX() - b.getX())
* (c.getY() - a.getY())) / 2;
}
/**
* calculate color weights with barycentric interpolation.
- *
+ *
* @param p Point within triangle
*
* @return array of weights (between 0 and 1) for a b c
@@ -116,9 +156,11 @@ public class GouraudTriangle
public double[] getWeights(Point2D p)
{
//
http://classes.soe.ucsc.edu/cmps160/Fall10/resources/barycentricInterpolation.pdf
- double area = getArea(pointA, pointB, pointC);
- return new double[]{getArea(pointB, pointC, p) / area, getArea(pointA,
pointC, p)
- / area, getArea(pointA, pointB, p) / area};
+ return new double[]
+ {
+ getArea(pointB, pointC, p) / area, getArea(pointA, pointC, p)
+ / area, getArea(pointA, pointB, p) / area
+ };
}
}