001 /* 002 * jiuconvert 003 * 004 * Copyright (c) 2002, 2003 Marco Schmidt. 005 * All rights reserved. 006 */ 007 008 package net.sourceforge.jiu.apps; 009 010 import java.io.File; 011 import java.io.IOException; 012 import java.util.Hashtable; 013 import java.util.Vector; 014 import net.sourceforge.jiu.codecs.BMPCodec; 015 import net.sourceforge.jiu.codecs.CodecMode; 016 import net.sourceforge.jiu.codecs.ImageCodec; 017 import net.sourceforge.jiu.codecs.ImageLoader; 018 import net.sourceforge.jiu.codecs.InvalidFileStructureException; 019 import net.sourceforge.jiu.codecs.InvalidImageIndexException; 020 import net.sourceforge.jiu.codecs.PalmCodec; 021 import net.sourceforge.jiu.codecs.PNMCodec; 022 import net.sourceforge.jiu.codecs.UnsupportedTypeException; 023 import net.sourceforge.jiu.data.PixelImage; 024 import net.sourceforge.jiu.ops.OperationFailedException; 025 026 class JiuConvertSettings 027 { 028 static final int VERBOSITY_QUIET = 0; 029 static final int VERBOSITY_NORMAL = 1; 030 static final int VERBOSITY_HIGH = 2; 031 static final int FORMAT_UNKNOWN = -1; 032 static final int FORMAT_BMP = 0; 033 static final int FORMAT_PNM = 1; 034 static final int FORMAT_PALM = 2; 035 036 Vector inputFileNames = new Vector(); 037 File destinationDirectory; 038 int fileFormat; 039 boolean noAwtLoading; 040 boolean overwrite; 041 boolean testOnly; 042 long time1; 043 long time2; 044 int verbosity; 045 } 046 047 abstract class Switch 048 { 049 void check(JiuConvertSettings settings) { } 050 abstract String getDescription(); 051 int getMinParameters() { return 0; } 052 String getParameters() { return ""; } 053 abstract String[] getValues(); 054 abstract int init(String[] args, int index, JiuConvertSettings settings); 055 void setDefaults(JiuConvertSettings settings) { } 056 } 057 058 059 class BMPSwitch extends Switch 060 { 061 void check(JiuConvertSettings settings) 062 { 063 if (settings.fileFormat == JiuConvertSettings.FORMAT_UNKNOWN && !settings.testOnly) 064 { 065 System.err.println("ERROR: You must either use test mode or provide an output file format switch."); 066 System.exit(1); 067 } 068 } 069 String[] getValues() { return new String[] {"-b", "--bmp"}; } 070 String getDescription() { return "write Windows BMP output"; } 071 int init(String[] args, int index, JiuConvertSettings settings) 072 { 073 settings.fileFormat = JiuConvertSettings.FORMAT_BMP; 074 return index; 075 } 076 void setDefaults(JiuConvertSettings settings) { settings.fileFormat = JiuConvertSettings.FORMAT_UNKNOWN; } 077 } 078 079 class DestinationDirectorySwitch extends Switch 080 { 081 int getMinParameters() { return 1; } 082 String getDescription() { return "write output files to directory DIR"; } 083 String getParameters() { return "DIR"; } 084 String[] getValues() { return new String[] {"-d", "--destdir"}; } 085 int init(String[] args, int index, JiuConvertSettings settings) 086 { 087 String name = args[index++]; 088 File dir = new File(name); 089 if (!dir.exists()) 090 { 091 System.err.println("Directory " + name + " does not exist."); 092 System.exit(1); 093 } 094 if (!dir.isDirectory()) 095 { 096 System.err.println(name + " does not seem to be a directory."); 097 System.exit(1); 098 } 099 settings.destinationDirectory = dir; 100 return index; 101 } 102 void setDefaults(JiuConvertSettings settings) { settings.destinationDirectory = new File("."); } 103 } 104 105 class NoAwtLoadingSwitch extends Switch 106 { 107 String[] getValues() { return new String[] {"--noawtloading"}; } 108 String getDescription() { return "never use AWT Toolkit to load images"; } 109 int init(String[] args, int index, JiuConvertSettings settings) 110 { 111 settings.noAwtLoading = true; 112 return index; 113 } 114 void setDefaults(JiuConvertSettings settings) { settings.noAwtLoading = false; } 115 } 116 117 class OverwriteSwitch extends Switch 118 { 119 String[] getValues() { return new String[] {"-o", "--overwrite"}; } 120 String getDescription() { return "overwrite existing files"; } 121 int init(String[] args, int index, JiuConvertSettings settings) 122 { 123 settings.overwrite = true; 124 return index; 125 } 126 void setDefaults(JiuConvertSettings settings) { settings.overwrite = false; } 127 } 128 129 class PalmSwitch extends Switch 130 { 131 String[] getValues() { return new String[] {"-P", "--palm"}; } 132 String getDescription() { return "write Palm native image output"; } 133 int init(String[] args, int index, JiuConvertSettings settings) 134 { 135 settings.fileFormat = JiuConvertSettings.FORMAT_PALM; 136 return index; 137 } 138 } 139 140 class PNMSwitch extends Switch 141 { 142 String[] getValues() { return new String[] {"-p", "--pnm"}; } 143 String getDescription() { return "write Portable Anymap (PNM/PBM/PGM/PPM) output"; } 144 int init(String[] args, int index, JiuConvertSettings settings) 145 { 146 settings.fileFormat = JiuConvertSettings.FORMAT_PNM; 147 return index; 148 } 149 } 150 151 class PrintHelpSwitch extends Switch 152 { 153 static Vector switches; 154 String[] getValues() { return new String[] {"-H", "--help"}; } 155 String getDescription() { return "print help text to stdout and terminate"; } 156 int init(String[] args, int index, JiuConvertSettings settings) 157 { 158 System.out.println("Usage: java jiuconvert [OPTIONS] [FILEs]"); 159 System.out.println(""); 160 for (int i = 0; i < switches.size(); i++) 161 { 162 Switch sw = (Switch)switches.elementAt(i); 163 System.out.print("\t"); 164 String[] values = sw.getValues(); 165 int chars = 0; 166 for (int j = 0; j < values.length; j++) 167 { 168 if (j > 0) 169 { 170 System.out.print(", "); 171 chars += 2; 172 } 173 System.out.print(values[j]); 174 chars += values[j].length(); 175 } 176 String params = sw.getParameters(); 177 System.out.print(" " + params); 178 chars += params.length() + 1; 179 while (chars++ < 24) 180 { 181 System.out.print(" "); 182 } 183 System.out.println(sw.getDescription()); 184 } 185 System.exit(0); 186 return 0; // compiler doesn't know that System.exit(0) prevents execution ever getting here 187 } 188 } 189 190 class PrintVersionSwitch extends Switch 191 { 192 String[] getValues() { return new String[] {"-V", "--version"}; } 193 String getDescription() { return "print version to stdout and terminate"; } 194 int init(String[] args, int index, JiuConvertSettings settings) 195 { 196 System.out.println("jiuconvert " + JiuInfo.JIU_VERSION); 197 System.out.println("Written by Marco Schmidt."); 198 System.out.println("Copyright (C) 2002 Marco Schmidt."); 199 System.out.println("This is free software; see the source for copying conditions. There is NO"); 200 System.out.println("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."); 201 System.exit(0); 202 return 0; // compiler doesn't know that System.exit(0) prevents execution ever getting here 203 } 204 } 205 206 class QuietSwitch extends Switch 207 { 208 String[] getValues() { return new String[] {"-q", "--quiet"}; } 209 String getDescription() { return "print only error messages"; } 210 int init(String[] args, int index, JiuConvertSettings settings) 211 { 212 settings.verbosity = JiuConvertSettings.VERBOSITY_QUIET; 213 return index; 214 } 215 void setDefaults(JiuConvertSettings settings) { settings.verbosity = JiuConvertSettings.VERBOSITY_NORMAL; } 216 } 217 218 class TestSwitch extends Switch 219 { 220 String[] getValues() { return new String[] {"-t", "--test"}; } 221 String getDescription() { return "test loading, do not write any output files"; } 222 int init(String[] args, int index, JiuConvertSettings settings) 223 { 224 settings.testOnly = true; 225 return index; 226 } 227 void setDefaults(JiuConvertSettings settings) { settings.testOnly = false; } 228 } 229 230 class VerbositySwitch extends Switch 231 { 232 String[] getValues() { return new String[] {"-v", "--verbose"}; } 233 String getDescription() { return "print extensive information to stdout"; } 234 int init(String[] args, int index, JiuConvertSettings settings) 235 { 236 settings.verbosity = JiuConvertSettings.VERBOSITY_HIGH; 237 return index; 238 } 239 } 240 241 /** 242 * A command line program to convert between file formats. 243 * @author Marco Schmidt 244 * @since 0.10.0 245 */ 246 public class jiuconvert 247 { 248 // to prevent instances of this class 249 private jiuconvert() 250 { 251 } 252 253 private static void exit(JiuConvertSettings settings, int exitCode) 254 { 255 settings.time2 = System.currentTimeMillis(); 256 println(JiuConvertSettings.VERBOSITY_NORMAL, settings, "Time: " + ((settings.time2 - settings.time1) / 1000L) + " s."); 257 System.exit(exitCode); 258 } 259 260 private static JiuConvertSettings initFromArguments(String[] args) 261 { 262 // create switch objects 263 Vector switches = new Vector(); 264 // note that the order in which the switches are added is the order in which they are displayed 265 switches.addElement(new BMPSwitch()); 266 switches.addElement(new PalmSwitch()); 267 switches.addElement(new PNMSwitch()); 268 switches.addElement(new TestSwitch()); 269 switches.addElement(new NoAwtLoadingSwitch()); 270 switches.addElement(new OverwriteSwitch()); 271 switches.addElement(new DestinationDirectorySwitch()); 272 switches.addElement(new QuietSwitch()); 273 switches.addElement(new VerbositySwitch()); 274 switches.addElement(new PrintHelpSwitch()); 275 switches.addElement(new PrintVersionSwitch()); 276 PrintHelpSwitch.switches = switches; 277 // set defaults 278 JiuConvertSettings settings = new JiuConvertSettings(); 279 settings.time1 = System.currentTimeMillis(); 280 Hashtable switchHash = new Hashtable(); 281 for (int i = 0; i < switches.size(); i++) 282 { 283 Switch sw = (Switch)switches.elementAt(i); 284 sw.setDefaults(settings); 285 String[] values = sw.getValues(); 286 int j = 0; 287 while (j < values.length) 288 { 289 String value = values[j++]; 290 if (switchHash.get(value) != null) 291 { 292 System.err.println("FATAL INTERNAL ERROR: Switch " + value + " is used more than once."); 293 System.exit(1); 294 } 295 switchHash.put(value, sw); 296 } 297 } 298 // process arguments 299 int index = 0; 300 while (index < args.length) 301 { 302 String arg = args[index++]; 303 Switch sw = (Switch)switchHash.get(arg); 304 if (sw == null) 305 { 306 // maybe a switch that does not exist? 307 if (arg.charAt(0) == '-') 308 { 309 System.err.println("Error: Unknown switch " + arg); 310 System.exit(1); 311 } 312 // there is no switch of that name => must be a file 313 File file = new File(arg); 314 if (!file.exists() || !file.isFile()) 315 { 316 System.err.println("Error: There is no file \"" + arg + "\"."); 317 System.exit(1); 318 } 319 settings.inputFileNames.addElement(arg); 320 } 321 else 322 { 323 int minParams = sw.getMinParameters(); 324 if (index + minParams > args.length) 325 { 326 System.err.println("Error: switch " + arg + " needs at least " + minParams + " parameter(s)."); 327 System.exit(1); 328 } 329 index = sw.init(args, index, settings); 330 } 331 } 332 // now call check() on each switch 333 for (int i = 0; i < switches.size(); i++) 334 { 335 Switch sw = (Switch)switches.elementAt(i); 336 sw.check(settings); 337 } 338 // other checks 339 if (settings.inputFileNames.size() < 1) 340 { 341 System.err.println("Error: You must provide at least one input file name."); 342 System.exit(1); 343 } 344 return settings; 345 } 346 347 private static void print(int minVerbosityLevel, JiuConvertSettings settings, String message) 348 { 349 if (settings.verbosity >= minVerbosityLevel) 350 { 351 System.out.print(message); 352 } 353 } 354 355 private static void println(int minVerbosityLevel, JiuConvertSettings settings, String message) 356 { 357 if (settings.verbosity >= minVerbosityLevel) 358 { 359 System.out.println(message); 360 } 361 } 362 363 private static void run(JiuConvertSettings settings, String inputFileName) 364 { 365 String message = null; 366 PixelImage image = null; 367 try 368 { 369 image = ImageLoader.load(inputFileName, (Vector)null); 370 } 371 catch (InvalidImageIndexException iiie) 372 { 373 message = "Failed: " + iiie.toString(); 374 } 375 catch (InvalidFileStructureException ifse) 376 { 377 message = "Failed: " + ifse.toString(); 378 } 379 catch (UnsupportedTypeException ute) 380 { 381 message = "Failed: " + ute.toString(); 382 } 383 catch (IOException ioe) 384 { 385 message = "Failed: " + ioe.toString(); 386 } 387 if (message == null && image == null) 388 { 389 message = "Failed."; 390 } 391 if (message != null) 392 { 393 println(JiuConvertSettings.VERBOSITY_QUIET, settings, "\"" + inputFileName + "\" " + message); 394 return; 395 } 396 else 397 { 398 print(JiuConvertSettings.VERBOSITY_NORMAL, settings, "\"" + inputFileName + "\" "); 399 print(JiuConvertSettings.VERBOSITY_NORMAL, settings, "Loaded (" + 400 //ImageDescriptionCreator.getDescription(image, Locale.US, state) + 401 ")."); 402 } 403 if (settings.testOnly) 404 { 405 println(JiuConvertSettings.VERBOSITY_NORMAL, settings, ""); 406 return; 407 } 408 String fileExtension = null; 409 String outputFileName = inputFileName; 410 String sep = System.getProperty("file.separator"); 411 int index = outputFileName.lastIndexOf(sep); 412 if (index != -1) 413 { 414 outputFileName = outputFileName.substring(index + sep.length()); 415 } 416 index = outputFileName.lastIndexOf("."); 417 if (index != -1) 418 { 419 outputFileName = outputFileName.substring(0, index); 420 } 421 ImageCodec codec = null; 422 switch(settings.fileFormat) 423 { 424 case(JiuConvertSettings.FORMAT_BMP): 425 { 426 codec = new BMPCodec(); 427 break; 428 } 429 case(JiuConvertSettings.FORMAT_PALM): 430 { 431 codec = new PalmCodec(); 432 break; 433 } 434 case(JiuConvertSettings.FORMAT_PNM): 435 { 436 codec = new PNMCodec(); 437 break; 438 } 439 } 440 String ext = codec.suggestFileExtension(image); 441 if (ext != null) 442 { 443 outputFileName += ext; 444 } 445 File outputFile = new File(settings.destinationDirectory, outputFileName); 446 outputFileName = outputFile.getAbsolutePath(); 447 if (outputFile.exists() && !settings.overwrite) 448 { 449 println(JiuConvertSettings.VERBOSITY_NORMAL, settings, " File \"" + outputFileName + "\" already exists, skipping."); 450 } 451 codec.setImage(image); 452 try 453 { 454 codec.setFile(outputFileName, CodecMode.SAVE); 455 codec.process(); 456 codec.close(); 457 println(JiuConvertSettings.VERBOSITY_NORMAL, settings, " Wrote \"" + outputFileName + "\"."); 458 } 459 catch (IOException ioe) 460 { 461 println(JiuConvertSettings.VERBOSITY_HIGH, settings, " I/O error writing \"" + outputFileName + "\": " + ioe.toString()); 462 } 463 catch (OperationFailedException ofe) 464 { 465 println(JiuConvertSettings.VERBOSITY_HIGH, settings, " Error writing \"" + outputFileName + "\": " + ofe.toString()); 466 } 467 } 468 469 private static void run(JiuConvertSettings settings) 470 { 471 int index = 0; 472 while (index < settings.inputFileNames.size()) 473 { 474 String fileName = (String)settings.inputFileNames.elementAt(index++); 475 run(settings, fileName); 476 } 477 exit(settings, 0); 478 } 479 480 public static void main(String[] args) 481 { 482 JiuConvertSettings settings = initFromArguments(args); 483 run(settings); 484 } 485 }