Package org.alastairmailer

Source Code of org.alastairmailer.PDFHighlightImage

package org.alastairmailer;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.io.File;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.logging.Logger;

import org.jpedal.PdfDecoder;
import org.jpedal.grouping.DefaultSearchListener;
import org.jpedal.grouping.PdfGroupingAlgorithms;
import org.jpedal.grouping.SearchListener;
import org.jpedal.grouping.SearchType;
import org.jpedal.objects.PdfPageData;

public class PDFImageCacher {

  private Map<File, Vector<Future<PDFHighlightImage>>> cache = new HashMap<File, Vector<Future<PDFHighlightImage>>>();
     
  public ExecutorService threadPool;
 
  private static final int CACHE_LIMIT = 30;
 
  private static final int THREAD_LIMIT = 2;
 
  private int cacheCount = 0;
 
  private final Logger log = Logger.getLogger(PDFImageCacher.class.getCanonicalName());
 
  public PDFImageCacher() {
    threadPool = Executors.newFixedThreadPool(THREAD_LIMIT);
  }
 
  public void requestCache(File f, int pageNum, String[] highlight) {
    log.fine("Cache requested: " + f + ' ' + pageNum);
    if (cache.containsKey(f)) {
      Vector<Future<PDFHighlightImage>> pages = cache.get(f);
      if (pages.size() < pageNum) { pages.setSize(pageNum); }
      if (pages.get(pageNum - 1) == null) {
        log.fine("No copy in cache, caching");
        if (cacheCount < CACHE_LIMIT) {
          GetPDFImage request = new GetPDFImage(f, pageNum, highlight);
          Future<PDFHighlightImage> result = threadPool.submit(request);
          pages.set(pageNum - 1, result);
          cacheCount++;
        } else {
          log.fine("Cache overflow");
        }
      }
    } else {
      Vector<Future<PDFHighlightImage>> fileEntry = new Vector<Future<PDFHighlightImage>>();
      if (fileEntry.size() < pageNum) { fileEntry.setSize(pageNum); }
      if (cacheCount < CACHE_LIMIT) {
        GetPDFImage request = new GetPDFImage(f, pageNum, highlight);
        Future<PDFHighlightImage> result = threadPool.submit(request);
        fileEntry.set(pageNum - 1, result);
        cacheCount++;
        cache.put(f, fileEntry);
        log.fine("Added " + f.toString() + ' ' + pageNum);
      } else {
        log.fine("Cache overflow");
      }
    }
  }
 
  public void decache(File f) {
    if (cache.containsKey(f)) {
      log.fine("Decaching " + f);
    Vector<Future<PDFHighlightImage>> pages = cache.get(f);
    for (Future<PDFHighlightImage> future : pages) {
      if (future != null) { future.cancel(true); }
    }
    cacheCount -= cache.get(f).size();
    cache.remove(f);
    }
  }
 
  public void decache(File f, int pageNum) {
    if (cache.containsKey(f)) {
    Vector<Future<PDFHighlightImage>> pages = cache.get(f);
    pages.get(pageNum).cancel(true);
    cacheCount--;
    pages.remove(pageNum);
    }
  }
 
  public void decacheExceptFirst(File f) {
    if (cache.containsKey(f)) {
      log.fine("Decaching " + f + " except first page");
    Vector<Future<PDFHighlightImage>> pages = cache.get(f);
    for (Future<PDFHighlightImage> future : pages) {
      if (future != null && future != pages.firstElement()) {
        future.cancel(true);
        }
    }
    cacheCount -= pages.size() - 1;
    pages.retainAll(Collections.singletonList(pages.firstElement()));
    }
  }
 
  public PDFHighlightImage getImage(File f, int pageNum) {
    PDFHighlightImage image = null;
      if (cache.containsKey(f)) {
        Future<PDFHighlightImage> imageF = cache.get(f).get(pageNum - 1);
        if (imageF != null) {
          try {
            image = imageF.get();
          }
          catch (CancellationException e) { }
          catch (ExecutionException e) {
            log.warning("Exception encountered getting page " + pageNum + " of " + f.toString() + ": " + e.getMessage());
          }
          catch (InterruptedException e) { }
        }
      }

      return image;
  }
 
}

class GetPDFImage implements Callable<PDFHighlightImage> {
 
  File pdfFile;
  int pageNum;
  BufferedImage im;
  String[] highlightTerms;
   
  public GetPDFImage(File f, int pageNo, String[] highlights) {
    pdfFile = f;
    pageNum = pageNo;
    highlightTerms = highlights;
  }

  float zoom = 1.25f;
 
  @SuppressWarnings("unchecked")
  public PDFHighlightImage call() throws Exception {
    PdfDecoder pdf = new PdfDecoder();
    PdfDecoder.setFontReplacements(pdf);
    pdf.openPdfFile(pdfFile.toString());
    pdf.setPageParameters(zoom, pageNum);
    pdf.decodePage(pageNum);
    BufferedImage pdfImage = pdf.getPageAsImage(pageNum);
    PdfGroupingAlgorithms grouping = pdf.getGroupingObject();
    PdfPageData page = pdf.getPdfPageData();
    int x1 = page.getMediaBoxX(pageNum);
    int x2 = page.getMediaBoxWidth(pageNum);
    int y1 = page.getMediaBoxY(pageNum);
    int y2 = page.getMediaBoxHeight(pageNum);
    final SearchListener listener = new DefaultSearchListener();
    List<Rectangle> highlights = grouping.findMultipleTermsInRectangle(
        x1, y1, x2, y2,
        page.getRotation(pageNum),
        pageNum,
        highlightTerms,
        true, SearchType.DEFAULT, listener);
    List<Rectangle> rectangles = new Vector<Rectangle>();
    for (Rectangle r: highlights) {
      int rX = Math.round((r.x - x1) * zoom);
      // 0.25f is to account for descender height, which JPedal does not seem to do
      int rY = Math.round((y2 - r.y - r.height + y1 + r.height * 0.2f) * zoom);
      int rW = Math.round(r.width * zoom);
      int rH = Math.round(r.height * zoom);
      Rectangle pdfR = new Rectangle(rX, rY, rW, rH);
      rectangles.add(pdfR);
    }
    pdf.closePdfFile();
    pdf = null;
   
    return new PDFHighlightImage(pdfImage, rectangles, pageNum);
  }

}

class PDFHighlightImage {
 
  public BufferedImage pdfImage;
  public List<Rectangle> highlights;
  public int pageNum;
  private static final Color selectColor = new Color(255,255,0,125);
  private static final Color otherColor = new Color(0,0,255,125);

  public PDFHighlightImage(BufferedImage pdfImage, List<Rectangle> highlights, int pageNum) {
    this.pdfImage = pdfImage;
    this.highlights = highlights;
    this.pageNum = pageNum;
  }
 
  public BufferedImage getHighlightedImage(Rectangle highlighted) {
    WritableRaster wr = pdfImage.copyData(null);
    BufferedImage imNew = new BufferedImage(pdfImage.getColorModel(), wr, pdfImage.isAlphaPremultiplied(), null);
    Graphics2D g = imNew.createGraphics();
   
    for (Rectangle r : highlights) {
      g.setColor(r == highlighted ? selectColor : otherColor);
      g.fill(r);
    }
    g.dispose();
    return imNew;
  }
 
}
TOP

Related Classes of org.alastairmailer.PDFHighlightImage

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.