Subversion Repositories general

Rev

Rev 962 | Rev 1251 | 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
 
1074 dev 308
    File origin;
309
    Map  cache;
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
    }
335
    else {
336
      if(logger.isInfoEnabled())
337
        logger.warn(
338
          "unknown type of cached " + file.getCanonicalPath());
936 dev 339
 
1074 dev 340
      return;
341
    }
936 dev 342
 
1074 dev 343
		loadCacheInfo(file, origin, cache);
344
	}
936 dev 345
 
1074 dev 346
	protected void loadCacheInfo(File file, File origin, Map cache)
347
    throws IOException
348
	{
349
    long  originTimestamp = origin.lastModified();
350
    long  cachedTimestamp = file.lastModified();
351
    int[] sizes           = getOriginSize(file);
936 dev 352
 
1074 dev 353
    if(origin.exists() && cachedTimestamp >= originTimestamp) {
354
      cache.put(origin.getCanonicalPath(),
355
        new CachedFile(file, origin, cachedTimestamp,
356
          originTimestamp, sizes[0], sizes[1]));
936 dev 357
 
1074 dev 358
      logger.debug("added");
359
    }
360
    else {
361
      file.delete();
936 dev 362
 
1074 dev 363
      if(logger.isDebugEnabled())
364
        logger.debug("deleted: " + origin.exists()
365
          + " " + cachedTimestamp + " " + originTimestamp);
366
    }
367
	}
936 dev 368
 
1074 dev 369
  protected void loadCaches(File dir)
370
    throws IOException
371
  {
372
    if(logger.isDebugEnabled())
373
      logger.debug("load caches in " + dir.getCanonicalPath());
374
 
375
    File[] children = dir.listFiles();
376
 
377
    if(children == null) return; // the dir does not exists
378
 
379
    Arrays.sort(children, fileNameComparator);
380
 
381
    for(int i = 0; i < children.length; i++) {
382
      if(children[i].isDirectory())
383
        loadCaches(children[i]);
384
      else
385
      	loadFileCache(children[i]);
936 dev 386
    }
387
  }
388
 
389
  protected File getOriginFile(File cached, String suffix)
390
    throws IOException
391
  {
392
    String fileEnd    = suffix + "." + format;
393
    String fileName   = cached.getName();
394
    String cachedPath = cached.getParentFile().getCanonicalPath();
395
    String cacheRoot  = cacheDir.getCanonicalPath();
396
 
397
    fileName = fileName.substring(0, fileName.length() - fileEnd.length());
398
 
399
    if(!cacheRoot.equals(cachedPath))
400
      if(!cacheRoot.endsWith(File.separator)) cacheRoot += File.separator;
401
 
402
    return new File(imagesRoot, cachedPath.substring(cacheRoot.length())
403
      + File.separator + fileName);
404
  }
405
 
406
  protected File getCacheFileDir(File imageFile)
407
    throws IOException
408
  {
409
    String imagePath = imageFile.getParentFile().getCanonicalPath();
410
    String rootPath  = imagesRoot.getCanonicalPath();
411
 
412
    if(imagePath.equals(rootPath)) return cacheDir;
413
    if(!rootPath.endsWith(File.separator)) rootPath += File.separator;
414
 
415
    if(!imagePath.startsWith(rootPath))
416
      throw new RuntimeException("Image " + imageFile.getCanonicalPath()
417
        + " is not under images root " + imagesRoot.getCanonicalPath());
418
 
419
    return new File(cacheDir, imagePath.substring(rootPath.length()));
420
  }
421
 
422
  public void writeSmall(File imageFile, OutputStream out)
423
    throws IOException
