com.idrsolutions.pdf.color.blends.BlendContext Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of OpenViewerFX Show documentation
Show all versions of OpenViewerFX Show documentation
An Open Source JavaFX PDF Viewer
/*
* ===========================================
* 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
*
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* ---------------
* BlendContext.java
* ---------------
*/
package com.idrsolutions.pdf.color.blends;
import java.awt.CompositeContext;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import org.jpedal.objects.raw.PdfDictionary;
/**
*
*/
public class BlendContext implements CompositeContext {
// private final float alpha;
private final int blendMode;
public BlendContext(final int blendMode) {
this.blendMode = blendMode;
}
@Override
public void dispose() {
}
@Override
public void compose(final Raster src, final Raster dstIn, final WritableRaster dstOut) {
final int width = Math.min(src.getWidth(), dstIn.getWidth());
final int height = Math.min(src.getHeight(), dstIn.getHeight());
final int[] srcPixels = new int[width];
final int[] dstInPixels = new int[width];
final int[] dstOutPixels = new int[width];
for (int y = 0; y < height; y++) {
src.getDataElements(0, y, width, 1, srcPixels);
dstIn.getDataElements(0, y, width, 1, dstInPixels);
int oldS = 0;
int oldD = 0;
int oldR = 0;
for (int x = 0; x < width; x++) {
final int s = srcPixels[x];
final int d = dstInPixels[x];
if (s == oldS && d == oldD) {
dstOutPixels[x] = oldR;
} else {
oldS = s;
oldD = d;
final int[] sp = getRGBA(s);
final int[] dp = getRGBA(d);
int[] result = new int[4];
// if (sp[3] != 255) { //transparency involved convert to rgb
//// int r = sp[0] * sp[3] + dp[0] * (255 - sp[3]);
//// int g = sp[1] * sp[3] + dp[1] * (255 - sp[3]);
//// int b = sp[2] * sp[3] + dp[2] * (255 - sp[3]);
//// sp = new int[]{r / 255, g / 255, b / 255, sp[3]};
//// dp = new int[]{0,0,0,dp[3]};
// dp[3] = 255;
//// sp[3] = 255;
//// System.out.println(dp[0]+" "+dp[1]+" "+dp[2]+" "+dp[3]);
// }
switch (blendMode) {
case PdfDictionary.Normal:
break;
case PdfDictionary.Hue:
result = doHue(sp, dp);
break;
case PdfDictionary.Saturation:
result = doSaturation(sp, dp);
break;
case PdfDictionary.Color:
result = doColor(sp, dp);
break;
case PdfDictionary.Luminosity:
result = doLuminosity(sp, dp);
break;
default:
break;
}
if (sp[3] != 255) {
double sr = result[0] / 255.0;
double sg = result[1] / 255.0;
double sb = result[2] / 255.0;
final double sa = sp[3] / 255.0;
final double dr = dp[0] / 255.0;
final double dg = dp[1] / 255.0;
final double db = dp[2] / 255.0;
sr = ((1 - sa) * dr) + (sa * sr);
sg = ((1 - sa) * dg) + (sa * sg);
sb = ((1 - sa) * db) + (sa * sb);
result[0] = (int) (sr * 255);
result[1] = (int) (sg * 255);
result[2] = (int) (sb * 255);
}
dstOutPixels[x] = oldR = (Math.min(255, sp[3] + dp[3]) << 24 | result[0] << 16 | result[1] << 8 | result[2]);
}
// dstOutPixels[x] = sp[3] << 24 | sp[0] << 16 | sp[1] << 8 | sp[2];
//
}
dstOut.setDataElements(0, y, width, 1, dstOutPixels);
}
}
private static int[] getRGBA(final int argb) {
return new int[]{(argb >> 16) & 0xff, (argb >> 8) & 0xff, argb & 0xff, (argb >> 24) & 0xff};
}
private static int[] doColor(final int[] src, final int[] dst) {
if (dst[0] == 255 && dst[1] == 255 && dst[2] == 255) {
return new int[]{src[0], src[1], src[2]};
}
final int[] result = new int[3];
final double sr = src[0] / 255.0;
final double sg = src[1] / 255.0;
final double sb = src[2] / 255.0;
final double dr = dst[0] / 255.0;
final double dg = dst[1] / 255.0;
final double db = dst[2] / 255.0;
final double[] rgb = setLum(sr, sg, sb, lum(dr, dg, db));
result[0] = (int) (255 * rgb[0]);
result[1] = (int) (255 * rgb[1]);
result[2] = (int) (255 * rgb[2]);
return result;
}
private static int[] doLuminosity(final int[] src, final int[] dst) {
if (dst[0] == 255 && dst[1] == 255 && dst[2] == 255) {
return new int[]{src[0], src[1], src[2]};
}
final int[] result = new int[3];
final double sr = src[0] / 255.0;
final double sg = src[1] / 255.0;
final double sb = src[2] / 255.0;
final double dr = dst[0] / 255.0;
final double dg = dst[1] / 255.0;
final double db = dst[2] / 255.0;
final double[] rgb = setLum(dr, dg, db, lum(sr, sg, sb));
result[0] = (int) (255 * rgb[0]);
result[1] = (int) (255 * rgb[1]);
result[2] = (int) (255 * rgb[2]);
return result;
}
private static int[] doHue(final int[] src, final int[] dst) {
if (dst[0] == 255 && dst[1] == 255 && dst[2] == 255) {
return new int[]{src[0], src[1], src[2]};
}
final double[] srcHSL = new double[3];
rgbToHSL(src[0], src[1], src[2], srcHSL);
final double[] dstHSL = new double[3];
rgbToHSL(dst[0], dst[1], dst[2], dstHSL);
final int[] result = new int[4];
hslToRGB(srcHSL[0], dstHSL[1], dstHSL[2], result);
return result;
}
private static int[] doSaturation(final int[] src, final int[] dst) {
if (dst[0] == 255 && dst[1] == 255 && dst[2] == 255) {
return new int[]{src[0], src[1], src[2]};
}
final double[] srcHSL = new double[3];
rgbToHSL(src[0], src[1], src[2], srcHSL);
final double[] dstHSL = new double[3];
rgbToHSL(dst[0], dst[1], dst[2], dstHSL);
final int[] result = new int[4];
hslToRGB(dstHSL[0], srcHSL[1], dstHSL[2], result);
return result;
}
private static double lum(final double r, final double g, final double b) {
return 0.3 * r + 0.59 * g + 0.11 * b;
}
private static double[] setLum(double r, double g, double b, final double l) {
final double d = l - lum(r, g, b);
r += d;
g += d;
b += d;
return clipColor(r, g, b);
}
private static double[] clipColor(double r, double g, double b) {
final double l = lum(r, g, b);
final double n = Math.min(Math.min(r, g), b);
final double x = Math.max(Math.max(r, g), b);
if (n < 0.0) {
r = l + (((r - l) * l) / (l - n));
g = l + (((g - l) * l) / (l - n));
b = l + (((b - l) * l) / (l - n));
}
if (x > 1.0) {
r = l + (((r - l) * (1 - l)) / (x - l));
g = l + (((g - l) * (1 - l)) / (x - l));
b = l + (((b - l) * (1 - l)) / (x - l));
}
return new double[]{r, g, b};
}
private static void rgbToHSL(final int r, final int g, final int b, final double[] hsl) {
final double rr = (r / 255.0);
final double gg = (g / 255.0);
final double bb = (b / 255.0);
final double var_Min = Math.min(Math.min(rr, gg), bb);
final double var_Max = Math.max(Math.max(rr, gg), bb);
final double del_Max = var_Max - var_Min;
double H;
final double S;
final double L;
L = (var_Max + var_Min) / 2.0;
if (del_Max - 0.01 <= 0.0) {
H = 0;
S = 0;
} else {
if (L < 0.5) {
S = del_Max / (var_Max + var_Min);
} else {
S = del_Max / (2 - var_Max - var_Min);
}
final double del_R = (((var_Max - rr) / 6.0) + (del_Max / 2.0)) / del_Max;
final double del_G = (((var_Max - gg) / 6.0) + (del_Max / 2.0)) / del_Max;
final double del_B = (((var_Max - bb) / 6.0) + (del_Max / 2.0)) / del_Max;
if (rr == var_Max) {
H = del_B - del_G;
} else if (gg == var_Max) {
H = (1 / 3f) + del_R - del_B;
} else {
H = (2 / 3f) + del_G - del_R;
}
if (H < 0) {
H += 1;
}
if (H > 1) {
H -= 1;
}
}
hsl[0] = H;
hsl[1] = S;
hsl[2] = L;
}
private static void hslToRGB(final double h, final double s, final double l, final int[] rgb) {
final int R;
final int G;
final int B;
if (s - 0.01 <= 0.0) {
R = (int) (l * 255.0f);
G = (int) (l * 255.0f);
B = (int) (l * 255.0f);
} else {
final double v1;
final double v2;
if (l < 0.5f) {
v2 = l * (1 + s);
} else {
v2 = (l + s) - (s * l);
}
v1 = 2 * l - v2;
R = (int) (255.0 * hueToRGB(v1, v2, h + (1.0 / 3.0)));
G = (int) (255.0 * hueToRGB(v1, v2, h));
B = (int) (255.0 * hueToRGB(v1, v2, h - (1.0 / 3.0)));
}
rgb[0] = R;
rgb[1] = G;
rgb[2] = B;
}
private static double hueToRGB(final double v1, final double v2, double vH) {
if (vH < 0.0) {
vH += 1.0;
}
if (vH > 1.0) {
vH -= 1.0;
}
if ((6.0 * vH) < 1.0) {
return (v1 + (v2 - v1) * 6.0 * vH);
}
if ((2.0 * vH) < 1.0) {
return v2;
}
if ((3.0 * vH) < 2.0) {
return (v1 + (v2 - v1) * ((2.0 / 3.0) - vH) * 6.0);
}
return v1;
}
}