001
014
015 package com.liferay.portlet.documentlibrary.util;
016
017 import com.liferay.portal.kernel.image.GhostscriptUtil;
018 import com.liferay.portal.kernel.lar.PortletDataContext;
019 import com.liferay.portal.kernel.log.Log;
020 import com.liferay.portal.kernel.log.LogFactoryUtil;
021 import com.liferay.portal.kernel.messaging.DestinationNames;
022 import com.liferay.portal.kernel.process.ClassPathUtil;
023 import com.liferay.portal.kernel.process.ProcessCallable;
024 import com.liferay.portal.kernel.process.ProcessException;
025 import com.liferay.portal.kernel.process.ProcessExecutor;
026 import com.liferay.portal.kernel.repository.model.FileEntry;
027 import com.liferay.portal.kernel.repository.model.FileVersion;
028 import com.liferay.portal.kernel.util.ContentTypes;
029 import com.liferay.portal.kernel.util.FileUtil;
030 import com.liferay.portal.kernel.util.GetterUtil;
031 import com.liferay.portal.kernel.util.MimeTypesUtil;
032 import com.liferay.portal.kernel.util.PropsKeys;
033 import com.liferay.portal.kernel.util.ServerDetector;
034 import com.liferay.portal.kernel.util.StreamUtil;
035 import com.liferay.portal.kernel.util.StringPool;
036 import com.liferay.portal.kernel.util.SystemEnv;
037 import com.liferay.portal.kernel.util.Validator;
038 import com.liferay.portal.kernel.xml.Element;
039 import com.liferay.portal.log.Log4jLogFactoryImpl;
040 import com.liferay.portal.repository.liferayrepository.model.LiferayFileVersion;
041 import com.liferay.portal.util.PropsUtil;
042 import com.liferay.portal.util.PropsValues;
043 import com.liferay.portlet.documentlibrary.NoSuchFileEntryException;
044 import com.liferay.portlet.documentlibrary.store.DLStoreUtil;
045 import com.liferay.util.log4j.Log4JUtil;
046
047 import java.io.File;
048 import java.io.InputStream;
049
050 import java.util.ArrayList;
051 import java.util.Arrays;
052 import java.util.List;
053 import java.util.Map;
054 import java.util.Properties;
055 import java.util.Set;
056 import java.util.Vector;
057 import java.util.concurrent.Future;
058
059 import org.apache.commons.lang.time.StopWatch;
060 import org.apache.pdfbox.pdmodel.PDDocument;
061
062
069 public class PDFProcessorImpl
070 extends DLPreviewableProcessor implements PDFProcessor {
071
072 @Override
073 public void afterPropertiesSet() throws Exception {
074 FileUtil.mkdirs(PREVIEW_TMP_PATH);
075 FileUtil.mkdirs(THUMBNAIL_TMP_PATH);
076 }
077
078 @Override
079 public void generateImages(
080 FileVersion sourceFileVersion, FileVersion destinationFileVersion)
081 throws Exception {
082
083 _generateImages(sourceFileVersion, destinationFileVersion);
084 }
085
086 @Override
087 public InputStream getPreviewAsStream(FileVersion fileVersion, int index)
088 throws Exception {
089
090 return doGetPreviewAsStream(fileVersion, index, PREVIEW_TYPE);
091 }
092
093 @Override
094 public int getPreviewFileCount(FileVersion fileVersion) {
095 try {
096 return doGetPreviewFileCount(fileVersion);
097 }
098 catch (Exception e) {
099 _log.error(e, e);
100 }
101
102 return 0;
103 }
104
105 @Override
106 public long getPreviewFileSize(FileVersion fileVersion, int index)
107 throws Exception {
108
109 return doGetPreviewFileSize(fileVersion, index);
110 }
111
112 @Override
113 public InputStream getThumbnailAsStream(FileVersion fileVersion, int index)
114 throws Exception {
115
116 return doGetThumbnailAsStream(fileVersion, index);
117 }
118
119 @Override
120 public long getThumbnailFileSize(FileVersion fileVersion, int index)
121 throws Exception {
122
123 return doGetThumbnailFileSize(fileVersion, index);
124 }
125
126 @Override
127 public boolean hasImages(FileVersion fileVersion) {
128 boolean hasImages = false;
129
130 try {
131 hasImages = _hasImages(fileVersion);
132
133 if (!hasImages && isSupported(fileVersion)) {
134 _queueGeneration(null, fileVersion);
135 }
136 }
137 catch (Exception e) {
138 _log.error(e, e);
139 }
140
141 return hasImages;
142 }
143
144 @Override
145 public boolean isDocumentSupported(FileVersion fileVersion) {
146 return isSupported(fileVersion);
147 }
148
149 @Override
150 public boolean isDocumentSupported(String mimeType) {
151 return isSupported(mimeType);
152 }
153
154 @Override
155 public boolean isSupported(String mimeType) {
156 if (Validator.isNull(mimeType)) {
157 return false;
158 }
159
160 if (mimeType.equals(ContentTypes.APPLICATION_PDF) ||
161 mimeType.equals(ContentTypes.APPLICATION_X_PDF)) {
162
163 return true;
164 }
165
166 if (DocumentConversionUtil.isEnabled()) {
167 Set<String> extensions = MimeTypesUtil.getExtensions(mimeType);
168
169 for (String extension : extensions) {
170 extension = extension.substring(1);
171
172 String[] targetExtensions =
173 DocumentConversionUtil.getConversions(extension);
174
175 if (Arrays.binarySearch(targetExtensions, "pdf") >= 0) {
176 return true;
177 }
178 }
179 }
180
181 return false;
182 }
183
184 @Override
185 public void trigger(
186 FileVersion sourceFileVersion, FileVersion destinationFileVersion) {
187
188 super.trigger(sourceFileVersion, destinationFileVersion);
189
190 _queueGeneration(sourceFileVersion, destinationFileVersion);
191 }
192
193 @Override
194 protected void copyPreviews(
195 FileVersion sourceFileVersion, FileVersion destinationFileVersion) {
196
197 if (!PropsValues.DL_FILE_ENTRY_PREVIEW_ENABLED) {
198 return;
199 }
200
201 try {
202 if (hasPreview(sourceFileVersion) &&
203 !hasPreview(destinationFileVersion)) {
204
205 int count = getPreviewFileCount(sourceFileVersion);
206
207 for (int i = 0; i < count; i++) {
208 String previewFilePath = getPreviewFilePath(
209 destinationFileVersion, i + 1);
210
211 InputStream is = doGetPreviewAsStream(
212 sourceFileVersion, i + 1, PREVIEW_TYPE);
213
214 addFileToStore(
215 destinationFileVersion.getCompanyId(), PREVIEW_PATH,
216 previewFilePath, is);
217 }
218 }
219 }
220 catch (Exception e) {
221 _log.error(e, e);
222 }
223 }
224
225 @Override
226 protected void doExportGeneratedFiles(
227 PortletDataContext portletDataContext, FileEntry fileEntry,
228 Element fileEntryElement)
229 throws Exception {
230
231 exportThumbnails(
232 portletDataContext, fileEntry, fileEntryElement, "pdf");
233
234 exportPreviews(portletDataContext, fileEntry, fileEntryElement);
235 }
236
237 @Override
238 protected void doImportGeneratedFiles(
239 PortletDataContext portletDataContext, FileEntry fileEntry,
240 FileEntry importedFileEntry, Element fileEntryElement)
241 throws Exception {
242
243 importThumbnails(
244 portletDataContext, fileEntry, importedFileEntry, fileEntryElement,
245 "pdf");
246
247 importPreviews(
248 portletDataContext, fileEntry, importedFileEntry, fileEntryElement);
249 }
250
251 protected void exportPreviews(
252 PortletDataContext portletDataContext, FileEntry fileEntry,
253 Element fileEntryElement)
254 throws Exception {
255
256 FileVersion fileVersion = fileEntry.getFileVersion();
257
258 if (!isSupported(fileVersion) || !_hasImages(fileVersion)) {
259 return;
260 }
261
262 if (!portletDataContext.isPerformDirectBinaryImport()) {
263 int previewFileCount = getPreviewFileCount(fileVersion);
264
265 fileEntryElement.addAttribute(
266 "bin-path-pdf-preview-count", String.valueOf(previewFileCount));
267
268 for (int i = 0; i < previewFileCount; i++) {
269 exportPreview(
270 portletDataContext, fileEntry, fileEntryElement, "pdf",
271 PREVIEW_TYPE, i);
272 }
273 }
274 }
275
276 @Override
277 protected List<Long> getFileVersionIds() {
278 return _fileVersionIds;
279 }
280
281 @Override
282 protected String getPreviewType(FileVersion fileVersion) {
283 return PREVIEW_TYPE;
284 }
285
286 @Override
287 protected String getThumbnailType(FileVersion fileVersion) {
288 return THUMBNAIL_TYPE;
289 }
290
291 protected boolean hasPreview(FileVersion fileVersion) throws Exception {
292 return hasPreview(fileVersion, null);
293 }
294
295 @Override
296 protected boolean hasPreview(FileVersion fileVersion, String type)
297 throws Exception {
298
299 String previewFilePath = getPreviewFilePath(fileVersion, 1);
300
301 return DLStoreUtil.hasFile(
302 fileVersion.getCompanyId(), REPOSITORY_ID, previewFilePath);
303 }
304
305 protected void importPreviews(
306 PortletDataContext portletDataContext, FileEntry fileEntry,
307 FileEntry importedFileEntry, Element fileEntryElement)
308 throws Exception {
309
310 int previewFileCount = GetterUtil.getInteger(
311 fileEntryElement.attributeValue("bin-path-pdf-preview-count"));
312
313 for (int i = 0; i < previewFileCount; i++) {
314 importPreview(
315 portletDataContext, fileEntry, importedFileEntry,
316 fileEntryElement, "pdf", PREVIEW_TYPE, i);
317 }
318 }
319
320 private void _generateImages(FileVersion fileVersion, File file)
321 throws Exception {
322
323 if (GhostscriptUtil.isEnabled()) {
324 if (!_ghostscriptInitialized) {
325 GhostscriptUtil.reset();
326
327 _ghostscriptInitialized = true;
328 }
329
330 _generateImagesGS(fileVersion, file);
331 }
332 else {
333 _generateImagesPB(fileVersion, file);
334 }
335 }
336
337 private void _generateImages(
338 FileVersion sourceFileVersion, FileVersion destinationFileVersion)
339 throws Exception {
340
341 InputStream inputStream = null;
342
343 try {
344 if (sourceFileVersion != null) {
345 copy(sourceFileVersion, destinationFileVersion);
346
347 return;
348 }
349
350 if (_hasImages(destinationFileVersion)) {
351 return;
352 }
353
354 String extension = destinationFileVersion.getExtension();
355
356 if (extension.equals("pdf")) {
357 if (destinationFileVersion instanceof LiferayFileVersion) {
358 try {
359 LiferayFileVersion liferayFileVersion =
360 (LiferayFileVersion)destinationFileVersion;
361
362 File file = liferayFileVersion.getFile(false);
363
364 _generateImages(destinationFileVersion, file);
365
366 return;
367 }
368 catch (UnsupportedOperationException uoe) {
369 }
370 }
371
372 inputStream = destinationFileVersion.getContentStream(false);
373
374 _generateImages(destinationFileVersion, inputStream);
375 }
376 else if (DocumentConversionUtil.isEnabled()) {
377 inputStream = destinationFileVersion.getContentStream(false);
378
379 String tempFileId = DLUtil.getTempFileId(
380 destinationFileVersion.getFileEntryId(),
381 destinationFileVersion.getVersion());
382
383 File file = DocumentConversionUtil.convert(
384 tempFileId, inputStream, extension, "pdf");
385
386 _generateImages(destinationFileVersion, file);
387 }
388 }
389 catch (NoSuchFileEntryException nsfee) {
390 }
391 finally {
392 StreamUtil.cleanUp(inputStream);
393
394 _fileVersionIds.remove(destinationFileVersion.getFileVersionId());
395 }
396 }
397
398 private void _generateImages(
399 FileVersion fileVersion, InputStream inputStream)
400 throws Exception {
401
402 if (GhostscriptUtil.isEnabled()) {
403 _generateImagesGS(fileVersion, inputStream);
404 }
405 else {
406 _generateImagesPB(fileVersion, inputStream);
407 }
408 }
409
410 private void _generateImagesGS(FileVersion fileVersion, File file)
411 throws Exception {
412
413 if (_isGeneratePreview(fileVersion)) {
414 StopWatch stopWatch = new StopWatch();
415
416 stopWatch.start();
417
418 _generateImagesGS(fileVersion, file, false);
419
420 if (_log.isInfoEnabled()) {
421 int previewFileCount = getPreviewFileCount(fileVersion);
422
423 _log.info(
424 "Ghostscript generated " + previewFileCount +
425 " preview pages for " + fileVersion.getTitle() +
426 " in " + stopWatch.getTime() + " ms");
427 }
428 }
429
430 if (_isGenerateThumbnail(fileVersion)) {
431 StopWatch stopWatch = new StopWatch();
432
433 stopWatch.start();
434
435 _generateImagesGS(fileVersion, file, true);
436
437 if (_log.isInfoEnabled()) {
438 _log.info(
439 "Ghostscript generated a thumbnail for " +
440 fileVersion.getTitle() + " in " + stopWatch.getTime() +
441 " ms");
442 }
443 }
444 }
445
446 private void _generateImagesGS(
447 FileVersion fileVersion, File file, boolean thumbnail)
448 throws Exception {
449
450
451
452 String tempFileId = DLUtil.getTempFileId(
453 fileVersion.getFileEntryId(), fileVersion.getVersion());
454
455 List<String> arguments = new ArrayList<String>();
456
457 arguments.add("-sDEVICE=png16m");
458
459 if (thumbnail) {
460 arguments.add(
461 "-sOutputFile=" + getThumbnailTempFilePath(tempFileId));
462 arguments.add("-dFirstPage=1");
463 arguments.add("-dLastPage=1");
464 }
465 else {
466 arguments.add(
467 "-sOutputFile=" + getPreviewTempFilePath(tempFileId, -1));
468 }
469
470 arguments.add("-dPDFFitPage");
471 arguments.add("-dTextAlphaBits=4");
472 arguments.add("-dGraphicsAlphaBits=4");
473 arguments.add("-r" + PropsValues.DL_FILE_ENTRY_PREVIEW_DOCUMENT_DPI);
474
475 if (PropsValues.DL_FILE_ENTRY_PREVIEW_DOCUMENT_MAX_WIDTH != 0) {
476 arguments.add(
477 "-dDEVICEWIDTH=" +
478 PropsValues.DL_FILE_ENTRY_PREVIEW_DOCUMENT_MAX_WIDTH);
479 }
480
481 if (PropsValues.DL_FILE_ENTRY_PREVIEW_DOCUMENT_MAX_HEIGHT != 0) {
482 arguments.add(
483 "-dDEVICEHEIGHT=" +
484 PropsValues.DL_FILE_ENTRY_PREVIEW_DOCUMENT_MAX_HEIGHT);
485 }
486
487 arguments.add(file.getPath());
488
489 Future<?> future = GhostscriptUtil.execute(arguments);
490
491 String processIdentity = String.valueOf(fileVersion.getFileVersionId());
492
493 while (!future.isCancelled()) {
494 if (future.isDone()) {
495 futures.put(processIdentity, future);
496
497 break;
498 }
499 }
500
501 future.get();
502
503
504
505 if (thumbnail) {
506 File thumbnailTempFile = getThumbnailTempFile(tempFileId);
507
508 try {
509 storeThumbnailImages(fileVersion, thumbnailTempFile);
510 }
511 finally {
512 FileUtil.delete(thumbnailTempFile);
513 }
514 }
515 else {
516 int total = getPreviewTempFileCount(fileVersion);
517
518 for (int i = 0; i < total; i++) {
519 File previewTempFile = getPreviewTempFile(tempFileId, i + 2);
520
521 try {
522 addFileToStore(
523 fileVersion.getCompanyId(), PREVIEW_PATH,
524 getPreviewFilePath(fileVersion, i + 1),
525 previewTempFile);
526 }
527 finally {
528 FileUtil.delete(previewTempFile);
529 }
530 }
531 }
532 }
533
534 private void _generateImagesGS(
535 FileVersion fileVersion, InputStream inputStream)
536 throws Exception {
537
538 File file = null;
539
540 try {
541 file = FileUtil.createTempFile(inputStream);
542
543 _generateImagesGS(fileVersion, file);
544 }
545 finally {
546 FileUtil.delete(file);
547 }
548 }
549
550 private void _generateImagesPB(FileVersion fileVersion, File file)
551 throws Exception {
552
553 String tempFileId = DLUtil.getTempFileId(
554 fileVersion.getFileEntryId(), fileVersion.getVersion());
555
556 File thumbnailFile = getThumbnailTempFile(tempFileId);
557
558 int previewFilesCount = 0;
559
560 PDDocument pdDocument = null;
561
562 try {
563 pdDocument = PDDocument.load(file);
564
565 previewFilesCount = pdDocument.getNumberOfPages();
566 }
567 finally {
568 if (pdDocument != null) {
569 pdDocument.close();
570 }
571 }
572
573 File[] previewFiles = new File[previewFilesCount];
574
575 for (int i = 0; i < previewFilesCount; i++) {
576 previewFiles[i] = getPreviewTempFile(tempFileId, i);
577 }
578
579 boolean generatePreview = _isGeneratePreview(fileVersion);
580 boolean generateThumbnail = _isGenerateThumbnail(fileVersion);
581
582 if (PropsValues.DL_FILE_ENTRY_PREVIEW_FORK_PROCESS_ENABLED) {
583 ProcessCallable<String> processCallable =
584 new LiferayPDFBoxProcessCallable(
585 ServerDetector.getServerId(),
586 PropsUtil.get(PropsKeys.LIFERAY_HOME),
587 Log4JUtil.getCustomLogSettings(), file, thumbnailFile,
588 previewFiles, getThumbnailType(fileVersion),
589 getPreviewType(fileVersion),
590 PropsValues.DL_FILE_ENTRY_PREVIEW_DOCUMENT_DPI,
591 PropsValues.DL_FILE_ENTRY_PREVIEW_DOCUMENT_MAX_HEIGHT,
592 PropsValues.DL_FILE_ENTRY_PREVIEW_DOCUMENT_MAX_WIDTH,
593 generatePreview, generateThumbnail);
594
595 Future<String> future = ProcessExecutor.execute(
596 ClassPathUtil.getPortalClassPath(), processCallable);
597
598 String processIdentity = String.valueOf(
599 fileVersion.getFileVersionId());
600
601 futures.put(processIdentity, future);
602
603 future.get();
604 }
605 else {
606 LiferayPDFBoxConverter liferayConverter =
607 new LiferayPDFBoxConverter(
608 file, thumbnailFile, previewFiles,
609 getPreviewType(fileVersion), getThumbnailType(fileVersion),
610 PropsValues.DL_FILE_ENTRY_PREVIEW_DOCUMENT_DPI,
611 PropsValues.DL_FILE_ENTRY_PREVIEW_DOCUMENT_MAX_HEIGHT,
612 PropsValues.DL_FILE_ENTRY_PREVIEW_DOCUMENT_MAX_WIDTH,
613 generatePreview, generateThumbnail);
614
615 liferayConverter.generateImagesPB();
616 }
617
618 if (generateThumbnail) {
619 try {
620 storeThumbnailImages(fileVersion, thumbnailFile);
621 }
622 finally {
623 FileUtil.delete(thumbnailFile);
624 }
625
626 if (_log.isInfoEnabled()) {
627 _log.info(
628 "PDFBox generated a thumbnail for " +
629 fileVersion.getFileVersionId());
630 }
631 }
632
633 if (generatePreview) {
634 int index = 0;
635
636 for (File previewFile : previewFiles) {
637 try {
638 addFileToStore(
639 fileVersion.getCompanyId(), PREVIEW_PATH,
640 getPreviewFilePath(fileVersion, index +1), previewFile);
641 }
642 finally {
643 FileUtil.delete(previewFile);
644 }
645
646 index++;
647 }
648
649 if (_log.isInfoEnabled()) {
650 _log.info(
651 "PDFBox generated " +
652 getPreviewFileCount(fileVersion) +
653 " preview pages for " +
654 fileVersion.getFileVersionId());
655 }
656 }
657 }
658
659 private void _generateImagesPB(
660 FileVersion fileVersion, InputStream inputStream)
661 throws Exception {
662
663 File file = null;
664
665 try {
666 file = FileUtil.createTempFile(inputStream);
667
668 _generateImagesPB(fileVersion, file);
669 }
670 finally {
671 FileUtil.delete(file);
672 }
673 }
674
675 private boolean _hasImages(FileVersion fileVersion) throws Exception {
676 if (PropsValues.DL_FILE_ENTRY_PREVIEW_ENABLED) {
677 if (!hasPreview(fileVersion)) {
678 return false;
679 }
680 }
681
682 return hasThumbnails(fileVersion);
683 }
684
685 private boolean _isGeneratePreview(FileVersion fileVersion)
686 throws Exception {
687
688 if (PropsValues.DL_FILE_ENTRY_PREVIEW_ENABLED &&
689 !hasPreview(fileVersion)) {
690
691 return true;
692 }
693 else {
694 return false;
695 }
696 }
697
698 private boolean _isGenerateThumbnail(FileVersion fileVersion)
699 throws Exception {
700
701 if (PropsValues.DL_FILE_ENTRY_THUMBNAIL_ENABLED &&
702 !hasThumbnail(fileVersion, THUMBNAIL_INDEX_DEFAULT)) {
703
704 return true;
705 }
706 else {
707 return false;
708 }
709 }
710
711 private void _queueGeneration(
712 FileVersion sourceFileVersion, FileVersion destinationFileVersion) {
713
714 if (_fileVersionIds.contains(
715 destinationFileVersion.getFileVersionId())) {
716
717 return;
718 }
719
720 boolean generateImages = false;
721
722 String extension = destinationFileVersion.getExtension();
723
724 if (extension.equals("pdf")) {
725 generateImages = true;
726 }
727 else if (DocumentConversionUtil.isEnabled()) {
728 String[] conversions = DocumentConversionUtil.getConversions(
729 extension);
730
731 for (String conversion : conversions) {
732 if (conversion.equals("pdf")) {
733 generateImages = true;
734
735 break;
736 }
737 }
738 }
739
740 if (generateImages) {
741 _fileVersionIds.add(destinationFileVersion.getFileVersionId());
742
743 sendGenerationMessage(
744 DestinationNames.DOCUMENT_LIBRARY_PDF_PROCESSOR,
745 sourceFileVersion, destinationFileVersion);
746 }
747 }
748
749 private static Log _log = LogFactoryUtil.getLog(PDFProcessorImpl.class);
750
751 private List<Long> _fileVersionIds = new Vector<Long>();
752 private boolean _ghostscriptInitialized = false;
753
754 private static class LiferayPDFBoxProcessCallable
755 implements ProcessCallable<String> {
756
757 public LiferayPDFBoxProcessCallable(
758 String serverId, String liferayHome,
759 Map<String, String> customLogSettings, File inputFile,
760 File thumbnailFile, File[] previewFiles, String extension,
761 String thumbnailExtension, int dpi, int height, int width,
762 boolean generatePreview, boolean generateThumbnail) {
763
764 _serverId = serverId;
765 _liferayHome = liferayHome;
766 _customLogSettings = customLogSettings;
767 _inputFile = inputFile;
768 _thumbnailFile = thumbnailFile;
769 _previewFiles = previewFiles;
770 _extension = extension;
771 _thumbnailExtension = thumbnailExtension;
772 _dpi = dpi;
773 _height = height;
774 _width = width;
775 _generatePreview = generatePreview;
776 _generateThumbnail = generateThumbnail;
777 }
778
779 @Override
780 public String call() throws ProcessException {
781 Properties systemProperties = System.getProperties();
782
783 SystemEnv.setProperties(systemProperties);
784
785 Class<?> clazz = getClass();
786
787 ClassLoader classLoader = clazz.getClassLoader();
788
789 Log4JUtil.initLog4J(
790 _serverId, _liferayHome, classLoader, new Log4jLogFactoryImpl(),
791 _customLogSettings);
792
793 try {
794 LiferayPDFBoxConverter liferayConverter =
795 new LiferayPDFBoxConverter(
796 _inputFile, _thumbnailFile, _previewFiles, _extension,
797 _thumbnailExtension, _dpi, _height, _width,
798 _generatePreview, _generateThumbnail);
799
800 liferayConverter.generateImagesPB();
801 }
802 catch (Exception e) {
803 throw new ProcessException(e);
804 }
805
806 return StringPool.BLANK;
807 }
808
809 private static final long serialVersionUID = 1L;
810
811 private Map<String, String> _customLogSettings;
812 private int _dpi;
813 private String _extension;
814 private boolean _generatePreview;
815 private boolean _generateThumbnail;
816 private int _height;
817 private File _inputFile;
818 private String _liferayHome;
819 private File[] _previewFiles;
820 private String _serverId;
821 private String _thumbnailExtension;
822 private File _thumbnailFile;
823 private int _width;
824
825 }
826
827 }