Subversion Repositories general

Rev

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