001/* =================================================== 002 * JFreeSVG : an SVG library for the Java(tm) platform 003 * =================================================== 004 * 005 * (C)opyright 2013-2021, by Object Refinery Limited. All rights reserved. 006 * 007 * Project Info: http://www.jfree.org/jfreesvg/index.html 008 * 009 * This program is free software: you can redistribute it and/or modify 010 * it under the terms of the GNU General Public License as published by 011 * the Free Software Foundation, either version 3 of the License, or 012 * (at your option) any later version. 013 * 014 * This program is distributed in the hope that it will be useful, 015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 017 * GNU General Public License for more details. 018 * 019 * You should have received a copy of the GNU General Public License 020 * along with this program. If not, see <http://www.gnu.org/licenses/>. 021 * 022 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 023 * Other names may be trademarks of their respective owners.] 024 * 025 * If you do not wish to be bound by the terms of the GPL, an alternative 026 * commercial license can be purchased. For details, please see visit the 027 * JFreeSVG home page: 028 * 029 * http://www.jfree.org/jfreesvg 030 * 031 */ 032 033package org.jfree.svg; 034 035import java.io.BufferedWriter; 036import java.io.File; 037import java.io.FileOutputStream; 038import java.io.IOException; 039import java.io.OutputStream; 040import java.io.OutputStreamWriter; 041import java.util.function.DoubleFunction; 042import java.util.logging.Level; 043import java.util.logging.Logger; 044import java.util.zip.GZIPOutputStream; 045import org.jfree.svg.util.Args; 046import org.jfree.svg.util.DoubleConverter; 047import org.jfree.svg.util.RyuDouble; 048 049/** 050 * Utility methods related to the {@link SVGGraphics2D} implementation. 051 */ 052public class SVGUtils { 053 054 private SVGUtils() { 055 // no need to instantiate this 056 } 057 058 /** 059 * Returns a new string where any special characters in the source string 060 * have been encoded. 061 * 062 * @param source the source string ({@code null} not permitted). 063 * 064 * @return A new string with special characters escaped for XML. 065 * 066 * @since 1.5 067 */ 068 public static String escapeForXML(String source) { 069 Args.nullNotPermitted(source, "source"); 070 StringBuilder sb = new StringBuilder(); 071 for (int i = 0; i < source.length(); i++) { 072 char c = source.charAt(i); 073 switch (c) { 074 case '<' : { 075 sb.append("<"); 076 break; 077 } 078 case '>' : { 079 sb.append(">"); 080 break; 081 } 082 case '&' : { 083 String next = source.substring(i, Math.min(i + 6, 084 source.length())); 085 if (next.startsWith("<") || next.startsWith(">") 086 || next.startsWith("&") 087 || next.startsWith("'") 088 || next.startsWith(""")) { 089 sb.append(c); 090 } else { 091 sb.append("&"); 092 } 093 break; 094 } 095 case '\'' : { 096 sb.append("'"); 097 break; 098 } 099 case '\"' : { 100 sb.append("""); 101 break; 102 } 103 default : sb.append(c); 104 } 105 } 106 return sb.toString(); 107 } 108 109 /** 110 * Writes a file containing the SVG element. 111 * 112 * @param file the file ({@code null} not permitted). 113 * @param svgElement the SVG element ({@code null} not permitted). 114 * 115 * @throws IOException if there is an I/O problem. 116 * 117 * @since 1.2 118 */ 119 public static void writeToSVG(File file, String svgElement) 120 throws IOException { 121 writeToSVG(file, svgElement, false); 122 } 123 124 /** 125 * Writes a file containing the SVG element. 126 * 127 * @param file the file ({@code null} not permitted). 128 * @param svgElement the SVG element ({@code null} not permitted). 129 * @param zip compress the output. 130 * 131 * @throws IOException if there is an I/O problem. 132 * 133 * @since 3.0 134 */ 135 public static void writeToSVG(File file, String svgElement, boolean zip) 136 throws IOException { 137 BufferedWriter writer = null; 138 try { 139 OutputStream os = new FileOutputStream(file); 140 if (zip) { 141 os = new GZIPOutputStream(os); 142 } 143 OutputStreamWriter osw = new OutputStreamWriter(os, "UTF-8"); 144 writer = new BufferedWriter(osw); 145 writer.write("<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n"); 146 writer.write(svgElement + "\n"); 147 writer.flush(); 148 } finally { 149 try { 150 if (writer != null) { 151 writer.close(); 152 } 153 } catch (IOException ex) { 154 throw new RuntimeException(ex); 155 } 156 } 157 } 158 159 /** 160 * Writes an HTML file containing an SVG element. 161 * 162 * @param file the file. 163 * @param title the title. 164 * @param svgElement the SVG element. 165 * 166 * @throws IOException if there is an I/O problem. 167 */ 168 public static void writeToHTML(File file, String title, String svgElement) 169 throws IOException { 170 BufferedWriter writer = null; 171 try { 172 FileOutputStream fos = new FileOutputStream(file); 173 OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8"); 174 writer = new BufferedWriter(osw); 175 writer.write("<!DOCTYPE html>\n"); 176 writer.write("<html>\n"); 177 writer.write("<head>\n"); 178 writer.write("<title>" + title + "</title>\n"); 179 writer.write("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n"); 180 writer.write("</head>\n"); 181 writer.write("<body>\n"); 182 writer.write(svgElement + "\n"); 183 writer.write("</body>\n"); 184 writer.write("</html>\n"); 185 writer.flush(); 186 } finally { 187 try { 188 if (writer != null) { 189 writer.close(); 190 } 191 } catch (IOException ex) { 192 Logger.getLogger(SVGUtils.class.getName()).log(Level.SEVERE, 193 null, ex); 194 } 195 } 196 } 197 198 /** 199 * Returns a string representing the specified double value. Internally 200 * this method is using the code from: https://github.com/ulfjack/ryu which 201 * is optimised for speed. 202 * 203 * @param d the value. 204 * 205 * @return A string representation of the double. 206 * 207 * @since 5.0 208 */ 209 public static String doubleToString(double d) { 210 return RyuDouble.doubleToString(d); 211 } 212 213 /** 214 * Returns a double-to-string function that limits the output to a 215 * specific number of decimal places (in the range 1 to 10). 216 * 217 * @param dp the decimal places (required in the range 1 to 10). 218 * 219 * @return The converter. 220 * 221 * @since 5.0 222 */ 223 public static DoubleFunction<String> createDoubleConverter(int dp) { 224 return new DoubleConverter(dp); 225 } 226 227}