package org.ebookdroid.droids.mupdf.codec;
import org.ebookdroid.common.bitmaps.ByteBufferBitmap;
import org.ebookdroid.common.bitmaps.ByteBufferManager;
import org.ebookdroid.common.settings.AppSettings;
import org.ebookdroid.core.ViewState;
import org.ebookdroid.core.codec.AbstractCodecPage;
import org.ebookdroid.core.codec.PageLink;
import org.ebookdroid.core.codec.PageTextBox;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.RectF;
import java.nio.ByteBuffer;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.emdev.utils.LengthUtils;
import org.emdev.utils.MatrixUtils;
public class MuPdfPage extends AbstractCodecPage {
private long pageHandle;
private final long docHandle;
final RectF pageBounds;
final int actualWidth;
final int actualHeight;
private final static boolean USE_DIRECT = true;
private MuPdfPage(final long pageHandle, final long docHandle) {
this.pageHandle = pageHandle;
this.docHandle = docHandle;
this.pageBounds = getBounds();
this.actualWidth = (int) pageBounds.width();
this.actualHeight = (int) pageBounds.height();
}
@Override
public int getWidth() {
return actualWidth;
}
@Override
public int getHeight() {
return actualHeight;
}
@Override
public ByteBufferBitmap renderBitmap(final ViewState viewState, final int width, final int height,
final RectF pageSliceBounds) {
final float[] matrixArray = calculateFz(width, height, pageSliceBounds);
return render(viewState, new Rect(0, 0, width, height), matrixArray);
}
private float[] calculateFz(final int width, final int height, final RectF pageSliceBounds) {
final Matrix matrix = MatrixUtils.get();
matrix.postScale(width / pageBounds.width(), height / pageBounds.height());
matrix.postTranslate(-pageSliceBounds.left * width, -pageSliceBounds.top * height);
matrix.postScale(1 / pageSliceBounds.width(), 1 / pageSliceBounds.height());
final float[] matrixSource = new float[9];
matrix.getValues(matrixSource);
final float[] matrixArray = new float[6];
matrixArray[0] = matrixSource[0];
matrixArray[1] = matrixSource[3];
matrixArray[2] = matrixSource[1];
matrixArray[3] = matrixSource[4];
matrixArray[4] = matrixSource[2];
matrixArray[5] = matrixSource[5];
return matrixArray;
}
static MuPdfPage createPage(final long dochandle, final int pageno) {
return new MuPdfPage(open(dochandle, pageno), dochandle);
}
@Override
protected void finalize() throws Throwable {
recycle();
super.finalize();
}
@Override
public synchronized void recycle() {
if (pageHandle != 0) {
free(docHandle, pageHandle);
pageHandle = 0;
}
}
@Override
public boolean isRecycled() {
return pageHandle == 0;
}
private RectF getBounds() {
final float[] box = new float[4];
getBounds(docHandle, pageHandle, box);
return new RectF(box[0], box[1], box[2], box[3]);
}
public ByteBufferBitmap render(final ViewState viewState, final Rect viewbox, final float[] ctm) {
if (isRecycled()) {
throw new RuntimeException("The page has been recycled before: " + this);
}
final int[] mRect = new int[4];
mRect[0] = viewbox.left;
mRect[1] = viewbox.top;
mRect[2] = viewbox.right;
mRect[3] = viewbox.bottom;
final int width = viewbox.width();
final int height = viewbox.height();
final int nightmode = viewState != null && viewState.nightMode && viewState.positiveImagesInNightMode ? 1 : 0;
final int slowcmyk = AppSettings.current().slowCMYK ? 1 : 0;
final ByteBufferBitmap bmp = ByteBufferManager.getBitmap(width, height);
final ByteBuffer byteBuffer = bmp.getPixels();
final boolean res = renderPageDirect(docHandle, pageHandle, mRect, ctm, byteBuffer, nightmode, slowcmyk);
if (res) {
return bmp;
}
bmp.eraseColor(Color.GRAY);
return bmp;
}
@Override
public List<PageLink> getPageLinks() {
return MuPdfLinks.getPageLinks(docHandle, pageHandle, pageBounds);
}
private static native void getBounds(long dochandle, long handle, float[] bounds);
private static native void free(long dochandle, long handle);
private static native long open(long dochandle, int pageno);
private static native boolean renderPageDirect(long dochandle, long pagehandle, int[] viewboxarray,
float[] matrixarray, ByteBuffer buffer, int noghtmode, int slowcmyk);
private native static List<PageTextBox> search(long docHandle, long pageHandle, String pattern);
@Override
public List<? extends RectF> searchText(final String pattern) {
final List<PageTextBox> rects = search(docHandle, pageHandle, pattern);
if (LengthUtils.isNotEmpty(rects)) {
final Set<String> temp = new HashSet<String>();
final Iterator<PageTextBox> iter = rects.iterator();
while (iter.hasNext()) {
final PageTextBox b = iter.next();
if (temp.add(b.toString())) {
b.left = (b.left - pageBounds.left) / pageBounds.width();
b.top = (b.top - pageBounds.top) / pageBounds.height();
b.right = (b.right - pageBounds.left) / pageBounds.width();
b.bottom = (b.bottom - pageBounds.top) / pageBounds.height();
} else {
iter.remove();
}
}
}
return rects;
}
}