1 10 package org.mmbase.util.images; 11 12 import java.util.*; 13 import java.util.regex.*; 14 import org.mmbase.util.logging.Logging; 15 import org.mmbase.util.logging.Logger; 16 17 import java.io.*; 18 19 24 25 26 public abstract class Imaging { 27 28 private static final Logger log = Logging.getLoggerInstance(Imaging.class); 29 30 public static final String FIELD_HANDLE = "handle"; 31 public static final String FIELD_CKEY = "ckey"; 32 33 34 39 public static String getMimeTypeByExtension(String ext) { 40 return getMimeTypeByFileName("dummy." + ext); 41 } 42 43 public static String getMimeTypeByFileName(String fileName) { 44 javax.servlet.ServletContext sx = org.mmbase.module.core.MMBaseContext.getServletContext(); 45 String mimeType = sx.getMimeType(fileName); 46 if (mimeType == null) { 47 log.warn("Can't find mimetype for a file with name '" + fileName + "'. Defaulting to text/html"); 48 log.warn(Logging.stackTrace()); 49 mimeType = "text/html"; 50 } 51 return mimeType; 52 } 53 54 59 public static String getAlias(String a) { 60 if (a.equals("s")) return "geometry"; 61 if (a.equals("r")) return "rotate"; 62 if (a.equals("c")) return "colors"; 63 if (a.equals("t")) return "transparent"; 64 if (a.equals("i")) return "interlace"; 65 if (a.equals("q")) return "quality"; 66 if (a.equals("mono")) return "monochrome"; 67 if (a.equals("highcontrast")) return "contrast"; 68 if (a.equals("flipx")) return "flop"; 69 if (a.equals("flipy")) return "flip"; 70 if (a.equals("dia")) return "negate"; 73 return a; 74 75 } 76 77 private static final char NOQUOTING = '-'; 78 86 public static List parseTemplate(String template) { 88 if (log.isDebugEnabled()) log.debug("parsing " + template); 89 List params = new ArrayList(); 90 if (template != null) { 91 int bracketDepth = 0; 92 char quoteState = NOQUOTING; StringBuffer buf = new StringBuffer (); 94 95 int i = 0; 96 while (i < template.length() && template.charAt(i) == '+') i++; for (; i < template.length(); i++) { 98 char c = template.charAt(i); 99 switch(c) { 100 case '\'': 101 case '"': 102 if (quoteState == c) { 103 quoteState = NOQUOTING; 104 } else if (quoteState == NOQUOTING) { 105 quoteState = c; 106 } 107 break; 108 case '(': if (quoteState == NOQUOTING) bracketDepth++; break; 109 case ')': if (quoteState == NOQUOTING) bracketDepth--; break; 110 case '+': if (bracketDepth == 0 && quoteState == NOQUOTING ) { 114 removeSurroundingQuotes(buf); 115 params.add(buf.toString()); 116 buf.setLength(0); 117 continue; 118 } 119 break; 120 } 121 122 buf.append(c); 123 } 124 if (bracketDepth != 0) log.warn("Unbalanced brackets in " + template); 125 if (quoteState != NOQUOTING) log.warn("Unbalanced quotes in " + template); 126 127 removeSurroundingQuotes(buf); 128 if (! buf.toString().equals("")) params.add(buf.toString()); 129 } 130 return params; 131 } 132 136 protected static void removeSurroundingQuotes(StringBuffer buf) { 137 if (buf.length() >= 2 && (buf.charAt(0) == '"' || buf.charAt(0) == '\'') && buf.charAt(buf.length() - 1) == buf.charAt(0)) { 139 buf.deleteCharAt(0); 140 buf.deleteCharAt(buf.length() - 1); 141 } 142 } 143 144 147 public static String unparseTemplate(List params) { 148 StringBuffer buf = new StringBuffer (); 149 Iterator i = params.iterator(); 150 while (i.hasNext()) { 151 buf.append(i.next()); 152 if (i.hasNext()) { 153 buf.append('+'); 154 } 155 } 156 return buf.toString(); 157 } 158 159 160 public static final Pattern GEOMETRY = Pattern.compile("(\\d*)([\\%\\!\\<\\>\\@]*)"); 161 162 172 public static Dimension predictDimension(Dimension originalSize, List params) { 173 174 Dimension dim = new Dimension(originalSize); 175 String gravity = "West"; 176 Iterator i = params.iterator(); 177 while (i.hasNext()) { 178 String key = (String )i.next(); 179 int pos = key.indexOf('('); 180 int pos2 = key.lastIndexOf(')'); 181 if (pos != -1 && pos2 != -1) { 182 String type = key.substring(0, pos); 183 String cmd = key.substring(pos + 1, pos2); 184 String [] tokens = cmd.split("[x,\\n\\r]"); 185 if (log.isDebugEnabled()) { 186 log.debug("getCommands(): type=" + type + " cmd=" + cmd); 187 } 188 type = getAlias(type); 192 if (type.equals("geometry")) { 193 String xString = tokens.length > 0 ? tokens[0] : ""; 194 String yString = tokens.length > 1 ? tokens[1] : ""; 195 196 Matcher matchX = GEOMETRY.matcher(xString); 197 xString = matchX.matches() ? matchX.group(1) : ""; 198 Matcher matchY = GEOMETRY.matcher(yString); 199 yString = matchY.matches() ? matchY.group(1) : ""; 200 201 202 String options = (matchX.matches() ? matchX.group(2) : "") + (matchY.matches() ? matchY.group(2) : ""); 203 204 boolean aspectRatio = true; 205 boolean area = false; 206 boolean percentage = false; 207 boolean onlyWhenOneBigger = false; 208 boolean onlyWhenBothSmaller = false; 209 210 for (int j = 0 ; j < options.length(); j++) { 211 char o = options.charAt(j); 212 if (o == '%') percentage = true; 213 if (o == '@') area = true; 214 if (o == '!') aspectRatio = false; 215 if (o == '>') onlyWhenOneBigger = true; 216 if (o == '<') onlyWhenBothSmaller = true; 217 } 218 219 int x = "".equals(xString) ? 0 : Integer.parseInt(xString); 220 int y = "".equals(yString) ? 0 : Integer.parseInt(yString); 221 222 223 if (percentage) { 224 x *= (float) dim.x / 100.0; 225 y *= (float) dim.y / 100.0; 226 aspectRatio = false; 227 } 228 if (x == 0) { 229 x = Math.round((float) dim.x * y / dim.y); 230 } 231 232 if (area) { 233 float a = x; 234 if (dim.getArea() > a) { 235 float ratio = (float) dim.x / dim.y; 236 x = (int) Math.floor(Math.sqrt(a * ratio)); 237 y = (int) Math.floor(Math.sqrt(a / ratio)); 238 } else { 239 x = dim.x; 240 y = dim.y; 241 } 242 aspectRatio = false; } 244 245 if (y == 0) { 246 y = Math.round((float) dim.y * x / dim.x); 247 } 248 249 250 boolean skipScale = 251 (onlyWhenOneBigger && dim.x < x && dim.y < y) || 252 (onlyWhenBothSmaller && (dim.x > x || dim.y > y)); 253 254 if (! skipScale) { 255 if (! aspectRatio) { 256 dim.x = x; 257 dim.y = y; 258 } else { 259 if ((float)dim.x/dim.y > (float)x / y) { 260 dim.y *= ((float) x / dim.x); 261 dim.x = x; 262 } else { 263 dim.x *= ((float) y / dim.y); 264 dim.y = y; 265 } 266 } 267 } 268 } else if (type.equals("border")) { 269 int x = tokens.length > 0 ? Integer.parseInt(tokens[0]) : 0; 270 int y = tokens.length > 1 ? Integer.parseInt(tokens[1]) : x; 271 dim.x += 2 * x; 272 dim.y += 2 * y; 273 } else if (type.equals("rotate")) { 274 double degrees = Double.parseDouble(tokens[0]); 275 double a = Math.toRadians(degrees); double xorg = dim.x; 277 double yorg = dim.y; 278 dim.x = (int) Math.round(Math.abs(Math.cos(a)) * xorg + Math.abs(Math.sin(a) * yorg)); 279 dim.y = (int) Math.round(Math.abs(Math.sin(a)) * xorg + Math.abs(Math.cos(a) * yorg)); 280 281 } else if (type.equals("gravity")) { 282 gravity = cmd; 283 } else if (type.equals("chop")) { 284 } else if (type.equals("shave")) { 285 } else if (type.equals("crop")) { 286 } else if (type.equals("part")) { 287 int x1 = Integer.parseInt(tokens[0]); 288 int y1 = Integer.parseInt(tokens[1]); 289 int x2 = Integer.parseInt(tokens[2]); 290 int y2 = Integer.parseInt(tokens[3]); 291 if (x2 > dim.x) x2 = dim.x; 292 if (y2 > dim.y) y2 = dim.y; 293 if (x1 > x2) x1 = x2; 294 if (y1 > y2) y1 = y2; 295 dim.x = x2 - x1; 296 dim.y = y2 - y1; 297 } 298 } 299 300 } 301 return dim; 302 } 303 304 308 public static int predictFileSize(Dimension originalDimension, int originalFileSize, Dimension predictedDimension) { 309 return originalFileSize * predictedDimension.getArea() / originalDimension.getArea(); 311 312 313 } 314 315 318 public static CKey parseCKey(String ckey) { 319 int pos = 0; 320 while (Character.isDigit(ckey.charAt(pos))) pos ++; 321 return new CKey(Integer.parseInt(ckey.substring(0, pos)), ckey.substring(pos)); 322 } 323 324 327 public static class CKey { 328 public String template; 329 public int node; 330 CKey(int n, String t) { 331 template = t; 332 node = n; 333 } 334 public String toString() { 335 return "" + node + template; 336 } 337 } 338 339 340 343 public static void main(String [] args) { 344 try { 345 File file = new File(args[0]); 346 FileInputStream input = new FileInputStream(file); 347 ByteArrayOutputStream bytes = new ByteArrayOutputStream(); 348 int b = input.read(); 349 while (b != -1) { 350 bytes.write(b); 351 b = input.read(); 352 } 353 input.close(); 354 byte[] ba = bytes.toByteArray(); 355 ImageInformer informer = new ImageMagickImageInformer(); 356 357 Dimension originalSize = informer.getDimension(ba); 358 359 ImageConverter converter1 = new ImageMagickImageConverter(); 360 ImageConverter converter2 = new JAIImageConverter(); 361 362 363 String [] templates = { 364 "s(100x60)+f(jpeg)", 365 "part(10x10x30x50)", 366 "part(10x10x2000x2000)", 367 "s(10000@)", "s(100x100@)", 368 "s(10000x2000>)", "s(100000x2000<)", 369 "s(4x5<)", "s(4x5>)", 370 "r(90)", "r(45)", "r(198)", "r(-30)", 371 "border(5)", "border(5x8)", 372 "r(45)+border(10x20)", 373 "flip", 374 "s(100)", "s(x100)", "s(10x70)", "s(70x10)", "s(60x70!)", "s(80%x150%)", 375 "s(100)+f(png)+r(20)+s(400x400)" 376 }; 377 378 System.out.println("original size: " + originalSize); 379 System.out.println("template:predicted size:actual size (IM):actual size(JAI)"); 380 for (int i = 0 ; i < templates.length; i++) { 381 382 String template = templates[i]; 383 List params = parseTemplate(template); 384 System.out.print(template + ":" + predictDimension(originalSize, params) + ":"); 385 try { 386 System.out.print(informer.getDimension(converter1.convertImage(ba, null, params))); 387 } catch (Exception e) { 388 System.out.print(e.getMessage()); 389 } 390 System.out.print(":"); 391 try { 392 System.out.print(informer.getDimension(converter2.convertImage(ba, null, params))); 393 } catch (Exception e) { 394 System.out.print(e.getMessage()); 395 } 396 System.out.println(""); 397 } 398 399 } catch (IOException ioe) { 400 throw new RuntimeException (ioe); 401 } 402 403 } 404 405 } 406 | Popular Tags |