001    /**
002     * Copyright (c) 2000-2011 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.documentlibrary.util;
016    
017    import com.liferay.portal.kernel.image.ImageBag;
018    import com.liferay.portal.kernel.image.ImageProcessorUtil;
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.messaging.MessageBusException;
023    import com.liferay.portal.kernel.messaging.MessageBusUtil;
024    import com.liferay.portal.kernel.repository.model.FileEntry;
025    import com.liferay.portal.kernel.repository.model.FileVersion;
026    import com.liferay.portal.kernel.util.FileUtil;
027    import com.liferay.portal.kernel.util.PropsKeys;
028    import com.liferay.portal.kernel.util.SetUtil;
029    import com.liferay.portal.kernel.util.StringBundler;
030    import com.liferay.portal.kernel.util.StringPool;
031    import com.liferay.portal.kernel.util.Validator;
032    import com.liferay.portal.model.CompanyConstants;
033    import com.liferay.portal.util.PrefsPropsUtil;
034    import com.liferay.portal.util.PropsValues;
035    import com.liferay.portlet.documentlibrary.NoSuchFileEntryException;
036    import com.liferay.portlet.documentlibrary.store.DLStoreUtil;
037    
038    import java.awt.image.RenderedImage;
039    
040    import java.io.File;
041    import java.io.IOException;
042    import java.io.InputStream;
043    
044    import java.util.List;
045    import java.util.Set;
046    import java.util.Vector;
047    
048    /**
049     * @author Sergio González
050     * @author Alexander Chow
051     */
052    public class ImageProcessor extends DLPreviewableProcessor {
053    
054            public void cleanUp(FileEntry fileEntry) {
055                    deleteFiles(fileEntry, null);
056            }
057    
058            public void cleanUp(FileVersion fileVersion) {
059                    String type = _instance._getType(fileVersion);
060    
061                    deleteFiles(fileVersion, type);
062            }
063    
064            public static void generateImages(FileVersion fileVersion) {
065                    _instance._generateImages(fileVersion);
066            }
067    
068            public static InputStream getCustom1AsStream(FileVersion fileVersion)
069                    throws Exception {
070    
071                    String type = _instance._getType(fileVersion);
072    
073                    return _instance._getCustomAsStream(fileVersion, type, 1);
074            }
075    
076            public static long getCustom1FileSize(FileVersion fileVersion)
077                    throws Exception {
078    
079                    String type = _instance._getType(fileVersion);
080    
081                    return _instance._getCustomFileSize(fileVersion, type, 1);
082            }
083    
084            public static InputStream getCustom2AsStream(FileVersion fileVersion)
085                    throws Exception {
086    
087                    String type = _instance._getType(fileVersion);
088    
089                    return _instance._getCustomAsStream(fileVersion, type, 2);
090            }
091    
092            public static long getCustom2FileSize(FileVersion fileVersion)
093                    throws Exception {
094    
095                    String type = _instance._getType(fileVersion);
096    
097                    return _instance._getCustomFileSize(fileVersion, type, 2);
098            }
099    
100            public static Set<String> getImageMimeTypes() {
101                    return _instance._imageMimeTypes;
102            }
103    
104            public static InputStream getThumbnailAsStream(FileVersion fileVersion)
105                    throws Exception {
106    
107                    String type = _instance._getType(fileVersion);
108    
109                    return _instance.doGetThumbnailAsStream(fileVersion, type);
110            }
111    
112            public static long getThumbnailFileSize(FileVersion fileVersion)
113                    throws Exception {
114    
115                    String type = _instance._getType(fileVersion);
116    
117                    return _instance.doGetThumbnailFileSize(fileVersion, type);
118            }
119    
120            public static boolean hasImages(FileVersion fileVersion) {
121                    if (!PropsValues.DL_FILE_ENTRY_THUMBNAIL_ENABLED) {
122                            return false;
123                    }
124    
125                    boolean hasImages = false;
126    
127                    try {
128                            hasImages = _instance._hasImages(fileVersion);
129    
130                            if (!hasImages && _instance.isSupported(fileVersion)) {
131                                    _instance._queueGeneration(fileVersion);
132                            }
133                    }
134                    catch (Exception e) {
135                            _log.error(e, e);
136                    }
137    
138                    return hasImages;
139            }
140    
141            public static boolean hasThumbnailImage(FileVersion fileVersion) {
142                    return _instance._hasThumbnailImage(fileVersion);
143            }
144    
145            public static boolean isImageSupported(FileVersion fileVersion) {
146                    return _instance.isSupported(fileVersion);
147            }
148    
149            public static boolean isImageSupported(String mimeType) {
150                    return _instance.isSupported(mimeType);
151            }
152    
153            public static void storeThumbnail(
154                            long companyId, long groupId, long fileEntryId, long fileVersionId,
155                            long custom1ImageId, long custom2ImageId,
156                            InputStream is, String type)
157                    throws Exception {
158    
159                    _instance._storeThumbnail(
160                            companyId, groupId, fileEntryId, fileVersionId, custom1ImageId,
161                            custom2ImageId, is, type);
162            }
163    
164            public boolean isSupported(String mimeType) {
165                    if (Validator.isNull(mimeType)) {
166                            return false;
167                    }
168    
169                    return _imageMimeTypes.contains(mimeType);
170            }
171    
172            public void trigger(FileVersion fileVersion) {
173                    _instance._queueGeneration(fileVersion);
174            }
175    
176            private void _generateImages(FileVersion fileVersion) {
177                    try {
178                            if (!PropsValues.DL_FILE_ENTRY_THUMBNAIL_ENABLED) {
179                                    return;
180                            }
181    
182                            InputStream inputStream = fileVersion.getContentStream(false);
183    
184                            byte[] bytes = FileUtil.getBytes(inputStream);
185    
186                            ImageBag imageBag = ImageProcessorUtil.read(bytes);
187    
188                            RenderedImage renderedImage = imageBag.getRenderedImage();
189    
190                            if (renderedImage == null) {
191                                    return;
192                            }
193    
194                            String type = _instance._getType(fileVersion);
195    
196                            _saveThumbnailImage(
197                                    fileVersion, renderedImage,
198                                    PropsKeys.DL_FILE_ENTRY_THUMBNAIL_MAX_HEIGHT,
199                                    PropsKeys.DL_FILE_ENTRY_THUMBNAIL_MAX_WIDTH,
200                                    getThumbnailFilePath(fileVersion, type));
201    
202                            if ((PrefsPropsUtil.getInteger(
203                                            PropsKeys.
204                                                    DL_FILE_ENTRY_THUMBNAIL_CUSTOM_1_MAX_HEIGHT) > 0) ||
205                                    (PrefsPropsUtil.getInteger(
206                                            PropsKeys.
207                                                    DL_FILE_ENTRY_THUMBNAIL_CUSTOM_1_MAX_WIDTH) > 0)) {
208    
209                                    _saveThumbnailImage(
210                                            fileVersion, renderedImage,
211                                            PropsKeys.DL_FILE_ENTRY_THUMBNAIL_CUSTOM_1_MAX_HEIGHT,
212                                            PropsKeys.DL_FILE_ENTRY_THUMBNAIL_CUSTOM_1_MAX_WIDTH,
213                                            _getCustom1FilePath(fileVersion, type));
214                            }
215    
216                            if ((PrefsPropsUtil.getInteger(
217                                            PropsKeys.
218                                                    DL_FILE_ENTRY_THUMBNAIL_CUSTOM_2_MAX_HEIGHT) > 0) ||
219                                    (PrefsPropsUtil.getInteger(
220                                            PropsKeys.
221                                                    DL_FILE_ENTRY_THUMBNAIL_CUSTOM_2_MAX_WIDTH) > 0)) {
222    
223                                    _saveThumbnailImage(
224                                            fileVersion, renderedImage,
225                                            PropsKeys.DL_FILE_ENTRY_THUMBNAIL_CUSTOM_2_MAX_HEIGHT,
226                                            PropsKeys.DL_FILE_ENTRY_THUMBNAIL_CUSTOM_2_MAX_WIDTH,
227                                            _getCustom2FilePath(fileVersion, type));
228                            }
229                    }
230                    catch (NoSuchFileEntryException nsfee) {
231                    }
232                    catch (Exception e) {
233                            _log.error(e, e);
234                    }
235                    finally {
236                            _fileVersionIds.remove(fileVersion.getFileVersionId());
237                    }
238            }
239    
240            private String _getCustom1FilePath(FileVersion fileVersion, String type) {
241                    return _getCustomFilePath(fileVersion, type, 1);
242            }
243    
244            private String _getCustom2FilePath(FileVersion fileVersion, String type) {
245                    return _getCustomFilePath(fileVersion, type, 2);
246            }
247    
248            private InputStream _getCustomAsStream(
249                            FileVersion fileVersion, String type, int index)
250                    throws Exception {
251    
252                    return DLStoreUtil.getFileAsStream(
253                            fileVersion.getCompanyId(), CompanyConstants.SYSTEM,
254                            _getCustomFilePath(fileVersion, type, index));
255            }
256    
257            private String _getCustomFilePath(
258                    FileVersion fileVersion, String type, int index) {
259    
260                    StringBundler sb = new StringBundler(5);
261    
262                    sb.append(getPathSegment(fileVersion, false));
263                    sb.append(StringPool.DASH);
264                    sb.append(index);
265                    sb.append(StringPool.PERIOD);
266                    sb.append(type);
267    
268                    return sb.toString();
269            }
270    
271            private long _getCustomFileSize(
272                            FileVersion fileVersion, String type, int index)
273                    throws Exception {
274    
275                    return DLStoreUtil.getFileSize(
276                            fileVersion.getCompanyId(), CompanyConstants.SYSTEM,
277                            _getCustomFilePath(fileVersion, type, index));
278            }
279    
280            private String _getType(FileVersion fileVersion) {
281                    String type = fileVersion.getExtension();
282    
283                    if (type.equals("jpeg")) {
284                            type = "jpg";
285                    }
286    
287                    return type;
288            }
289    
290            private boolean _hasCustomImage(FileVersion fileVersion, int index) {
291                    try {
292                            String type = _getType(fileVersion);
293    
294                            return DLStoreUtil.hasFile(
295                                    fileVersion.getCompanyId(), REPOSITORY_ID,
296                                    _getCustomFilePath(fileVersion, type, index));
297                    }
298                    catch (Exception e) {
299                            _log.error(e, e);
300                    }
301    
302                    return false;
303            }
304    
305            private boolean _hasImages(FileVersion fileVersion) {
306                    if (!_hasThumbnailImage(fileVersion)) {
307                            return false;
308                    }
309    
310                    try {
311                            if ((PrefsPropsUtil.getInteger(
312                                            PropsKeys.
313                                                    DL_FILE_ENTRY_THUMBNAIL_CUSTOM_1_MAX_HEIGHT) > 0) ||
314                                    (PrefsPropsUtil.getInteger(
315                                            PropsKeys.
316                                                    DL_FILE_ENTRY_THUMBNAIL_CUSTOM_1_MAX_WIDTH) > 0)) {
317    
318                                    if (!_hasCustomImage(fileVersion, 1)) {
319                                            return false;
320                                    }
321                            }
322    
323                            if ((PrefsPropsUtil.getInteger(
324                                                    PropsKeys.
325                                                            DL_FILE_ENTRY_THUMBNAIL_CUSTOM_2_MAX_HEIGHT) > 0) ||
326                                            (PrefsPropsUtil.getInteger(
327                                                    PropsKeys.
328                                                            DL_FILE_ENTRY_THUMBNAIL_CUSTOM_2_MAX_WIDTH) > 0)) {
329    
330                                    if (!_hasCustomImage(fileVersion, 2)) {
331                                            return false;
332                                    }
333                            }
334                    }
335                    catch (Exception e) {
336                            _log.error(e, e);
337                    }
338    
339                    return true;
340            }
341    
342            private boolean _hasThumbnailImage(FileVersion fileVersion) {
343                    try {
344                            String imageType = _getType(fileVersion);
345    
346                            return DLStoreUtil.hasFile(
347                                    fileVersion.getCompanyId(), REPOSITORY_ID,
348                                    getThumbnailFilePath(fileVersion, imageType));
349                    }
350                    catch (Exception e) {
351                            _log.error(e, e);
352                    }
353    
354                    return false;
355            }
356    
357            private void _queueGeneration(FileVersion fileVersion) {
358                    if (!_fileVersionIds.contains(fileVersion.getFileVersionId()) &&
359                            isSupported(fileVersion) && !_hasImages(fileVersion)) {
360                            _fileVersionIds.add(fileVersion.getFileVersionId());
361    
362                            if (PropsValues.DL_FILE_ENTRY_PROCESSORS_TRIGGER_SYNCHRONOUSLY) {
363                                    try {
364                                            MessageBusUtil.sendSynchronousMessage(
365                                                    DestinationNames.DOCUMENT_LIBRARY_IMAGE_PROCESSOR,
366                                                    fileVersion);
367                                    }
368                                    catch (MessageBusException mbe) {
369                                            if (_log.isWarnEnabled()) {
370                                                    _log.warn(mbe, mbe);
371                                            }
372                                    }
373                            }
374                            else {
375                                    MessageBusUtil.sendMessage(
376                                            DestinationNames.DOCUMENT_LIBRARY_IMAGE_PROCESSOR,
377                                            fileVersion);
378                            }
379                    }
380            }
381    
382            private void _saveThumbnailImage(
383                            FileVersion fileVersion, RenderedImage renderedImage,
384                            String maxHeightPropsKey, String maxWidthPropsKey, String filePath)
385                    throws Exception {
386    
387                    File file = _scaleImage(
388                            renderedImage, fileVersion.getMimeType(),
389                            PrefsPropsUtil.getInteger(maxHeightPropsKey),
390                            PrefsPropsUtil.getInteger(maxWidthPropsKey));
391    
392                    try {
393                            addFileToStore(
394                                    fileVersion.getCompanyId(), THUMBNAIL_PATH, filePath, file);
395                    }
396                    finally {
397                            FileUtil.delete(file);
398                    }
399            }
400    
401            private File _scaleImage(
402                            RenderedImage renderedImage, String contentType, int height,
403                            int width)
404                    throws IOException {
405    
406                    RenderedImage thumbnailRenderedImage = ImageProcessorUtil.scale(
407                            renderedImage, height, width);
408    
409                    byte[] bytes = ImageProcessorUtil.getBytes(
410                            thumbnailRenderedImage, contentType);
411    
412                    return FileUtil.createTempFile(bytes);
413            }
414    
415            private void _storeThumbnail(
416                            long companyId, long groupId, long fileEntryId, long fileVersionId,
417                            long custom1ImageId, long custom2ImageId, InputStream is,
418                            String type)
419                    throws Exception {
420    
421                    StringBundler sb = new StringBundler(5);
422    
423                    sb.append(getPathSegment(groupId, fileEntryId, fileVersionId, false));
424    
425                    if (custom1ImageId != 0) {
426                            sb.append(StringPool.DASH);
427                            sb.append(1);
428                    }
429                    else if (custom2ImageId != 0) {
430                            sb.append(StringPool.DASH);
431                            sb.append(2);
432                    }
433    
434                    sb.append(StringPool.PERIOD);
435                    sb.append(type);
436    
437                    String filePath = sb.toString();
438    
439                    File file = null;
440    
441                    try {
442                            file = FileUtil.createTempFile(is);
443    
444                            addFileToStore(companyId, THUMBNAIL_PATH, filePath, file);
445                    }
446                    finally {
447                            FileUtil.delete(file);
448                    }
449            }
450    
451            private static Log _log = LogFactoryUtil.getLog(ImageProcessor.class);
452    
453            private static ImageProcessor _instance = new ImageProcessor();
454    
455            private List<Long> _fileVersionIds = new Vector<Long>();
456            private Set<String> _imageMimeTypes = SetUtil.fromArray(
457                    PropsValues.DL_FILE_ENTRY_PREVIEW_IMAGE_MIME_TYPES);
458    
459    }