Repository: wicket
Updated Branches:
  refs/heads/master e5f6ea091 -> aa859dee6


WICKET-5827 - CssUrlReplacer supports base64 encoded images


Project: http://git-wip-us.apache.org/repos/asf/wicket/repo
Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/aa859dee
Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/aa859dee
Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/aa859dee

Branch: refs/heads/master
Commit: aa859dee621959de98e39ecafda28d9ab7ccc7fa
Parents: e5f6ea0
Author: klopfdreh <[email protected]>
Authored: Wed Feb 18 16:25:56 2015 +0100
Committer: klopfdreh <[email protected]>
Committed: Thu Mar 12 11:35:50 2015 +0100

----------------------------------------------------------------------
 .../apache/wicket/resource/CssUrlReplacer.java  | 80 ++++++++++++++++++--
 .../wicket/resource/CssUrlReplacerTest.java     | 65 +++++++++++-----
 2 files changed, 120 insertions(+), 25 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/wicket/blob/aa859dee/wicket-core/src/main/java/org/apache/wicket/resource/CssUrlReplacer.java
----------------------------------------------------------------------
diff --git 
a/wicket-core/src/main/java/org/apache/wicket/resource/CssUrlReplacer.java 
b/wicket-core/src/main/java/org/apache/wicket/resource/CssUrlReplacer.java
index b7e55f0..8071d9a 100644
--- a/wicket-core/src/main/java/org/apache/wicket/resource/CssUrlReplacer.java
+++ b/wicket-core/src/main/java/org/apache/wicket/resource/CssUrlReplacer.java
@@ -16,18 +16,25 @@
  */
 package org.apache.wicket.resource;
 
+import java.io.IOException;
+import java.io.InputStream;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import org.apache.wicket.WicketRuntimeException;
 import org.apache.wicket.css.ICssCompressor;
 import org.apache.wicket.request.Url;
 import org.apache.wicket.request.cycle.RequestCycle;
 import org.apache.wicket.request.resource.PackageResourceReference;
+import org.apache.wicket.util.crypt.Base64;
+import org.apache.wicket.util.io.IOUtils;
+import org.apache.wicket.util.resource.IResourceStream;
+import org.apache.wicket.util.resource.ResourceStreamNotFoundException;
 
 /**
  * This compressor is used to replace url within css files with resources that 
belongs to their
- * corresponding component classes. The compress method is not compressing any 
content, but replacing the
- * URLs with Wicket representatives.<br>
+ * corresponding component classes. The compress method is not compressing any 
content, but
+ * replacing the URLs with Wicket representatives.<br>
  * <br>
  * Usage:
  * 
@@ -44,6 +51,12 @@ public class CssUrlReplacer implements 
IScopeAwareTextResourceProcessor, ICssCom
        private static final Pattern URL_PATTERN = 
Pattern.compile("url\\(['|\"]*(.*?)['|\"]*\\)");
 
        /**
+        * Used to be append to CSS URLs (background-image: 
url('Beer.gif?embedBase64');). The
+        * CssUrlReplacer embeds the base64 content instead of using an URL.
+        */
+       public static final String EMBED_BASE64 = "embedBase64";
+
+       /**
         * Replaces the URLs of CSS resources with Wicket representatives.
         */
        @Override
@@ -58,6 +71,8 @@ public class CssUrlReplacer implements 
IScopeAwareTextResourceProcessor, ICssCom
                {
                        Url imageCandidateUrl = Url.parse(matcher.group(1));
                        CharSequence processedUrl;
+                       boolean embedded = false;
+
                        if (imageCandidateUrl.isFull())
                        {
                                processedUrl = 
imageCandidateUrl.toString(Url.StringMode.FULL);
@@ -71,19 +86,72 @@ public class CssUrlReplacer implements 
IScopeAwareTextResourceProcessor, ICssCom
                                // relativize against the url for the 
containing CSS file
                                Url cssUrlCopy = new Url(cssUrl);
                                cssUrlCopy.resolveRelative(imageCandidateUrl);
-                               PackageResourceReference imageReference = new 
PackageResourceReference(scope, cssUrlCopy.toString());
-                               processedUrl = cycle.urlFor(imageReference, 
null);
+
+                               // if the image should be processed as URL or 
base64 embedded
+                               if (cssUrlCopy.getQueryString() != null &&
+                                       
cssUrlCopy.getQueryString().contains(EMBED_BASE64))
+                               {
+                                       embedded = true;
+                                       PackageResourceReference imageReference 
= new PackageResourceReference(scope,
+                                               
cssUrlCopy.toString().replace("?" + EMBED_BASE64, ""));
+                                       try
+                                       {
+                                               processedUrl = 
createBase64EncodedImage(imageReference);
+                                       }
+                                       catch (Exception e)
+                                       {
+                                               throw new 
WicketRuntimeException(
+                                                       "Error while embedding 
an image into the css: " + imageReference, e);
+                                       }
+                               }
+                               else
+                               {
+                                       PackageResourceReference imageReference 
= new PackageResourceReference(scope,
+                                               cssUrlCopy.toString());
+                                       processedUrl = 
cycle.urlFor(imageReference, null);
+                               }
 
                        }
-                       matcher.appendReplacement(output, "url('" + 
processedUrl + "')");
+                       matcher.appendReplacement(output, embedded ? "url(" + 
processedUrl + ")" : "url('" +
+                               processedUrl + "')");
                }
                matcher.appendTail(output);
                return output.toString();
        }
 
