org.jpedal.parser.image.downsample.OneBitDownSampler 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
Open Source (LGPL) JavaFX PDF Viewer for NetBeans plugin
/*
* ===========================================
* 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@
*
* ---------------
* OneBitDownSampler.java
* ---------------
*/
package org.jpedal.parser.image.downsample;
import org.jpedal.color.ColorSpaces;
import org.jpedal.color.DeviceRGBColorSpace;
import org.jpedal.color.GenericColorSpace;
import org.jpedal.images.SamplingFactory;
import org.jpedal.parser.image.PdfImageTypes;
import org.jpedal.parser.image.data.ImageData;
/**
* @author markee
*/
class OneBitDownSampler {
public static GenericColorSpace downSample(final int sampling, final ImageData imageData, GenericColorSpace decodeColorData) {
final byte[] data = imageData.getObjectData();
final int[] flag = {1, 2, 4, 8, 16, 32, 64, 128};
/* if(sampling>2){
System.out.println("downSample ="+sampling);
int newW=imageData.getWidth()>>1;
int newH=imageData.getHeight()>>1;
final int origLineLength= (imageData.getWidth()+7)>>3;
final int newLineLength= (newW+7)>>3;
int size=(newLineLength*newH);
byte[] newData=new byte[size];
//scan all pixels and down-sample
for(int y=0;ywGapLeft) {
wCount = wGapLeft;
}
if(hCount>hGapLeft) {
hCount = hGapLeft;
}
//count pixels in sample we will make into a pixel (ie 2x2 is 4 pixels , 4x4 is 16 pixels)
final int bytes = getPixelSetCount(2, false, data, flag, origLineLength, y, x, wCount, hCount);
final int inputByte=(x>>2)+(origLineLength*(y<<2));
final int outputByte=(x>>3)+(newLineLength*y);
if(bytes>3){
//set value as white or average of pixels
// final int outputByte=((x>>1) )+(newLineLength*(y>>2));
newData[outputByte] = (byte) (newData[outputByte] | (flag[7-((x & 7))]));
}
}
}
imageData.setWidth(newW);
imageData.setHeight(newH);
data=newData;
sampling=sampling>>1;
}
System.out.println("downSample ="+sampling);
/**/
final int newW = imageData.getWidth() / sampling;
final int newH = imageData.getHeight() / sampling;
final int size = newW * newH;
final byte[] newData = new byte[size];
final int origLineLength = (imageData.getWidth() + 7) >> 3;
//scan all pixels and down-sample
for (int y = 0; y < newH; y++) {
for (int x = 0; x < newW; x++) {
//allow for edges in number of pixels left
int wCount = sampling, hCount = sampling;
final int wGapLeft = imageData.getWidth() - x;
final int hGapLeft = imageData.getHeight() - y;
if (wCount > wGapLeft) {
wCount = wGapLeft;
}
if (hCount > hGapLeft) {
hCount = hGapLeft;
}
//count pixels in sample we will make into a pixel (ie 2x2 is 4 pixels , 4x4 is 16 pixels)
final int bytes = getPixelSetCount(sampling, false, data, flag, origLineLength, y, x, wCount, hCount);
final int count = (wCount * hCount);
//set value as white or average of pixels
final int offset = x + (newW * y);
if (count > 0) {
newData[offset] = (byte) ((255 * bytes) / count);
} else {
newData[offset] = (byte) 255;
}
}
}
imageData.setWidth(newW);
imageData.setHeight(newH);
imageData.setCompCount(1);
//suggest you add kernel sharpening here
//@bethan
//imageData=KernelUtils.sharpenGrayScale(imageData,w,h);
//remap Separation as already converted here
if (decodeColorData.getID() == ColorSpaces.Separation || decodeColorData.getID() == ColorSpaces.DeviceN) {
decodeColorData = new DeviceRGBColorSpace();
imageData.setCompCount(1);
invertBytes(newData);
}
imageData.setObjectData(newData);
imageData.setDepth(8);
return decodeColorData;
}
private static void invertBytes(final byte[] newData) {
final int count = newData.length;
for (int aa = 0; aa < count; aa++) {
newData[aa] = (byte) (newData[aa] ^ 255);
}
}
public static void downsampleTo8Bit(final int sampling, final ImageData imageData, final boolean isMask) {
final byte[] data = imageData.getObjectData();
final int newW = imageData.getWidth() / sampling;
final int newH = imageData.getHeight() / sampling;
final int size = newW * newH;
final byte[] newData = new byte[size];
final int[] flag = {1, 2, 4, 8, 16, 32, 64, 128};
final int origLineLength = (imageData.getWidth() + 7) >> 3;
//scan all pixels and down-sample
for (int y = 0; y < newH; y++) {
for (int x = 0; x < newW; x++) {
//allow for edges in number of pixels left
int wCount = sampling, hCount = sampling;
final int wGapLeft = imageData.getWidth() - x;
final int hGapLeft = imageData.getHeight() - y;
if (wCount > wGapLeft) {
wCount = wGapLeft;
}
if (hCount > hGapLeft) {
hCount = hGapLeft;
}
//count pixels in sample we will make into a pixel (ie 2x2 is 4 pixels , 4x4 is 16 pixels)
final int bytes = getPixelSetCount(sampling, isMask, data, flag, origLineLength, y, x, wCount, hCount);
final int count = (wCount * hCount);
//set value as white or average of pixels
final int offset = x + (newW * y);
if (bytes > 0) {
newData[offset] = (byte) (255 * bytes / count);
}
}
}
imageData.setWidth(newW);
imageData.setHeight(newH);
imageData.setObjectData(newData);
imageData.setDepth(8);
imageData.setCompCount(1);
}
static void convertToARGB(final ImageData imageData, final byte[] maskCol, final boolean scaleTransparency) {
final byte[] data = imageData.getObjectData();
final int newW = imageData.getWidth();
final int newH = imageData.getHeight();
final int size = newW * newH * 4;
final byte[] newData = new byte[size];
//scan all pixels and down-sample
for (int y = 0; y < newH; y++) {
for (int x = 0; x < newW; x++) {
//set value as white or average of pixels
final int offset = x + (newW * y);
final int bytes = data[offset] & 255;
int ptr = 4;
if (bytes < 128) {
ptr = 0;
}
System.arraycopy(maskCol, 0 + ptr, newData, (offset * 4) + 0, 3);
if (scaleTransparency) {
newData[(offset * 4) + 3] = (byte) (((maskCol[3 + ptr] & 255) * bytes) >> 8);
} else {
newData[(offset * 4) + 3] = maskCol[3 + ptr];
}
}
}
imageData.setWidth(newW);
imageData.setHeight(newH);
imageData.setObjectData(newData);
imageData.setDepth(8);
}
private static int getPixelSetCount(final int sampling, final boolean imageMask, final byte[] data, final int[] flag, final int origLineLength,
final int y, final int x, final int wCount, final int hCount) {
byte currentByte;
int bit;
int bytes = 0;
int ptr;
for (int yy = 0; yy < hCount; yy++) {
for (int xx = 0; xx < wCount; xx++) {
ptr = ((yy + (y * sampling)) * origLineLength) + (((x * sampling) + xx) >> 3);
if (ptr < data.length) {
currentByte = data[ptr];
} else {
currentByte = 0;
}
if (imageMask) {
currentByte = (byte) (currentByte ^ 255);
}
bit = currentByte & flag[7 - (((x * sampling) + xx) & 7)];
if (bit != 0) {
bytes++;
}
}
}
return bytes;
}
public static GenericColorSpace downSample(GenericColorSpace decodeColorData, final byte[] maskCol, final int sampling, final ImageData imageData) {
byte[] index = decodeColorData.getIndexedMap();
final boolean needsSharpening = (SamplingFactory.kernelSharpen
|| SamplingFactory.downsampleLevel == SamplingFactory.mediumAndSharpen
|| SamplingFactory.downsampleLevel == SamplingFactory.highAndSharpen);
byte[] colIndex = null;
boolean scaleTransparency = true;
boolean isMask = false;
if (index != null) {
index = decodeColorData.convertIndexToRGB(index);
colIndex = new byte[]{index[0], index[1], index[2], (byte) 255, index[3], index[4], index[5], (byte) 255};
decodeColorData = new DeviceRGBColorSpace();
scaleTransparency = false;
} else if (maskCol != null) {
isMask = true;
colIndex = new byte[]{0, 0, 0, (byte) 255, maskCol[0], maskCol[1], maskCol[2], (byte) 255};
}
if (colIndex != null) {
OneBitDownSampler.downsampleTo8Bit(sampling, imageData, isMask);
if (needsSharpening && sampling < 8) {
KernelUtils.applyKernel(imageData, 1);
}
OneBitDownSampler.convertToARGB(imageData, colIndex, scaleTransparency);
imageData.setIsConvertedToARGB(true);
} else {
decodeColorData = OneBitDownSampler.downSample(sampling, imageData, decodeColorData);
imageData.setImageType(PdfImageTypes.Binary);
if (needsSharpening && sampling < 8) {
KernelUtils.applyKernel(imageData, 1);
}
}
return decodeColorData;
}
}