424
  {
425
    if(logger.isInfoEnabled())
426
      logger.info("write small " + imageFile.getCanonicalPath());
427
 
428
    if(writeCached(smallCache, imageFile, out)) return;
429
 
1074 dev 430
		if(nativeMode) {
431
			File dir       = getCacheFileDir(imageFile);
432
			File cacheFile = getCacheFile(dir, imageFile, SMALL_SUFFIX);
936 dev 433
 
1074 dev 434
    	createThumbnailNative(dir, cacheFile, imageFile, smallWidth, smallHeight);
435
			loadCacheInfo(cacheFile, imageFile, smallCache);
436
      writeCached(smallCache, imageFile, out);
437
		}
438
		else {
439
    	BufferedImage small = createThumbnail(imageFile, smallWidth, smallHeight);
936 dev 440
 
1074 dev 441
	    if(small != null) {
442
	    	// a thumbnail returned - save it into the cache dir
443
	      int sizes[] = calcSizes(
444
	        small.getWidth(null), small.getHeight(null), smallWidth, smallHeight);
445
	      cacheThumbnail(
446
	        smallCache, imageFile, small, SMALL_SUFFIX, sizes[0], sizes[1]);
447
 
448
	      if(out != null) ImageIO.write(small, format, out);
449
	    }
450
		}
936 dev 451
  }
452
 
453
  public void writeMedium(File imageFile, OutputStream out)
454
    throws IOException
455
  {
456
    if(logger.isInfoEnabled())
457
      logger.info("write medium " + imageFile.getCanonicalPath());
458
 
459
    if(writeCached(mediumCache, imageFile, out)) return;
460
 
1074 dev 461
		if(nativeMode) {
462
			File dir       = getCacheFileDir(imageFile);
463
			File cacheFile = getCacheFile(dir, imageFile, MEDIUM_SUFFIX);
936 dev 464
 
1074 dev 465
    	createThumbnailNative(dir, cacheFile, imageFile, mediumWidth, mediumHeight);
466
			loadCacheInfo(cacheFile, imageFile, mediumCache);
467
      writeCached(mediumCache, imageFile, out);
468
		}
469
		else {
470
    	BufferedImage medium = createThumbnail(imageFile, mediumWidth, mediumHeight);
936 dev 471
 
1074 dev 472
	    if(medium != null) {
473
	    	// a image returned - save it into the cache dir
474
	      int sizes[] = calcSizes(medium.getWidth(null), medium.getHeight(null),
475
	        mediumWidth, mediumHeight);
476
	      cacheThumbnail(
477
	        mediumCache, imageFile, medium, MEDIUM_SUFFIX, sizes[0], sizes[1]);
478
 
479
	      if(out != null) ImageIO.write(medium, format, out);
480
	    }
481
	  }
936 dev 482
  }
483
 
484
  public void writeDir(File dir, OutputStream out)
485
    throws IOException
486
  {
487
    if(logger.isInfoEnabled())
488
      logger.info("write dir " + dir.getCanonicalPath());
489
 
490
    if(writeCached(dirCache, dir, out)) return;
491
 
492
    BufferedImage thumbnail = createDirThumbnail(dir);
493
 
494
    if(thumbnail != null) {
495
      if(dirTemplateSize == null
496
        || dirTemplateTimestamp != dirTemplate.lastModified())
497
      {
498
        dirTemplateSize      = getOriginSize(dirTemplate);
499
        dirTemplateTimestamp = dirTemplate.lastModified();
500
      }
501
 
502
      cacheThumbnail(dirCache, dir, thumbnail, DIR_SUFFIX,
503
        dirTemplateSize[0], dirTemplateSize[1]);
504
 
505
      if(out != null) ImageIO.write(thumbnail, format, out);
506
    }
507
  }
508
 
509
  synchronized protected BufferedImage createThumbnail(File imageFile,
510
      int width, int height)
511
    throws IOException
512
  {
513
    if(logger.isDebugEnabled())
514
      logger.debug("create thumbnail " + imageFile.getCanonicalPath());
515
 
516
    Image image = loadImage(imageFile.getCanonicalPath());
517
      // = ImageIO.read(imageFile);
518
    int[] sizes;
519
 
520
    if(image == null) {   // not supported format
521
      logger.warn("unsupported format for origin or operation interrupted");
522
 
523
      return null;
524
    }
525
    else {
526
      sizes = calcSizes(image.getWidth(null), image.getHeight(null),
527
        width, height);
528
      logger.debug("resize to " + sizes[0] + "x" + sizes[1]);
529
 
530
      return resizer.resize(image, sizes[0], sizes[1]);
531
    }
532
  }
