Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

CSSEmbedTask.java

- Added native Ant task for running CSSEmbed, allows for much faster builds
- Replicates some of the functionality of CSSEmbed.java but in such a different style I didn't think reconciling them would necessarily be possible.

CSSURLEmbedder.java
- Count conversions correctly (uri -> datauri wasn't incrementing conversions counter)
- Clean up some formatting around opening curly braces & "if ()" blocks
- Wrap total conversion [INFO] line in a verbosity check so it doesn't always output
  • Loading branch information...
commit 3df7dfcb88e44d23cb2ae7e38f774910908be347 1 parent 62288c7
@tivac tivac authored
View
240 src/net/nczonline/web/cssembed/CSSEmbedTask.java
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2009 Nicholas C. Zakas. All rights reserved.
+ * http://www.nczonline.net/
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package net.nczonline.web.cssembed;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.BuildException;
+
+import org.apache.tools.ant.types.Mapper;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.resources.FileProvider;
+import org.apache.tools.ant.types.resources.FileResource;
+
+import org.apache.tools.ant.util.FileNameMapper;
+import org.apache.tools.ant.util.IdentityMapper;
+
+import java.io.*;
+
+import java.util.Vector;
+import java.util.Iterator;
+
+//Define a custom Ant Task that calls into the CSS Embedder
+public class CSSEmbedTask extends Task {
+
+ //attribute options
+ private String charset = "UTF-8";
+ private String root;
+ private boolean mhtml;
+ private String mhtmlRoot;
+ private boolean skipMissing;
+ private boolean verbose = false;
+ private int maxUriLength = 0;
+ private int maxImageSize = 0;
+ private File srcFile;
+ private File destFile;
+
+ //support nested resource collections & mappers
+ private Mapper mapperElement = null;
+ private Vector rcs = new Vector();
+
+ //Simple Setters
+ public void setCharset(String charset) {
+ this.charset = charset;
+ }
+
+ public void setRoot(String root) {
+ this.root = root;
+ }
+
+ public void setMhtml(boolean mhtml) {
+ this.mhtml = mhtml;
+ }
+
+ public void setMhtmlRoot(String mhtmlRoot) {
+ this.mhtmlRoot = mhtmlRoot;
+ }
+
+ public void setSkipMissing(boolean skipMissing) {
+ this.skipMissing = skipMissing;
+ }
+
+ public void setVerbose(boolean verbose) {
+ this.verbose = verbose;
+ }
+
+ public void setMaxUriLength(int maxUriLength) {
+ this.maxUriLength = maxUriLength;
+ }
+
+ public void setMaxImageSize(int maxImageSize) {
+ this.maxImageSize = maxImageSize;
+ }
+
+ public void setSrcFile(File srcFile) {
+ this.srcFile = srcFile;
+ }
+
+ public void setDestFile(File destFile) {
+ this.destFile = destFile;
+ }
+
+ //More complicated setters for nested elements...
+
+ //add a collection of resources to copy
+ public void add(ResourceCollection res) {
+ rcs.add(res);
+ }
+
+ //mapper takes source files & converts them to dest files
+ public Mapper createMapper() throws BuildException {
+ if (mapperElement != null) {
+ throw new BuildException("Cannot define more than one mapper", getLocation());
+ }
+ mapperElement = new Mapper(getProject());
+ return mapperElement;
+ }
+
+ //support multiple types of filename mappers being added
+ public void add(FileNameMapper fileNameMapper) {
+ createMapper().add(fileNameMapper);
+ }
+
+ //returns the mapper to use based on nested elements, defaults to IdentityMapper
+ private FileNameMapper getMapper() {
+ FileNameMapper mapper = null;
+ if (mapperElement != null) {
+ mapper = mapperElement.getImplementation();
+ } else {
+ mapper = new IdentityMapper();
+ }
+ return mapper;
+ }
+
+ //ensure that attributes are legit
+ protected void validateAttributes() throws BuildException {
+ //if there's no nested resource containers make sure that a srcFile/destFile are set
+ if(this.rcs == null || this.rcs.size() == 0) {
+ if (this.srcFile == null || !this.srcFile.exists()) {
+ throw new BuildException("Must specify an input file or at least one nested resource", getLocation());
+ }
+
+ if(this.destFile == null) {
+ throw new BuildException("Must specify an output file or at least one nested resource", getLocation());
+ }
+ }
+
+ if(this.mhtml && this.mhtmlRoot == null) {
+ throw new BuildException("Must specify mhtmlRoot in mhtml mode", getLocation());
+ }
+
+ if(this.mhtmlRoot != null && !this.mhtml) {
+ log("mhtmlRoot has no effect if mhtml mode is not activated", Project.MSG_WARN);
+ }
+ }
+
+ //run the task
+ public void execute () throws BuildException {
+ validateAttributes();
+
+ //set options flags
+ int options = (this.mhtml) ? CSSURLEmbedder.MHTML_OPTION : CSSURLEmbedder.DATAURI_OPTION;
+ if(skipMissing) {
+ options = options | CSSURLEmbedder.SKIP_MISSING_OPTION;
+ }
+
+ if(srcFile != null && srcFile.exists()) {
+ try {
+ embed(srcFile, destFile, options);
+ } catch(IOException ex) {
+ throw new BuildException(ex.getMessage(), ex);
+ }
+ }
+
+ FileNameMapper mapper = getMapper();
+
+ for(Iterator it = this.rcs.iterator(); it.hasNext();) {
+ ResourceCollection rc = (ResourceCollection) it.next();
+
+ for(Iterator rcit = rc.iterator(); rcit.hasNext();) {
+ FileResource fr = (FileResource) rcit.next();
+ File in = fr.getFile();
+
+ String[] mapped = mapper.mapFileName(in.getName());
+ if (mapped != null && mapped.length > 0) {
+ for(int k = 0; k < mapped.length; k++) {
+ File out = getProject().resolveFile(in.getParent() + File.separator + mapped[k]);
+
+ try {
+ embed(in, out, options);
+ } catch(IOException ex) {
+ throw new BuildException(ex.getMessage(), ex);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void embed(File input, File output, int options) throws IOException {
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ Reader in = new InputStreamReader(new FileInputStream(input), charset);
+ Writer out = new OutputStreamWriter(bytes, charset);
+ String pathRoot = root;
+
+ if(pathRoot == null) {
+ pathRoot = input.getCanonicalPath();
+ pathRoot = pathRoot.substring(0, pathRoot.lastIndexOf(File.separator));
+ }
+
+ if (!pathRoot.endsWith(File.separator)){
+ pathRoot += File.separator;
+ }
+
+ if(verbose) {
+ log("[INFO] embedding images from '" + input + "'");
+ }
+
+ CSSURLEmbedder embedder = new CSSURLEmbedder(in, options, verbose, maxUriLength, maxImageSize);
+
+ if(mhtml) {
+ embedder.setMHTMLRoot(mhtmlRoot);
+ embedder.setFilename(output.getName());
+ }
+
+ embedder.embedImages(out, pathRoot);
+
+ in.close();
+ out.close();
+
+ if(bytes.size() > 0) {
+ if(verbose) {
+ log("[INFO] Writing to file: " + output);
+ }
+
+ bytes.writeTo(new FileOutputStream(output));
+ }
+ }
+}
View
25 src/net/nczonline/web/cssembed/CSSURLEmbedder.java
@@ -215,7 +215,6 @@ public void embedImages(Writer out, String root) throws IOException {
}
foundMedia.put(url, lineNum);
-
//Begin processing URL
String newUrl = url;
if (verbose){
@@ -230,18 +229,16 @@ public void embedImages(Writer out, String root) throws IOException {
//get the data URI format
String uriString = getImageURIString(newUrl, url);
-
+
//if it doesn't begin with data:, it's not a data URI
if (uriString.startsWith("data:")){
-
-
- if (maxUriLength > 0 && uriString.length() > maxUriLength) {
+ if (maxUriLength > 0 && uriString.length() > maxUriLength){
if (verbose){
System.err.println("[WARNING] File " + newUrl + " creates a data URI larger than " + maxUriLength + " bytes. Skipping.");
}
builder.append(url);
} else if (maxUriLength > 0 && uriString.length() > maxUriLength){
- if (verbose) {
+ if (verbose){
System.err.println("[INFO] File " + newUrl + " creates a data URI longer than " + maxUriLength + " characters. Skipping.");
}
builder.append(url);
@@ -252,7 +249,6 @@ public void embedImages(Writer out, String root) throws IOException {
* have both a data URI and MHTML in the same file.
*/
if (hasOption(MHTML_OPTION)){
-
String entryName = getFilename(url);
//create MHTML header entry
@@ -272,6 +268,7 @@ public void embedImages(Writer out, String root) throws IOException {
conversions++;
} else if (hasOption(DATAURI_OPTION)){
builder.append(uriString);
+ conversions++;
}
}
} else {
@@ -306,8 +303,10 @@ public void embedImages(Writer out, String root) throws IOException {
mhtmlHeader.append("*/\n");
out.write(mhtmlHeader.toString());
}
-
- System.err.println("[INFO] Converted " + conversions + " images to data URIs.");
+
+ if (verbose){
+ System.err.println("[INFO] Converted " + conversions + " images to data URIs.");
+ }
out.write(builder.toString());
}
@@ -353,9 +352,9 @@ private String getImageURIString(String url, String originalUrl) throws IOExcept
}
//check file size if we've been asked to
- if(this.maxImageSize > 0 && file.length() > this.maxImageSize) {
- if(verbose) {
- System.err.println("[INFO] File " + originalUrl + " is larger than " + this.maxImageSize + " bytes. Skipping.");
+ if (maxImageSize > 0 && file.length() > maxImageSize){
+ if (verbose){
+ System.err.println("[INFO] File '" + originalUrl + "' is larger than " + maxImageSize + " bytes. Skipping.");
}
writer.write(originalUrl);
@@ -369,7 +368,7 @@ private String getImageURIString(String url, String originalUrl) throws IOExcept
System.err.println("[INFO] Generated data URI for '" + url + "'.");
}
} catch (FileNotFoundException e){
- if(hasOption(SKIP_MISSING_OPTION)) {
+ if (hasOption(SKIP_MISSING_OPTION)){
System.err.println("[INFO] Could not find file. " + e.getMessage() + " Skipping.");
writer.write(originalUrl);
Please sign in to comment.
Something went wrong with that request. Please try again.