+       /**
+        * Creates a base64 encoded image string based on the given image 
reference
+        * 
+        * @param imageReference
+        *            the image reference to create the base64 encoded image 
string of
+        * @return the base64 encoded image string
+        * @throws ResourceStreamNotFoundException
+        *             if the resource couldn't be found
+        * @throws IOException
+        *             if the stream couldn't be read
+        */
+       private CharSequence createBase64EncodedImage(PackageResourceReference 
imageReference)
+               throws ResourceStreamNotFoundException, IOException
+       {
+               IResourceStream resourceStream = 
imageReference.getResource().getResourceStream();
+               InputStream inputStream = resourceStream.getInputStream();
+               try
+               {
+                       byte[] bytes = IOUtils.toByteArray(inputStream);
+                       String base64EncodedImage = 
Base64.encodeBase64String(bytes);
+                       return "data:" + resourceStream.getContentType() + 
";base64," +
+                               base64EncodedImage.replaceAll("\\s", "");
+               }
+               finally
+               {
+                       IOUtils.closeQuietly(inputStream);
+               }
+       }
+
        @Override
        public String compress(String original)
        {
-               throw new 
UnsupportedOperationException(CssUrlReplacer.class.getSimpleName() + 
".process() should be used instead!");
+               throw new 
UnsupportedOperationException(CssUrlReplacer.class.getSimpleName() +
+                       ".process() should be used instead!");
        }
 }

http://git-wip-us.apache.org/repos/asf/wicket/blob/aa859dee/wicket-core/src/test/java/org/apache/wicket/resource/CssUrlReplacerTest.java
----------------------------------------------------------------------
diff --git 
a/wicket-core/src/test/java/org/apache/wicket/resource/CssUrlReplacerTest.java 
b/wicket-core/src/test/java/org/apache/wicket/resource/CssUrlReplacerTest.java
index df25e63..741b839 100644
--- 
a/wicket-core/src/test/java/org/apache/wicket/resource/CssUrlReplacerTest.java
+++ 
b/wicket-core/src/test/java/org/apache/wicket/resource/CssUrlReplacerTest.java
@@ -20,6 +20,7 @@ import static org.hamcrest.Matchers.containsString;
 import static org.hamcrest.Matchers.is;
 
 import org.apache.wicket.WicketTestCase;
+import org.apache.wicket.markup.html.image.ImageTest;
 import org.apache.wicket.mock.MockApplication;
 import org.apache.wicket.protocol.http.WebApplication;
 import 
org.apache.wicket.request.resource.caching.FilenameWithVersionResourceCachingStrategy;
@@ -36,20 +37,23 @@ public class CssUrlReplacerTest extends WicketTestCase
        @Override
        protected WebApplication newApplication()
        {
-               return new MockApplication() {
+               return new MockApplication()
+               {
                        @Override
                        protected void init()
                        {
                                super.init();
 
-                               getResourceSettings().setCachingStrategy(new 
FilenameWithVersionResourceCachingStrategy("=VER=", new 
MessageDigestResourceVersion())
-                               {
-                                       @Override
-                                       public void decorateUrl(ResourceUrl 
url, IStaticCacheableResource resource)
+                               getResourceSettings().setCachingStrategy(
+                                       new 
FilenameWithVersionResourceCachingStrategy("=VER=",
+                                               new 
MessageDigestResourceVersion())
                                        {
-                                               
url.setFileName(url.getFileName() + DECORATION_SUFFIX);
-                                       }
-                               });
+                                               @Override
+                                               public void 
decorateUrl(ResourceUrl url, IStaticCacheableResource resource)
+                                               {
+                                                       
url.setFileName(url.getFileName() + DECORATION_SUFFIX);
+                                               }
+                                       });
                        }
                };
        }