533
 
1074 dev 534
  synchronized protected BufferedImage createThumbnailNative(File dir, File cacheFile,
535
  		File imageFile, int width, int height)
536
    throws IOException
537
  {
538
    if(logger.isDebugEnabled())
539
      logger.debug("create thumbnail2 " + imageFile.getCanonicalPath() + " to "
540
      	+	cacheFile.getCanonicalPath());
541
 
542
    dir.mkdirs();
543
 
544
		// FIMXE: 1) make util path (and params?) configurable
545
		Process process = Runtime.getRuntime().exec(new String[] {
546
			"/usr/local/bin/convert",
547
			"-size",      width + "x" + height,
548
			"-thumbnail", width + "x" + height,
549
      imageFile.getCanonicalPath(),
550
    	cacheFile.getCanonicalPath()
551
		});
552
 
553
    // FIXME make it finner
554
    BufferedReader in = new BufferedReader(new InputStreamReader(process.getErrorStream()));
555
    String line;
556
    while((line = in.readLine()) != null) {
557
    	System.out.println("EXEC: " + line);
558
    }
559
 
560
		try {
561
	    int res = process.waitFor();
562
 
563
	    if(logger.isDebugEnabled())
564
	      logger.debug("process exited with result " + res);
565
		}
566
		catch(InterruptedException ex) {
567
      logger.debug("process interrupted");
568
		}
569
 
570
    return null;
571
  }
572
 
936 dev 573
  synchronized protected BufferedImage createDirThumbnail(File dir)
574
    throws IOException
575
  {
1074 dev 576
	long timeStart = System.currentTimeMillis();
577
 
936 dev 578
    if(logger.isDebugEnabled())
579
      logger.debug("create dir thumbnail " + dir.getCanonicalPath());
580
 
581
    Image         template = loadImage(dirTemplate.getCanonicalPath());
582
    BufferedImage dirThumbnail;
583
    Graphics      graphics;
584
    int           count;
585
    File[]        firstFiles;
586
 
587
    if(template == null) {   // not supported format
588
      logger.warn("unsupported format for template or operation interrupted");
589
 
590
      return null;
591
    }
592
 
593
    dirThumbnail = createBufferedImage(template);
594
 
595
    graphics     = dirThumbnail.getGraphics();
596
    count        = dirThumbnailPositions.length;
597
    firstFiles   = new File[count];
598
    count        = getFirstFiles(dir, count, firstFiles, 0);
599
 
600
    for(int i = 0; i < count; i++) {
1074 dev 601
      Image         image;
602
      BufferedImage thumbnail = null;
603
      int[]         sizes;
936 dev 604
 
1074 dev 605
			if(nativeMode) {
606
				File cacheFileDir = getCacheFileDir(firstFiles[i]);
607
				File cacheFile    = getCacheFile(cacheFileDir, firstFiles[i], DIR_PART_SUFFIX);
608
	    	createThumbnailNative(cacheFileDir, cacheFile, firstFiles[i],
609
	    		dirThumbnailPositions[i].getWidth(), dirThumbnailPositions[i].getHeight());
610
	      image     = loadImage(cacheFile.getCanonicalPath());
611
	      thumbnail = createBufferedImage(image);
612
			}
613
			else {
614
	      image = loadImage(firstFiles[i].getCanonicalPath());
615
      }
616
 
936 dev 617
      if(image == null) {   // not supported format
618
        logger.warn("unsupported format for origin or operation interrupted");
619
 
620
        return null;
621
      }
622
      else {
623
        sizes = calcSizes(image.getWidth(null), image.getHeight(null),
624
          dirThumbnailPositions[i].getWidth(),
625
          dirThumbnailPositions[i].getHeight());
1074 dev 626
      }
936 dev 627
 
1074 dev 628
			if(!nativeMode) {
936 dev 629
        thumbnail = resizer.resize(image, sizes[0], sizes[1]);
630
      }
1074 dev 631
 
632
      graphics.drawImage(thumbnail,
633
        getXPosition(dirThumbnailPositions[i].getX(),
634
          dirThumbnailPositions[i].getWidth(), sizes[0],
635
          dirThumbnailPositions[i].getHorAlign()),
636
        getYPosition(dirThumbnailPositions[i].getY(),
637
          dirThumbnailPositions[i].getHeight(), sizes[1],
638
          dirThumbnailPositions[i].getVertAlign()),
639
        null);
936 dev 640
    }
641
 
1074 dev 642
    if(logger.isDebugEnabled()) {
643
      logger.debug("dir thumbnail created in "
644
      	+ (System.currentTimeMillis() - timeStart) + " ms");
645
    }
646
 
936 dev 647
    return dirThumbnail;
648
  }
