Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.idrsolutions.pdf.color.shading.LatticeFormShadeContext Maven / Gradle / Ivy
/*
* ===========================================
* Java Pdf Extraction Decoding Access Library
* ===========================================
*
* Project Info: http://www.idrsolutions.com
* Help section for developers at http://www.idrsolutions.com/support/
*
* (C) Copyright 1997-2017 IDRsolutions and Contributors.
*
* This file is part of JPedal/JPDF2HTML5
*
@LICENSE@
*
* ---------------
* LatticeFormShadeContext.java
* ---------------
*/
package com.idrsolutions.pdf.color.shading;
import java.awt.Color;
import java.awt.PaintContext;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.util.ArrayList;
import java.util.List;
import org.jpedal.color.GenericColorSpace;
import org.jpedal.function.PDFFunction;
import org.jpedal.objects.raw.PdfDictionary;
import org.jpedal.objects.raw.PdfObject;
import org.jpedal.utils.Matrix;
/**
* @author suda
*/
public class LatticeFormShadeContext implements PaintContext {
private final GenericColorSpace shadingColorSpace;
private final float[] background;
//final double textX;
//final double textY;
private final float[][] toUserSpace;
private final float[][] toShadeSpace;
private final int bitsPerComponent;
private final int bitsPerFlag;
private final int bitsPerCoordinate;
private final float[] decodeArr;
private final PDFFunction[] function;
private final int nComp;
private final List triCoords;
private final List triColors;
private final int triCount;
private final int verticesPerRow;
public LatticeFormShadeContext(final AffineTransform xform, final GenericColorSpace shadingColorSpace, final float[] background, final PdfObject shadingObject, final float[][] sm, final PDFFunction[] function) {
this.shadingColorSpace = shadingColorSpace;
this.bitsPerComponent = shadingObject.getInt(PdfDictionary.BitsPerComponent);
this.bitsPerFlag = shadingObject.getInt(PdfDictionary.BitsPerFlag);
this.bitsPerCoordinate = shadingObject.getInt(PdfDictionary.BitsPerCoordinate);
this.decodeArr = shadingObject.getFloatArray(PdfDictionary.Decode);
this.function = function;
this.background = background;
this.nComp = (this.decodeArr.length - 4) / 2;
this.verticesPerRow = shadingObject.getInt(PdfDictionary.VerticesPerRow);
float[][] shadeMatrix = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
if (sm != null) {
shadeMatrix = sm;
}
final float[][] xformMatrix = {
{(float) xform.getScaleX(), (float) xform.getShearX(), 0},
{(float) xform.getShearY(), (float) xform.getScaleY(), 0},
{(float) xform.getTranslateX(), (float) xform.getTranslateY(), 1}
};
toUserSpace = Matrix.inverse(xformMatrix);
toShadeSpace = Matrix.inverse(shadeMatrix);
final boolean hasSmallBits = bitsPerFlag < 8 || bitsPerComponent < 8 || bitsPerCoordinate < 8;
final BitReader reader = new BitReader(shadingObject.getDecodedStream(), hasSmallBits);
final double bitCoordScaling = 1.0 / ((1L << bitsPerCoordinate) - 1);
final double bitCompScaling = 1.0 / ((1L << bitsPerComponent) - 1);
final List trianglesPoints = new ArrayList();
triColors = new ArrayList();
final ArrayList pList = new ArrayList();
final ArrayList cList = new ArrayList();
while (reader.getPointer() < reader.getTotalBitLen()) {
final Point2D p = getPointCoords(reader, bitCoordScaling, bitsPerCoordinate, decodeArr);
final Color c = getPointColor(reader, bitCompScaling, bitsPerComponent);
pList.add(p);
cList.add(c);
}
final int totalRows = pList.size() / verticesPerRow;
//populate triangles : please refer to the pdf spec for understanding
for (int mm = 0; mm < (totalRows - 1); mm++) {
final int mRows = mm * totalRows;
for (int nn = 0; nn < (verticesPerRow - 1); nn++) {
final int nm = nn + mRows;
final int[] t = new int[6];
t[0] = nm;
t[1] = t[3] = nm + 1;
t[2] = t[4] = nm + verticesPerRow;
t[5] = nm + verticesPerRow + 1;
for (int z = 0; z < t.length; z++) {
trianglesPoints.add(pList.get(t[z]));
triColors.add(cList.get(t[z]));
}
}
}
triCoords = new ArrayList();
for (final Point2D trianglesPoint : trianglesPoints) {
final float[] xy = new float[2];
xy[0] = (float) trianglesPoint.getX();
xy[1] = (float) trianglesPoint.getY();
triCoords.add(xy);
}
triCount = triCoords.size() / 3;
Matrix.show(shadeMatrix);
}
@Override
public void dispose() {
}
@Override
public ColorModel getColorModel() {
return ColorModel.getRGBdefault();
}
private static Point2D getPointCoords(final BitReader reader, final double bitScaling, final int bps, final float[] decode) {
final long x_ = reader.readBitsAsLong(bps);
final long y_ = reader.readBitsAsLong(bps);
final double x = x_ * bitScaling * (decode[1] - decode[0]) + decode[0];
final double y = y_ * bitScaling * (decode[3] - decode[2]) + decode[2];
return new Point2D.Double(x, y);
}
private Color getPointColor(final BitReader reader, final double bitScaling, final int bps) {
final float[] components = new float[nComp];
for (int i = 0, j = 4; i < nComp; i++, j += 2) {
final long ci = reader.readBitsAsLong(bps);
components[i] = (float) (ci * bitScaling * (decodeArr[j + 1] - decodeArr[j]) + decodeArr[j]);
}
return calculateColor(components);
}
@Override
public Raster getRaster(final int startX, final int startY, final int w, final int h) {
final int rastSize = (w * h * 4);
final int[] data = new int[rastSize];
if (background != null) {
shadingColorSpace.setColor(background, 4);
final Color c = (Color) shadingColorSpace.getColor();
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
final int base = (i * w + j) * 4;
data[base] = c.getRed();
data[base + 1] = c.getGreen();
data[base + 2] = c.getBlue();
data[base + 3] = 255;
}
}
}
float x, y, x1, y1, x2, y2, x3, y3;
float[] temp;
int r, g, b;
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
float[] src = {startX + j, startY + i};
src = Matrix.transformPoint(toUserSpace, src[0], src[1]);
src = Matrix.transformPoint(toShadeSpace, src[0], src[1]);
x = src[0];
y = src[1];
for (int t = 0; t < triCount; t++) {
final int p = t * 3;
temp = triCoords.get(p);
x1 = temp[0];
y1 = temp[1];
temp = triCoords.get(p + 1);
x2 = temp[0];
y2 = temp[1];
temp = triCoords.get(p + 2);
x3 = temp[0];
y3 = temp[1];
if (isInTriangle(x, y, x1, y1, x2, y2, x3, y3)) { //shapes.get(t).contains(x, y)) { //
final Color c1 = triColors.get(p);
final Color c2 = triColors.get(p + 1);
final Color c3 = triColors.get(p + 2);
final float a = areaTriangle(x1, y1, x2, y2, x3, y3);
final float a1 = areaTriangle(x, y, x1, y1, x2, y2);
final float a2 = areaTriangle(x, y, x1, y1, x3, y3);
final float a3 = areaTriangle(x, y, x2, y2, x3, y3);
r = (int) ((a1 / a) * c3.getRed() + (a2 / a) * c2.getRed() + (a3 / a) * c1.getRed());
g = (int) ((a1 / a) * c3.getGreen() + (a2 / a) * c2.getGreen() + (a3 / a) * c1.getGreen());
b = (int) ((a1 / a) * c3.getBlue() + (a2 / a) * c2.getBlue() + (a3 / a) * c1.getBlue());
final int base = (i * w + j) * 4;
data[base] = r;
data[base + 1] = g;
data[base + 2] = b;
data[base + 3] = 255;
break;
}
}
}
}
final WritableRaster raster = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB).getRaster();
raster.setPixels(0, 0, w, h, data);
return raster;
}
private Color calculateColor(final float[] val) {
final Color col;
if (function != null) {
final float[] colValues = ShadingFactory.applyFunctions(function, val);
shadingColorSpace.setColor(colValues, colValues.length);
col = (Color) shadingColorSpace.getColor();
} else {
shadingColorSpace.setColor(val, val.length);
col = (Color) shadingColorSpace.getColor();
}
return col;
}
public float areaTriangle(final float x1, final float y1, final float x2, final float y2, final float x3, final float y3) {
return Math.abs((x1 - x3) * (y2 - y1) - (x1 - x2) * (y3 - y1));
}
private static boolean isInTriangle(final float x, final float y, final float x1, final float y1, final float x2, final float y2, final float x3, final float y3) {
final float dX = x - x3;
final float dY = y - y3;
final float dX21 = x3 - x2;
final float dY12 = y2 - y3;
final float D = dY12 * (x1 - x3) + dX21 * (y1 - y3);
final float s = dY12 * dX + dX21 * dY;
final float t = (y3 - y1) * dX + (x1 - x3) * dY;
if (D < 0) {
return s <= 0 && t <= 0 && s + t >= D;
}
return s >= 0 && t >= 0 && s + t <= D;
}
}