Subversion Repositories general

Rev

Rev 1251 | Rev 1257 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
936 dev 1
package ak.photoalbum.images;
2
 
3
import java.util.Map;
4
import java.util.HashMap;
5
import java.util.Comparator;
6
import java.util.Arrays;
1074 dev 7
import java.io.*; // FIXME
936 dev 8
import java.io.File;
9
import java.io.FileFilter;
10
import java.io.IOException;
11
import java.io.FileInputStream;
12
import java.io.FileOutputStream;
13
import java.io.OutputStream;
14
import java.awt.Image;
15
import java.awt.Toolkit;
16
import java.awt.Graphics;
17
import java.awt.image.BufferedImage;
18
import java.awt.image.ImageObserver;
19
import java.awt.image.PixelGrabber;
20
import javax.imageio.ImageIO;
21
import org.apache.log4j.Logger;
22
import marcoschmidt.image.ImageInfo;
23
import ak.photoalbum.util.FileUtils;
24
import ak.photoalbum.util.FileNameComparator;
25
 
26
public class Thumbnailer
27
{
28
  protected static final String DEFAULT_FORMAT        = "jpg";
29
  protected static final String SMALL_SUFFIX          = ".small";
30
  protected static final String MEDIUM_SUFFIX         = ".medium";
31
  protected static final String DIR_SUFFIX            = ".dir";
1074 dev 32
  protected static final String DIR_PART_SUFFIX       = ".dir_part";
936 dev 33
  protected static final int    DEFAULT_SMALL_WIDTH   = 120;
34
  protected static final int    DEFAULT_SMALL_HEIGHT  = 120;
35
  protected static final int    DEFAULT_MEDIUM_WIDTH  = 800;
36
  protected static final int    DEFAULT_MEDIUM_HEIGHT = 800;
37
 
38
  protected Logger       logger;
39
  protected ImageResizer resizer;
40
  protected int          smallWidth            = DEFAULT_SMALL_WIDTH;
41
  protected int          smallHeight           = DEFAULT_SMALL_HEIGHT;
42
  protected int          mediumWidth           = DEFAULT_MEDIUM_WIDTH;
43
  protected int          mediumHeight          = DEFAULT_MEDIUM_HEIGHT;
44
  protected File         cacheDir;
45
  protected String       format                = DEFAULT_FORMAT;
46
  protected Map          smallCache            = new HashMap();
47
  protected Map          mediumCache           = new HashMap();
48
  protected Map          dirCache              = new HashMap();
49
  protected File         imagesRoot;
50
  protected FileFilter   imagesFilter          = null;
51
  protected Comparator   fileNameComparator    = new FileNameComparator(true);
52
  protected Comparator   fileNameComparatorRev = new FileNameComparator(false);
1074 dev 53
  protected boolean      nativeMode            = true; // FIXME config
936 dev 54
 
55
  protected File                dirTemplate;
56
  protected ThumbnailPosition[] dirThumbnailPositions;
57
  protected int[]               dirTemplateSize;
58
  protected long                dirTemplateTimestamp;
59
 
60
  public Thumbnailer()
61
  {
62
    this.logger = Logger.getLogger(this.getClass());
63
  }
64
 
65
  public String getMime()
66
  {
67
    return FileUtils.getMime(format);
68
  }
69
 
70
  public int[] getDirSize(File origin)
71
    throws IOException
72
  {
73
    if(dirTemplateSize == null
74
      || dirTemplateTimestamp != dirTemplate.lastModified())
75
    {
76
      dirTemplateSize      = getOriginSize(dirTemplate);
77
      dirTemplateTimestamp = dirTemplate.lastModified();
78
    }
79
 
80
    return dirTemplateSize;
81
  }
82
 
83
  public int[] getSmallSize(File origin)
84
    throws IOException
85
  {
86
    CachedFile cached = getCached(smallCache, origin);
87
 
88
    if(cached == null) {
89
      int[] originSize = getOriginSize(origin);
90
 
91
      return calcSizes(originSize[0], originSize[1], smallWidth, smallHeight);
92
    }
93
    else {
94
      int[] originSize = new int[2];
95
 
96
      originSize[0] = cached.getWidth();
97
      originSize[1] = cached.getHeight();
98
 
99
      return originSize;
100
    }
101
  }
102
 
103
  public int[] getMediumSize(File origin)
104
    throws IOException
105
  {
106
    CachedFile cached = getCached(mediumCache, origin);
107
 
108
    if(cached == null) {
109
      int[] originSize = getOriginSize(origin);
110
 
111
      return calcSizes(originSize[0], originSize[1], mediumWidth, mediumHeight);
112
    }
113
    else {
114
      int[] originSize = new int[2];
115
 
116
      originSize[0] = cached.getWidth();
117
      originSize[1] = cached.getHeight();
118
 
119
      return originSize;
120
    }
121
  }
122
 
123
  protected int[] getOriginSize(File origin)
124
    throws IOException
125
  {
126
    if(logger.isDebugEnabled())
127
      logger.debug("get size of " + origin.getCanonicalPath());
128
 
129
    ImageInfo       ii  = new ImageInfo();
130
    FileInputStream in  = null;
131
    int[]           res = new int[2];
132
 
133
    try {
134
      in = new FileInputStream(origin);
135
      ii.setInput(in);
136
 
137
      if(!ii.check()) {
138
        logger.warn("not supported format of " + origin.getCanonicalPath());
139
        res[0] = 0;
140
        res[1] = 0;
141
      }
142
      else{
143
        res[0] = ii.getWidth();
144
        res[1] = ii.getHeight();
145
      }
146
    }
147
    finally {
148
      if(in != null) in.close();
149
    }
150
 
151
    return res;
152
  }
153
 
154
  public void rebuildCache()
155
    throws IOException
156
  {
157
    logger.info("rebuild cache");
158
 
159
    deleteCache();
160
    buildCache();
161
  }
162
 
163
  public void deleteCache()
164
    throws IOException
165
  {
166
    logger.info("delete cache");
167
 
168
    deleteCache(cacheDir);
169
  }
170
 
171
  public void buildCache()
172
    throws IOException
173
  {
174
    logger.info("build cache");
175
 
176
    buildCache(imagesRoot);
177
  }
178
 
179
  protected void deleteCache(File dir)
180
    throws IOException
181
  {
182
    File[] children = dir.listFiles();
183
 
184
    if(children == null) return; // the dir does not exists
185
 
186
    Arrays.sort(children, fileNameComparator);
187
 
188
    for(int i = 0; i < children.length; i++) {
189
      if(children[i].isDirectory())
190
        deleteCache(children[i]);
191
      else
192
        children[i].delete();
193
    }
194
    dir.delete();
195
  }
196
 
197
  protected void buildCache(File dir)
198
    throws IOException
199
  {
200
    File[] children;
201
 
202
    if(imagesFilter == null)
203
      children = dir.listFiles();
204
    else
205
      children = dir.listFiles(imagesFilter);
206
 
207
    if(children == null) return; // the dir does not exists
208
 
209
    Arrays.sort(children, fileNameComparator);
210
 
211
    for(int i = 0; i < children.length; i++) {
212
      if(children[i].isDirectory()) {
213
        writeDir(children[i], null);
214
        buildCache(children[i]);
215
      }
216
      else {
217
        writeSmall(children[i], null);
218
        writeMedium(children[i], null);
219
      }
220
    }
221
  }
222
 
223
  protected CachedFile getCached(Map cache, File imageFile)
224
    throws IOException
225
  {
226
    CachedFile cached = (CachedFile)cache.get(imageFile.getCanonicalPath());
227
 
228
    if(cached == null || !cached.getFile().exists()) {
229
      logger.debug("not found in cache");
230
      return null;
231
    }
232
 
233
    if(cached.getOriginTimestamp() != imageFile.lastModified()) {
234
      cached.getFile().delete();
235
      cache.remove(imageFile.getCanonicalPath());
236
      logger.debug("timestamps dont match");
237
      return null;
238
    }
239
 
240
    return cached;
241
  }
242
 
243
  protected boolean writeCached(Map cache, File imageFile, OutputStream out)
244
    throws IOException
245
  {
246
    CachedFile cached = getCached(cache, imageFile);
247
 
248
    if(cached == null) return false;
249
 
250
    if(logger.isDebugEnabled())
251
      logger.debug("write cached " + imageFile.getCanonicalPath());
252
 
253
    if(out != null) {
254
      FileInputStream in = null;
255
 
256
      try {
257
        in  = new FileInputStream(cached.getFile());
258
        FileUtils.copyStreams(in, out);
259
      }
260
      finally {
261
        if(in != null) in.close();
262
      }
263
    }
264
 
265
    return true;
266
  }
267
 
1074 dev 268
  protected File getCacheFile(File dir, File imageFile, String suffix)
269
  {
270
    return new File(dir, imageFile.getName() + suffix + "." + format);
271
  }
272
 
936 dev 273
  protected void cacheThumbnail(Map cache, File imageFile,
274
      BufferedImage thumbnail, String suffix, int width, int height)
275
    throws IOException
276
  {
277
    logger.debug("cache thumbnail " + suffix + " "
278
      + imageFile.getCanonicalPath());
279
 
280
    File dir       = getCacheFileDir(imageFile);
1074 dev 281
    File cacheFile = getCacheFile(dir, imageFile, suffix);
936 dev 282
 
283
    dir.mkdirs();
284
    ImageIO.write(thumbnail, format, cacheFile);
285
 
286
    cache.put(imageFile.getCanonicalPath(),
287
      new CachedFile(cacheFile, imageFile,
288
      cacheFile.lastModified(), imageFile.lastModified(), width, height));
289
  }
290
 
291
  public void startup()
292
    throws IOException
293
  {
294
    logger.info("startup");
295
    loadCaches(cacheDir);
296
    logger.info("started");
297
  }
298
 
1074 dev 299
	protected void loadFileCache(File file)
936 dev 300
    throws IOException
1074 dev 301
	{
302
		/* FIXME use this optimization?
936 dev 303
    String dirEnd    = DIR_SUFFIX    + "." + format;
304
    String smallEnd  = SMALL_SUFFIX  + "." + format;
305
    String mediumEnd = MEDIUM_SUFFIX + "." + format;
1074 dev 306
    */
936 dev 307
 
1251 dev 308
    File origin = null;
309
    Map  cache  = null;
936 dev 310
 
1074 dev 311
    if(file.getName().endsWith(SMALL_SUFFIX + "." + format)) {
312
      origin = getOriginFile(file, SMALL_SUFFIX);
313
      cache  = smallCache;
936 dev 314
 
1074 dev 315
      if(logger.isDebugEnabled())
316
        logger.debug("load cached small " + file.getCanonicalPath()
317
          + " for " + origin.getCanonicalPath());
318
    }
319
    else if(file.getName().endsWith(MEDIUM_SUFFIX + "." + format)) {
320
      origin = getOriginFile(file, MEDIUM_SUFFIX);
321
      cache  = mediumCache;
936 dev 322
 
1074 dev 323
      if(logger.isDebugEnabled())
324
        logger.debug("load cached medium " + file.getCanonicalPath()
325
          + " for " + origin.getCanonicalPath());
326
    }
327
    else if(file.getName().endsWith(DIR_SUFFIX + "." + format)) {
328
      origin = getOriginFile(file, DIR_SUFFIX);
329
      cache  = dirCache;
936 dev 330
 
1074 dev 331
      if(logger.isDebugEnabled())
332
        logger.debug("load cached dir " + file.getCanonicalPath()
333
          + " for " + origin.getCanonicalPath());
334
    }
1251 dev 335
    else if(file.getName().endsWith(DIR_PART_SUFFIX + "." + format)) {
336
      if(logger.isDebugEnabled())
337
        logger.debug("skip cached dir part " + file.getCanonicalPath());
338
    }
1074 dev 339
    else {
340
      if(logger.isInfoEnabled())
341
        logger.warn(
342
          "unknown type of cached " + file.getCanonicalPath());
343
    }
936 dev 344
 
1251 dev 345
    if(origin != null && cache != null)
346
      loadCacheInfo(file, origin, cache);
1074 dev 347
	}
936 dev 348
 
1074 dev 349
	protected void loadCacheInfo(File file, File origin, Map cache)
350
    throws IOException
351
	{
352
    long  originTimestamp = origin.lastModified();
353
    long  cachedTimestamp = file.lastModified();
354
    int[] sizes           = getOriginSize(file);
936 dev 355
 
1074 dev 356
    if(origin.exists() && cachedTimestamp >= originTimestamp) {
357
      cache.put(origin.getCanonicalPath(),
358
        new CachedFile(file, origin, cachedTimestamp,
359
          originTimestamp, sizes[0], sizes[1]));
936 dev 360
 
1074 dev 361
      logger.debug("added");
362
    }
363
    else {
364
      file.delete();
936 dev 365
 
1074 dev 366
      if(logger.isDebugEnabled())
367
        logger.debug("deleted: " + origin.exists()
368
          + " " + cachedTimestamp + " " + originTimestamp);
369
    }
370
	}
936 dev 371
 
1074 dev 372
  protected void loadCaches(File dir)
373
    throws IOException
374
  {
375
    if(logger.isDebugEnabled())
376
      logger.debug("load caches in " + dir.getCanonicalPath());
377
 
378
    File[] children = dir.listFiles();
379
 
380
    if(children == null) return; // the dir does not exists
381
 
382
    Arrays.sort(children, fileNameComparator);
383
 
384
    for(int i = 0; i < children.length; i++) {
385
      if(children[i].isDirectory())
386
        loadCaches(children[i]);
387
      else
388
      	loadFileCache(children[i]);
936 dev 389
    }
390
  }
391
 
392
  protected File getOriginFile(File cached, String suffix)
393
    throws IOException
394
  {
395
    String fileEnd    = suffix + "." + format;
396
    String fileName   = cached.getName();
397
    String cachedPath = cached.getParentFile().getCanonicalPath();
398
    String cacheRoot  = cacheDir.getCanonicalPath();
399
 
400
    fileName = fileName.substring(0, fileName.length() - fileEnd.length());
401
 
402
    if(!cacheRoot.equals(cachedPath))
403
      if(!cacheRoot.endsWith(File.separator)) cacheRoot += File.separator;
404
 
405
    return new File(imagesRoot, cachedPath.substring(cacheRoot.length())
406
      + File.separator + fileName);
407
  }
408
 
409
  protected File getCacheFileDir(File imageFile)
410
    throws IOException
411
  {
412
    String imagePath = imageFile.getParentFile().getCanonicalPath();
413
    String rootPath  = imagesRoot.getCanonicalPath();
414
 
415
    if(imagePath.equals(rootPath)) return cacheDir;
416
    if(!rootPath.endsWith(File.separator)) rootPath += File.separator;
417
 
418
    if(!imagePath.startsWith(rootPath))
419
      throw new RuntimeException("Image " + imageFile.getCanonicalPath()
420
        + " is not under images root " + imagesRoot.getCanonicalPath());
421
 
422
    return new File(cacheDir, imagePath.substring(rootPath.length()));
423
  }
424
 
425
  public void writeSmall(File imageFile, OutputStream out)
426
    throws IOException
427
  {
428
    if(logger.isInfoEnabled())
429
      logger.info("write small " + imageFile.getCanonicalPath());
430
 
431
    if(writeCached(smallCache, imageFile, out)) return;
432
 
1074 dev 433
		if(nativeMode) {
434
			File dir       = getCacheFileDir(imageFile);
435
			File cacheFile = getCacheFile(dir, imageFile, SMALL_SUFFIX);
936 dev 436
 
1074 dev 437
    	createThumbnailNative(dir, cacheFile, imageFile, smallWidth, smallHeight);
438
			loadCacheInfo(cacheFile, imageFile, smallCache);
439
      writeCached(smallCache, imageFile, out);
440
		}
441
		else {
442
    	BufferedImage small = createThumbnail(imageFile, smallWidth, smallHeight);
936 dev 443
 
1074 dev 444
	    if(small != null) {
445
	    	// a thumbnail returned - save it into the cache dir
446
	      int sizes[] = calcSizes(
447
	        small.getWidth(null), small.getHeight(null), smallWidth, smallHeight);
448
	      cacheThumbnail(
449
	        smallCache, imageFile, small, SMALL_SUFFIX, sizes[0], sizes[1]);
450
 
451
	      if(out != null) ImageIO.write(small, format, out);
452
	    }
453
		}
936 dev 454
  }
455
 
456
  public void writeMedium(File imageFile, OutputStream out)
457
    throws IOException
458
  {
459
    if(logger.isInfoEnabled())
460
      logger.info("write medium " + imageFile.getCanonicalPath());
461
 
462
    if(writeCached(mediumCache, imageFile, out)) return;
463
 
1074 dev 464
		if(nativeMode) {
465
			File dir       = getCacheFileDir(imageFile);
466
			File cacheFile = getCacheFile(dir, imageFile, MEDIUM_SUFFIX);
936 dev 467
 
1074 dev 468
    	createThumbnailNative(dir, cacheFile, imageFile, mediumWidth, mediumHeight);
469
			loadCacheInfo(cacheFile, imageFile, mediumCache);
470
      writeCached(mediumCache, imageFile, out);
471
		}
472
		else {
473
    	BufferedImage medium = createThumbnail(imageFile, mediumWidth, mediumHeight);
936 dev 474
 
1074 dev 475
	    if(medium != null) {
476
	    	// a image returned - save it into the cache dir
477
	      int sizes[] = calcSizes(medium.getWidth(null), medium.getHeight(null),
478
	        mediumWidth, mediumHeight);
479
	      cacheThumbnail(
480
	        mediumCache, imageFile, medium, MEDIUM_SUFFIX, sizes[0], sizes[1]);
481
 
482
	      if(out != null) ImageIO.write(medium, format, out);
483
	    }
484
	  }
936 dev 485
  }
486
 
487
  public void writeDir(File dir, OutputStream out)
488
    throws IOException
489
  {
490
    if(logger.isInfoEnabled())
491
      logger.info("write dir " + dir.getCanonicalPath());
492
 
493
    if(writeCached(dirCache, dir, out)) return;
494
 
495
    BufferedImage thumbnail = createDirThumbnail(dir);
496
 
497
    if(thumbnail != null) {
498
      if(dirTemplateSize == null
499
        || dirTemplateTimestamp != dirTemplate.lastModified())
500
      {
501
        dirTemplateSize      = getOriginSize(dirTemplate);
502
        dirTemplateTimestamp = dirTemplate.lastModified();
503
      }
504
 
505
      cacheThumbnail(dirCache, dir, thumbnail, DIR_SUFFIX,
506
        dirTemplateSize[0], dirTemplateSize[1]);
507
 
508
      if(out != null) ImageIO.write(thumbnail, format, out);
509
    }
510
  }
511
 
512
  synchronized protected BufferedImage createThumbnail(File imageFile,
513
      int width, int height)
514
    throws IOException
515
  {
516
    if(logger.isDebugEnabled())
517
      logger.debug("create thumbnail " + imageFile.getCanonicalPath());
518
 
519
    Image image = loadImage(imageFile.getCanonicalPath());
520
      // = ImageIO.read(imageFile);
521
    int[] sizes;
522
 
523
    if(image == null) {   // not supported format
524
      logger.warn("unsupported format for origin or operation interrupted");
525
 
526
      return null;
527
    }
528
    else {
529
      sizes = calcSizes(image.getWidth(null), image.getHeight(null),
530
        width, height);
531
      logger.debug("resize to " + sizes[0] + "x" + sizes[1]);
532
 
533
      return resizer.resize(image, sizes[0], sizes[1]);
534
    }
535
  }
536
 
1074 dev 537
  synchronized protected BufferedImage createThumbnailNative(File dir, File cacheFile,
538
  		File imageFile, int width, int height)
539
    throws IOException
540
  {
541
    if(logger.isDebugEnabled())
542
      logger.debug("create thumbnail2 " + imageFile.getCanonicalPath() + " to "
543
      	+	cacheFile.getCanonicalPath());
544
 
545
    dir.mkdirs();
546
 
547
		// FIMXE: 1) make util path (and params?) configurable
548
		Process process = Runtime.getRuntime().exec(new String[] {
549
			"/usr/local/bin/convert",
550
			"-size",      width + "x" + height,
551
			"-thumbnail", width + "x" + height,
552
      imageFile.getCanonicalPath(),
553
    	cacheFile.getCanonicalPath()
554
		});
555
 
556
    // FIXME make it finner
557
    BufferedReader in = new BufferedReader(new InputStreamReader(process.getErrorStream()));
558
    String line;
559
    while((line = in.readLine()) != null) {
560
    	System.out.println("EXEC: " + line);
561
    }
562
 
563
		try {
564
	    int res = process.waitFor();
565
 
566
	    if(logger.isDebugEnabled())
567
	      logger.debug("process exited with result " + res);
568
		}
569
		catch(InterruptedException ex) {
570
      logger.debug("process interrupted");
571
		}
572
 
573
    return null;
574
  }
575
 
936 dev 576
  synchronized protected BufferedImage createDirThumbnail(File dir)
577
    throws IOException
578
  {
1074 dev 579
	long timeStart = System.currentTimeMillis();
580
 
936 dev 581
    if(logger.isDebugEnabled())
582
      logger.debug("create dir thumbnail " + dir.getCanonicalPath());
583
 
584
    Image         template = loadImage(dirTemplate.getCanonicalPath());
585
    BufferedImage dirThumbnail;
586
    Graphics      graphics;
587
    int           count;
588
    File[]        firstFiles;
589
 
590
    if(template == null) {   // not supported format
591
      logger.warn("unsupported format for template or operation interrupted");
592
 
593
      return null;
594
    }
595
 
596
    dirThumbnail = createBufferedImage(template);
597
 
598
    graphics     = dirThumbnail.getGraphics();
599
    count        = dirThumbnailPositions.length;
600
    firstFiles   = new File[count];
601
    count        = getFirstFiles(dir, count, firstFiles, 0);
602
 
603
    for(int i = 0; i < count; i++) {
1074 dev 604
      Image         image;
605
      BufferedImage thumbnail = null;
606
      int[]         sizes;
936 dev 607
 
1074 dev 608
			if(nativeMode) {
609
				File cacheFileDir = getCacheFileDir(firstFiles[i]);
610
				File cacheFile    = getCacheFile(cacheFileDir, firstFiles[i], DIR_PART_SUFFIX);
611
	    	createThumbnailNative(cacheFileDir, cacheFile, firstFiles[i],
612
	    		dirThumbnailPositions[i].getWidth(), dirThumbnailPositions[i].getHeight());
613
	      image     = loadImage(cacheFile.getCanonicalPath());
614
	      thumbnail = createBufferedImage(image);
615
			}
616
			else {
617
	      image = loadImage(firstFiles[i].getCanonicalPath());
618
      }
619
 
936 dev 620
      if(image == null) {   // not supported format
621
        logger.warn("unsupported format for origin or operation interrupted");
622
 
623
        return null;
624
      }
625
      else {
626
        sizes = calcSizes(image.getWidth(null), image.getHeight(null),
627
          dirThumbnailPositions[i].getWidth(),
628
          dirThumbnailPositions[i].getHeight());
1074 dev 629
      }
936 dev 630
 
1074 dev 631
			if(!nativeMode) {
936 dev 632
        thumbnail = resizer.resize(image, sizes[0], sizes[1]);
633
      }
1074 dev 634
 
635
      graphics.drawImage(thumbnail,
636
        getXPosition(dirThumbnailPositions[i].getX(),
637
          dirThumbnailPositions[i].getWidth(), sizes[0],
638
          dirThumbnailPositions[i].getHorAlign()),
639
        getYPosition(dirThumbnailPositions[i].getY(),
640
          dirThumbnailPositions[i].getHeight(), sizes[1],
641
          dirThumbnailPositions[i].getVertAlign()),
642
        null);
936 dev 643
    }
644
 
1074 dev 645
    if(logger.isDebugEnabled()) {
646
      logger.debug("dir thumbnail created in "
647
      	+ (System.currentTimeMillis() - timeStart) + " ms");
648
    }
649
 
936 dev 650
    return dirThumbnail;
651
  }
652
 
653
  protected Image loadImage(String fileName)
654
  {
1074 dev 655
	long timeStart = System.currentTimeMillis();
656
 
936 dev 657
    // FIXME: probably toolbox reads an image not by every request but
658
    //        caches it
659
    Toolkit toolkit = Toolkit.getDefaultToolkit();
660
    Image   image   = toolkit.getImage(fileName);
661
 
662
    toolkit.prepareImage(image, -1, -1, null);
663
 
664
    while(true) {
665
      int status = toolkit.checkImage(image, -1, -1, null);
666
 
667
      if((status & ImageObserver.ALLBITS) != 0) break;
668
      if((status & ImageObserver.ERROR)   != 0) return null;
669
 
670
      try {
671
        Thread.sleep(100);
672
      }
673
      catch(Exception ex) {
674
        return null;
675
      }
676
    }
677
 
1074 dev 678
    if(logger.isDebugEnabled()) {
679
      logger.debug("image " + fileName + " loaded in "
680
      	+ (System.currentTimeMillis() - timeStart) + " ms");
681
    }
682
 
936 dev 683
    return image;
684
  }
685
 
686
  protected int[] calcSizes(int width, int height, int maxWidth, int maxHeight)
687
  {
688
    int[]  result = new int[2];
689
    double xRate;
690
    double yRate;
691
 
692
    if(width == 0 || height == 0) {
693
      result[0] = 0;
694
      result[1] = 0;
695
      return result;
696
    }
697
 
698
    xRate  = (double)maxWidth  / (double)width;
699
    yRate  = (double)maxHeight / (double)height;
700
    if(xRate >= 1.0 || yRate >= 1.0) {
701
      result[0] = width;
702
      result[1] = height;
703
    }
704
    else if(xRate > yRate) {
705
      result[0] = maxHeight * width / height;
706
      result[1] = maxHeight;
707
    }
708
    else {
709
      result[0] = maxWidth;
710
      result[1] = maxWidth * height / width;
711
    }
712
 
713
    return result;
714
  }
715
 
716
  protected int getXPosition(int left, int maxWidth, int width, int align)
717
  {
718
    if(align == ThumbnailPosition.ALIGN_HOR_LEFT)
719
      return left;
720
    else if(align == ThumbnailPosition.ALIGN_HOR_RIGHT)
721
      return left + (maxWidth - width);
722
    else if(align == ThumbnailPosition.ALIGN_HOR_CENTER)
723
      return left + (maxWidth - width) / 2;
724
    else
725
      throw new RuntimeException("Unknown align type: " + align);
726
  }
727
 
728
  protected int getYPosition(int top, int maxHeight, int height, int align)
729
  {
730
    if(align == ThumbnailPosition.ALIGN_VERT_TOP)
731
      return top;
732
    else if(align == ThumbnailPosition.ALIGN_VERT_BOTTOM)
733
      return top + (maxHeight - height);
734
    else if(align == ThumbnailPosition.ALIGN_VERT_CENTER)
735
      return top + (maxHeight - height) / 2;
736
    else
737
      throw new RuntimeException("Unknown align type: " + align);
738
  }
739
 
740
  protected int getFirstFiles(File dir, int count, File[] files, int pos)
741
  {
742
    File[] children;
743
 
744
    if(imagesFilter == null)
745
      children = dir.listFiles();
746
    else
747
      children = dir.listFiles(imagesFilter);
748
 
749
    if(children == null) return 0; // the dir does not exists
750
 
751
    Arrays.sort(children, fileNameComparatorRev);
752
 
1254 dev 753
    for(int i = 0; i < children.length && pos < count; i++) {
936 dev 754
      if(children[i].isDirectory())
755
        ; //pos = getFirstFiles(children[i], count, files, pos);
756
      else {
757
        files[pos++] = children[i];
758
      }
759
    }
760
 
761
    return pos;
762
  }
763
 
764
  protected BufferedImage createBufferedImage(Image image)
765
  {
766
    if(image == null) return null;
767
 
768
    int width  = image.getWidth(null);
769
    int height = image.getHeight(null);
770
 
771
    if(width < 1 || height < 1) return null;
772
 
773
    // get pixels
774
    int[]        pixels = new int[width * height];
775
    PixelGrabber pg     = new PixelGrabber(image,
776
      0, 0, width, height, pixels, 0, width);
777
 
778
    try  {
779
      pg.grabPixels();
780
    }
781
    catch(InterruptedException e) {
782
      return null;
783
    }
784
 
785
    if((pg.getStatus() & ImageObserver.ABORT) != 0) return null;
786
 
787
    // create buffered image
788
    BufferedImage buffered = new BufferedImage(width, height,
789
      BufferedImage.TYPE_INT_RGB);
790
 
791
    for(int y = 0; y < height; y++) {
792
      for(int x = 0; x < width; x++)
793
        buffered.setRGB(x, y, pixels[y * width + x]);
794
    }
795
 
796
    return buffered;
797
  }
798
 
799
  public ImageResizer getResizer()
800
  {
801
    return resizer;
802
  }
803
 
804
  public void setResizer(ImageResizer resizer)
805
  {
806
    this.resizer = resizer;
807
  }
808
 
809
  public String getFormat()
810
  {
811
    return format;
812
  }
813
 
814
  public void setFormat(String format)
815
  {
816
    this.format = format;
817
  }
818
 
819
  public File getCacheDir()
820
  {
821
    return cacheDir;
822
  }
823
 
824
  public void setCacheDir(File dir)
825
  {
826
    this.cacheDir = dir;
827
  }
828
 
829
  public File getImagesRoot()
830
  {
831
    return imagesRoot;
832
  }
833
 
834
  public void setImagesRoot(File dir)
835
  {
836
    this.imagesRoot = dir;
837
  }
838
 
839
  public int getSmallWidth()
840
  {
841
    return smallWidth;
842
  }
843
 
844
  public void setSmallWidth(int width)
845
  {
846
    this.smallWidth = width;
847
  }
848
 
849
  public int getSmallHeight()
850
  {
851
    return smallHeight;
852
  }
853
 
854
  public void setSmallHeight(int height)
855
  {
856
    this.smallHeight = height;
857
  }
858
 
859
  public int getMediumWidth()
860
  {
861
    return mediumWidth;
862
  }
863
 
864
  public void setMediumWidth(int width)
865
  {
866
    this.mediumWidth = width;
867
  }
868
 
869
  public int getMediumHeight()
870
  {
871
    return mediumHeight;
872
  }
873
 
874
  public void setMediumHeight(int height)
875
  {
876
    this.mediumHeight = height;
877
  }
878
 
879
  public FileFilter getImagesFilter()
880
  {
881
    return imagesFilter;
882
  }
883
 
884
  public void setImagesFilter(FileFilter filter)
885
  {
886
    this.imagesFilter = filter;
887
  }
888
 
889
  public File getDirTemplate()
890
  {
891
    return dirTemplate;
892
  }
893
 
894
  public void setDirTemplate(File dirTemplate)
895
  {
896
    this.dirTemplate = dirTemplate;
897
  }
898
 
899
  public ThumbnailPosition[] getDirThumbnailPositions()
900
  {
901
    return dirThumbnailPositions;
902
  }
903
 
904
  public void setDirThumbnailPositions(
905
    ThumbnailPosition[] dirThumbnailPositions)
906
  {
907
    this.dirThumbnailPositions = dirThumbnailPositions;
908
  }
909
}