649
 
650
  protected Image loadImage(String fileName)
651
  {
1074 dev 652
	long timeStart = System.currentTimeMillis();
653
 
936 dev 654
    // FIXME: probably toolbox reads an image not by every request but
655
    //        caches it
656
    Toolkit toolkit = Toolkit.getDefaultToolkit();
657
    Image   image   = toolkit.getImage(fileName);
658
 
659
    toolkit.prepareImage(image, -1, -1, null);
660
 
661
    while(true) {
662
      int status = toolkit.checkImage(image, -1, -1, null);
663
 
664
      if((status & ImageObserver.ALLBITS) != 0) break;
665
      if((status & ImageObserver.ERROR)   != 0) return null;
666
 
667
      try {
668
        Thread.sleep(100);
669
      }
670
      catch(Exception ex) {
671
        return null;
672
      }
673
    }
674
 
1074 dev 675
    if(logger.isDebugEnabled()) {
676
      logger.debug("image " + fileName + " loaded in "
677
      	+ (System.currentTimeMillis() - timeStart) + " ms");
678
    }
679
 
936 dev 680
    return image;
681
  }
682
 
683
  protected int[] calcSizes(int width, int height, int maxWidth, int maxHeight)
684
  {
685
    int[]  result = new int[2];
686
    double xRate;
687
    double yRate;
688
 
689
    if(width == 0 || height == 0) {
690
      result[0] = 0;
691
      result[1] = 0;
692
      return result;
693
    }
694
 
695
    xRate  = (double)maxWidth  / (double)width;
696
    yRate  = (double)maxHeight / (double)height;
697
    if(xRate >= 1.0 || yRate >= 1.0) {
698
      result[0] = width;
699
      result[1] = height;
700
    }
701
    else if(xRate > yRate) {
702
      result[0] = maxHeight * width / height;
703
      result[1] = maxHeight;
704
    }
705
    else {
706
      result[0] = maxWidth;
707
      result[1] = maxWidth * height / width;
708
    }
709
 
710
    return result;
711
  }
712
 
713
  protected int getXPosition(int left, int maxWidth, int width, int align)
714
  {
715
    if(align == ThumbnailPosition.ALIGN_HOR_LEFT)
716
      return left;
717
    else if(align == ThumbnailPosition.ALIGN_HOR_RIGHT)
718
      return left + (maxWidth - width);
719
    else if(align == ThumbnailPosition.ALIGN_HOR_CENTER)
720
      return left + (maxWidth - width) / 2;
721
    else
722
      throw new RuntimeException("Unknown align type: " + align);
723
  }
724
 
725
  protected int getYPosition(int top, int maxHeight, int height, int align)
726
  {
727
    if(align == ThumbnailPosition.ALIGN_VERT_TOP)
728
      return top;
729
    else if(align == ThumbnailPosition.ALIGN_VERT_BOTTOM)
730
      return top + (maxHeight - height);
731
    else if(align == ThumbnailPosition.ALIGN_VERT_CENTER)
732
      return top + (maxHeight - height) / 2;
733
    else
734
      throw new RuntimeException("Unknown align type: " + align);
735
  }
736
 
737
  protected int getFirstFiles(File dir, int count, File[] files, int pos)