@@ -87,7 +91,10 @@ public class CssUrlReplacerTest extends WicketTestCase
                CssUrlReplacer replacer = new CssUrlReplacer();
 
                String processed = replacer.process(input, scope, 
cssRelativePath);
-               assertThat(processed, is(".class {background-image: 
url('./wicket/resource/org.apache.wicket.resource.CssUrlReplacerTest/res/css/some.img"+DECORATION_SUFFIX+"');}"));
+               assertThat(
+                       processed,
+                       is(".class {background-image: 
url('./wicket/resource/org.apache.wicket.resource.CssUrlReplacerTest/res/css/some.img"
 +
+                               DECORATION_SUFFIX + "');}"));
        }
 
        @Test
@@ -99,7 +106,10 @@ public class CssUrlReplacerTest extends WicketTestCase
                CssUrlReplacer replacer = new CssUrlReplacer();
 
                String processed = replacer.process(input, scope, 
cssRelativePath);
-               assertThat(processed, is(".class {background-image: 
url('./wicket/resource/org.apache.wicket.resource.CssUrlReplacerTest/res/css/some.img"+DECORATION_SUFFIX+"');}"));
+               assertThat(
+                       processed,
+                       is(".class {background-image: 
url('./wicket/resource/org.apache.wicket.resource.CssUrlReplacerTest/res/css/some.img"
 +
+                               DECORATION_SUFFIX + "');}"));
        }
 
        @Test
@@ -111,7 +121,10 @@ public class CssUrlReplacerTest extends WicketTestCase
                CssUrlReplacer replacer = new CssUrlReplacer();
 
                String processed = replacer.process(input, scope, 
cssRelativePath);
-               assertThat(processed, is(".class {background-image: 
url('./wicket/resource/org.apache.wicket.resource.CssUrlReplacerTest/res/images/some.img"+DECORATION_SUFFIX+"');}"));
+               assertThat(
+                       processed,
+                       is(".class {background-image: 
url('./wicket/resource/org.apache.wicket.resource.CssUrlReplacerTest/res/images/some.img"
 +
+                               DECORATION_SUFFIX + "');}"));
        }
 
        @Test
@@ -123,23 +136,37 @@ public class CssUrlReplacerTest extends WicketTestCase
                CssUrlReplacer replacer = new CssUrlReplacer();
 
                String processed = replacer.process(input, scope, 
cssRelativePath);
-               assertThat(processed, is(".class {background-image: 
url('./wicket/resource/org.apache.wicket.resource.CssUrlReplacerTest/res/css/images/some.img"+DECORATION_SUFFIX+"');}"));
+               assertThat(
+                       processed,
+                       is(".class {background-image: 
url('./wicket/resource/org.apache.wicket.resource.CssUrlReplacerTest/res/css/images/some.img"
 +
+                               DECORATION_SUFFIX + "');}"));
+       }
+
+       @Test
+       public void base64EncodedImage()
+       {
+               String input = ".class {background-image: 
url('Beer.gif?embedBase64');}";
+               Class<?> scope = ImageTest.class;
+               String cssRelativePath = "some.css";
+               CssUrlReplacer replacer = new CssUrlReplacer();
+               String processed = replacer.process(input, scope, 
cssRelativePath);
+               assertThat(
+                       processed,
+                       containsString(".class {background-image: 
url(data:image/gif;base64,R0lGODlh1wATAXAAACH5BAEAAP8ALAAAAADXA"));
        }
 
        @Test
        public void severalUrls()
        {
-               String input =
-                               ".class {\n" +
-                                       "a: url('../images/a.img');\n" +
-                                       "b: url('./b.img');\n" +
-                               "}";
+               String input = ".class {\n" + "a: url('../images/a.img');\n" + 
"b: url('./b.img');\n" + "}";
                Class<?> scope = CssUrlReplacerTest.class;
                String cssRelativePath = "res/css/some.css";
                CssUrlReplacer replacer = new CssUrlReplacer();
 
                String processed = replacer.process(input, scope, 
cssRelativePath);
-               assertThat(processed, 
containsString("CssUrlReplacerTest/res/images/a.img"+DECORATION_SUFFIX+"');"));
-               assertThat(processed, 
containsString("CssUrlReplacerTest/res/css/b.img"+DECORATION_SUFFIX+"');"));
+               assertThat(processed, 
containsString("CssUrlReplacerTest/res/images/a.img" +
+                       DECORATION_SUFFIX + "');"));
+               assertThat(processed, 
containsString("CssUrlReplacerTest/res/css/b.img" +
+                       DECORATION_SUFFIX + "');"));
        }
 }

Reply via email to