You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wicket.apache.org by ad...@apache.org on 2015/03/13 21:45:46 UTC

[30/50] wicket git commit: WICKET-5827 - CssUrlReplacer supports base64 encoded images

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/pr-86-media_tags
Commit: aa859dee621959de98e39ecafda28d9ab7ccc7fa
Parents: e5f6ea0
Author: klopfdreh <kl...@192.168.2.110>
Authored: Wed Feb 18 16:25:56 2015 +0100
Committer: klopfdreh <kl...@192.168.2.110>
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 + "');"));
 	}
 }