738
  {
739
    File[] children;
740
 
741
    if(imagesFilter == null)
742
      children = dir.listFiles();
743
    else
744
      children = dir.listFiles(imagesFilter);
745
 
746
    if(children == null) return 0; // the dir does not exists
747
 
748
    Arrays.sort(children, fileNameComparatorRev);
749
 
750
    for(int i = 0; i < children.length; i++) {
751
      if(children[i].isDirectory())
752
        ; //pos = getFirstFiles(children[i], count, files, pos);
753
      else {
754
        files[pos++] = children[i];
755
      }
756
 
757
      if(pos >= count) break;
758
    }
759
 
760
    return pos;
761
  }
762
 
763
  protected BufferedImage createBufferedImage(Image image)
764
  {
765
    if(image == null) return null;
766
 
767
    int width  = image.getWidth(null);
768
    int height = image.getHeight(null);
769
 
770
    if(width < 1 || height < 1) return null;
771
 
772
    // get pixels
773
    int[]        pixels = new int[width * height];
774
    PixelGrabber pg     = new PixelGrabber(image,
775
      0, 0, width, height, pixels, 0, width);
776
 
777
    try  {
778
      pg.grabPixels();
779
    }
780
    catch(InterruptedException e) {
781
      return null;
782
    }
783
 
784
    if((pg.getStatus() & ImageObserver.ABORT) != 0) return null;
785
 
786
    // create buffered image
787
    BufferedImage buffered = new BufferedImage(width, height,
788
      BufferedImage.TYPE_INT_RGB);
789
 
790
    for(int y = 0; y < height; y++) {
791
      for(int x = 0; x < width; x++)
792
        buffered.setRGB(x, y, pixels[y * width + x]);
793
    }
794
 
795
    return buffered;
796
  }
797
 
798
  public ImageResizer getResizer()
799
  {
800
    return resizer;
801
  }
802
 
803
  public void setResizer(ImageResizer resizer)
804
  {
805
    this.resizer = resizer;
806
  }
807
 
808
  public String getFormat()
809
  {
810
    return format;
811
  }
812
 
813
  public void setFormat(String format)
814
  {
815
    this.format = format;
816
  }
817
 
818
  public File getCacheDir()
819
  {
820
    return cacheDir;
821
  }
822
 
823
  public void setCacheDir(File dir)
824
  {
825
    this.cacheDir = dir;
826
  }
827
 
828
  public File getImagesRoot()
829
  {
830
    return imagesRoot;
831
  }
832
 
833
  public void setImagesRoot(File dir)
834
  {
835
    this.imagesRoot = dir;
836
  }
837
 
838
  public int getSmallWidth()
839
  {
840
    return smallWidth;
841
  }
842
 
843
  public void setSmallWidth(int width)
844
  {
845
    this.smallWidth = width;
846
  }
847
 
848
  public int getSmallHeight()
849
  {
850
    return smallHeight;
851
  }
852
 
853
  public void setSmallHeight(int height)
854
  {
855
    this.smallHeight = height;
856
  }
857
 
858
  public int getMediumWidth()
859
  {
860
    return mediumWidth;
861
  }
862
 
863
  public void setMediumWidth(int width)
864
  {
865
    this.mediumWidth = width;
866
  }
867
 
868
  public int getMediumHeight()
869
  {
870
    return mediumHeight;
871
  }
872
 
873
  public void setMediumHeight(int height)
874
  {
875
    this.mediumHeight = height;
876
  }
877
 
878
  public FileFilter getImagesFilter()
879
  {
880
    return imagesFilter;
881
  }
882
 
883
  public void setImagesFilter(FileFilter filter)
884
  {
885
    this.imagesFilter = filter;
886
  }
887
 
888
  public File getDirTemplate()
889
  {
890
    return dirTemplate;
891
  }
892
 
893
  public void setDirTemplate(File dirTemplate)
894
  {
895
    this.dirTemplate = dirTemplate;
896
  }
897
 
898
  public ThumbnailPosition[] getDirThumbnailPositions()
899
  {
900
    return dirThumbnailPositions;
901
  }
902
 
903
  public void setDirThumbnailPositions(
904
    ThumbnailPosition[] dirThumbnailPositions)
905
  {
906
    this.dirThumbnailPositions = dirThumbnailPositions;
907
  }
908
}