0

I want to convert pdfs to image files within appengine. Ideally I would upload the pdf as a blob and store both the pdf and an image of the pdf. The conversion could also be done at a different time (taskqueue).

I have not found any working samples or good documentation of doing this.
The official documentation is here. Here is my implementation on my upload servlet.

@SuppressWarnings("serial")
public class UploadBlobServlet extends HttpServlet {

  private static final Logger log = Logger.getLogger(UploadBlobServlet.class.getName());

public void doPost(HttpServletRequest req, HttpServletResponse resp)
        throws IOException {

    BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
    Map<String, BlobKey> blobs = blobstoreService.getUploadedBlobs(req);
    BlobKey blobKey = blobs.get("data");
    log.log(Level.WARNING,"blobKey: "+blobKey.getKeyString());



        if (blobKey != null) {
        resp.getWriter().println(blobKey.getKeyString());

        BlobstoreInputStream in=new BlobstoreInputStream(blobKey);
        byte[] b = IOUtils.toByteArray(is);
      //  try{
            in.read(b);
            Asset asset = new Asset(
                    "application/pdf", b, "testfile.pdf");
                Document document = new Document(asset);
                Conversion conversion = new Conversion(document, "image/png");

                ConversionService service =
                    ConversionServiceFactory.getConversionService();
                ConversionResult result = service.convert(conversion);

                if (result.success()) {
                  // Note: in most cases, we will return data all in one asset,
                  // except that we return multiple assets for multi-page images.
                FileService fileService=FileServiceFactory.getFileService(); 
                for (Asset ass : result.getOutputDoc().getAssets()) {
                    AppEngineFile file=fileService.createNewBlobFile("image/png", "testfile.png");
                    FileWriteChannel writeChannel=fileService.openWriteChannel(file, false);
                    writeChannel.write(ByteBuffer.wrap(b));
                    writeChannel.closeFinally();
                  }
                } else {
                    log.log(Level.WARNING,"error");

                }

Update: Have added byte[]=IOUtils.toByteArray(is); and still getting a NPE...

I am also curious as to the quality of the conversion if anyone has experience.

Patrick Jackson
  • 18,766
  • 22
  • 81
  • 141

2 Answers2

2

To convert a document you first have to create an asset. An asset is created by passing the the bytes to the constructor, as shown in the example. In your case you will need to use class BlobstoreInputStream to read the bytes of your PDF.

BlobKey blobKey = new BlobKey("your-pdf-blobkey");
InputStream is = new BlobstoreInputStream(blobkey);

Then you need to read all bytes from this input stream.

After the conversion, you can access the bytes of the converted image with asset.getData() and then follow this doc to write the image to the blobstore.

Sebastian Kreft
  • 7,819
  • 3
  • 24
  • 41
  • I have added source code of what I have tried. Now getting null for the blobstoreinputstream. – Patrick Jackson Jul 17 '12 at 00:32
  • Are you sure that the InputStream is null. I would say that the NullPointerException you are getting is because you are passing a null array to the read method(See http://docs.oracle.com/javase/6/docs/api/java/io/InputStream.html#read(byte[])). You need to read by chunks, see 2nd anser of http://stackoverflow.com/questions/1264709/convert-inputstream-to-byte-in-java. – Sebastian Kreft Jul 17 '12 at 00:51
  • ok, right about the null being passed in...duh! I have updated the code with IOUtils.toByteArray(is); and still getting NPE. will have to dig a little more... – Patrick Jackson Jul 17 '12 at 01:30
  • I got it working. thanks for the pointers! Quality looks good, but a just a little blurry around edges of text when converted to png. I added code to your answer to make it complete. – Patrick Jackson Jul 17 '12 at 14:19
  • @Patrick I rejected your suggested edit: http://stackoverflow.com/suggested-edits/319831. Make it an answer on it's own. Thank you for helping others with your update! :) – Kijewski Jul 17 '12 at 14:33
0

Here is the working code to receive an upload pdf and convert it to a png using the Conversion api. The upload is completed with a multi-part post to an upload url must be obtained through:

     String url=blobstoreService.createUploadUrl("/upload");

Just place this code in a servlet and map it to "upload" in your web.xml.

The Conversion is good quality, however I did notice just a little blurriness around text. In my case the png was about 25% larger.

public void doPost(HttpServletRequest req, HttpServletResponse resp)
        throws IOException {

    BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
    Map<String, BlobKey> blobs = blobstoreService.getUploadedBlobs(req);
    BlobKey blobKey = blobs.get("data");



        if (blobKey != null) {
        resp.getWriter().println(blobKey.getKeyString());
        BlobstoreInputStream in=new BlobstoreInputStream(blobKey);

        byte[] b = IOUtils.toByteArray(in);
        if(b!=null){
            log.log(Level.WARNING,"blobsize: "+b.length);
        }else{
            log.log(Level.WARNING,"b is null");

        }
            in.read(b);
            Asset asset = new Asset(
                    "application/pdf", b, "testfile.pdf");
                Document document = new Document(asset);
                Conversion conversion = new Conversion(document, "image/png");

                ConversionService service =
                    ConversionServiceFactory.getConversionService();
                ConversionResult result = service.convert(conversion);

                if (result.success()) {
                  // Note: in most cases, we will return data all in one asset,
                  // except that we return multiple assets for multi-page images.
                FileService fileService=FileServiceFactory.getFileService(); 
                for (Asset ass : result.getOutputDoc().getAssets()) {
                    AppEngineFile file=fileService.createNewBlobFile("image/png", "test3file.png");
                    FileWriteChannel writeChannel=fileService.openWriteChannel(file, true);
                    writeChannel.write(ByteBuffer.wrap(ass.getData()));

                    writeChannel.closeFinally();
                  }
                } else {
                    log.log(Level.WARNING,"error");

                }
Patrick Jackson
  • 18,766
  • 22
  • 81
  • 141