From dfb404f3449f51285aaddcc4ac34675850557642 Mon Sep 17 00:00:00 2001
From: Mark Wardle <mark@wardle.org>
Date: Thu, 12 Feb 2015 13:28:49 +0000
Subject: [PATCH] Add support for data URLs during PDF conversion.

During conversion to PDF, parse BASE64 encoded image data for use in the PDF document. This is useful for dynamically generated images.

Signed-off-by: Mark Wardle <mark@wardle.org>
---
 .../pdf/builder/ERPDFReplacedElementFactory.java   | 59 ++++++++++++++++++----
 1 file changed, 48 insertions(+), 11 deletions(-)

diff --git a/Frameworks/Misc/ERPDFGeneration/Sources/er/pdf/builder/ERPDFReplacedElementFactory.java b/Frameworks/Misc/ERPDFGeneration/Sources/er/pdf/builder/ERPDFReplacedElementFactory.java
index 75aa305..92f184f 100644
--- a/Frameworks/Misc/ERPDFGeneration/Sources/er/pdf/builder/ERPDFReplacedElementFactory.java
+++ b/Frameworks/Misc/ERPDFGeneration/Sources/er/pdf/builder/ERPDFReplacedElementFactory.java
@@ -1,5 +1,8 @@
 package er.pdf.builder;
 
+import java.io.IOException;
+
+import org.apache.commons.codec.binary.Base64;
 import org.w3c.dom.Element;
 import org.xhtmlrenderer.extend.FSImage;
 import org.xhtmlrenderer.extend.ReplacedElement;
@@ -11,6 +14,7 @@ import org.xhtmlrenderer.pdf.ITextOutputDevice;
 import org.xhtmlrenderer.pdf.ITextReplacedElementFactory;
 import org.xhtmlrenderer.render.BlockBox;
 
+import com.lowagie.text.BadElementException;
 import com.lowagie.text.Image;
 import com.webobjects.appserver.WOApplication;
 import com.webobjects.appserver.WOResourceManager;
@@ -32,24 +36,57 @@ public class ERPDFReplacedElementFactory extends ITextReplacedElementFactory {
   public ReplacedElement createReplacedElement(LayoutContext context, BlockBox box, UserAgentCallback callback, int cssWidth, int cssHeight) {
     Element element = box.getElement();
 
-    if (element.getNodeName().equals("img") 
-        && element.getAttribute("src").matches(".*/wr\\?wodata=[\\-0-9]*$")) {
-      String key = element.getAttribute("src").replaceFirst(".*/wr\\?wodata=(.*)", "$1");
-      try {
-        NSData data = cachedDataForKey(key);
-        FSImage fsImage = new ITextFSImage(Image.getInstance(data.bytes()));
-        if (cssWidth != -1 || cssHeight != -1) {
-          fsImage.scale(cssWidth, cssHeight);
+    if (element.getNodeName().equals("img")) {
+      String attribute = element.getAttribute("src");
+      if (attribute.matches(".*/wr\\?wodata=[\\-0-9]*$")) {
+        String key = attribute.replaceFirst(".*/wr\\?wodata=(.*)", "$1");
+        try {
+          NSData data = cachedDataForKey(key);
+          FSImage fsImage = new ITextFSImage(Image.getInstance(data.bytes()));
+          if (cssWidth != -1 || cssHeight != -1) {
+            fsImage.scale(cssWidth, cssHeight);
+          }
+          return new ITextImageElement(fsImage);
+        } catch (Exception e) {
+          e.printStackTrace();
         }
-        return new ITextImageElement(fsImage);
-      } catch (Exception e) {
-        e.printStackTrace();
+      }
+      if (attribute.matches("data:.*")) {
+        FSImage fsImage;
+        try {
+          fsImage = buildImage(attribute, callback);
+        } catch (BadElementException e1) {
+          fsImage = null;
+        } catch (IOException e1) {
+          fsImage = null;
+        }
+        if (fsImage != null) {
+          if (cssWidth != -1 || cssHeight != -1) {
+            fsImage.scale(cssWidth, cssHeight);
+          }
+          return new ITextImageElement(fsImage);
+        }
+        return null;
       }
     }
 
     return super.createReplacedElement(context, box, callback, cssWidth, cssHeight);
   }
 
+  protected FSImage buildImage(String srcAttr, UserAgentCallback uac) throws IOException, BadElementException {
+    FSImage fsImage;
+    if (srcAttr.startsWith("data:image/")) {
+      String b64encoded = srcAttr.substring(srcAttr.indexOf("base64,") + "base64,".length(), srcAttr.length());
+      byte[] decodedBytes = Base64.decodeBase64(b64encoded);
+
+      fsImage = new ITextFSImage(Image.getInstance(decodedBytes));
+    } else {
+      fsImage = uac.getImageResource(srcAttr).getImage();
+    }
+    return fsImage;
+  }
+
+
   private NSData cachedDataForKey(String key) {
     WOResourceManager resourceManager =  WOApplication.application().resourceManager();
     WOURLValuedElementData elementData = resourceManager._cachedDataForKey(key);
-- 
2.2.1

