001
014
015 package com.liferay.portlet.documentlibrary.util;
016
017 import com.liferay.document.library.kernel.exception.NoSuchFileEntryException;
018 import com.liferay.document.library.kernel.model.DLProcessorConstants;
019 import com.liferay.document.library.kernel.store.DLStoreUtil;
020 import com.liferay.document.library.kernel.util.DLPreviewableProcessor;
021 import com.liferay.document.library.kernel.util.ImageProcessor;
022 import com.liferay.exportimport.kernel.lar.PortletDataContext;
023 import com.liferay.portal.kernel.exception.PortalException;
024 import com.liferay.portal.kernel.image.ImageBag;
025 import com.liferay.portal.kernel.image.ImageTool;
026 import com.liferay.portal.kernel.image.ImageToolUtil;
027 import com.liferay.portal.kernel.log.Log;
028 import com.liferay.portal.kernel.log.LogFactoryUtil;
029 import com.liferay.portal.kernel.messaging.DestinationNames;
030 import com.liferay.portal.kernel.repository.model.FileEntry;
031 import com.liferay.portal.kernel.repository.model.FileVersion;
032 import com.liferay.portal.kernel.util.ContentTypes;
033 import com.liferay.portal.kernel.util.FileUtil;
034 import com.liferay.portal.kernel.util.SetUtil;
035 import com.liferay.portal.kernel.util.StreamUtil;
036 import com.liferay.portal.kernel.util.StringBundler;
037 import com.liferay.portal.kernel.util.StringPool;
038 import com.liferay.portal.kernel.util.Validator;
039 import com.liferay.portal.kernel.xml.Element;
040 import com.liferay.portal.util.PropsValues;
041
042 import java.awt.image.ColorModel;
043 import java.awt.image.RenderedImage;
044
045 import java.io.File;
046 import java.io.FileOutputStream;
047 import java.io.InputStream;
048
049 import java.util.List;
050 import java.util.Set;
051 import java.util.Vector;
052 import java.util.concurrent.Future;
053
054
059 public class ImageProcessorImpl
060 extends DLPreviewableProcessor implements ImageProcessor {
061
062 @Override
063 public void afterPropertiesSet() {
064 }
065
066 @Override
067 public void cleanUp(FileEntry fileEntry) {
068 deleteFiles(fileEntry, null);
069 }
070
071 @Override
072 public void cleanUp(FileVersion fileVersion) {
073 String type = getThumbnailType(fileVersion);
074
075 deleteFiles(fileVersion, type);
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 Set<String> getImageMimeTypes() {
088 return _imageMimeTypes;
089 }
090
091 @Override
092 public InputStream getPreviewAsStream(FileVersion fileVersion)
093 throws Exception {
094
095 if (_previewGenerationRequired(fileVersion)) {
096 String type = getPreviewType(fileVersion);
097
098 return doGetPreviewAsStream(fileVersion, type);
099 }
100
101 return fileVersion.getContentStream(false);
102 }
103
104 @Override
105 public long getPreviewFileSize(FileVersion fileVersion) throws Exception {
106 if (_previewGenerationRequired(fileVersion)) {
107 String type = getPreviewType(fileVersion);
108
109 return doGetPreviewFileSize(fileVersion, type);
110 }
111
112 return fileVersion.getSize();
113 }
114
115 @Override
116 public String getPreviewType(FileVersion fileVersion) {
117 return _getType(fileVersion);
118 }
119
120 @Override
121 public InputStream getThumbnailAsStream(FileVersion fileVersion, int index)
122 throws Exception {
123
124 return doGetThumbnailAsStream(fileVersion, index);
125 }
126
127 @Override
128 public long getThumbnailFileSize(FileVersion fileVersion, int index)
129 throws Exception {
130
131 return doGetThumbnailFileSize(fileVersion, index);
132 }
133
134 @Override
135 public String getThumbnailType(FileVersion fileVersion) {
136 return _getType(fileVersion);
137 }
138
139 @Override
140 public String getType() {
141 return DLProcessorConstants.IMAGE_PROCESSOR;
142 }
143
144 @Override
145 public boolean hasImages(FileVersion fileVersion) {
146 if (!PropsValues.DL_FILE_ENTRY_PREVIEW_ENABLED &&
147 !PropsValues.DL_FILE_ENTRY_THUMBNAIL_ENABLED) {
148
149 return false;
150 }
151
152 if (fileVersion.getSize() == 0) {
153 return false;
154 }
155
156 boolean hasImages = false;
157
158 try {
159 if (_hasPreview(fileVersion) && hasThumbnails(fileVersion)) {
160 hasImages = true;
161 }
162
163 if (!hasImages && isSupported(fileVersion)) {
164 _queueGeneration(null, fileVersion);
165 }
166 }
167 catch (Exception e) {
168 _log.error(e, e);
169 }
170
171 return hasImages;
172 }
173
174 @Override
175 public boolean isImageSupported(FileVersion fileVersion) {
176 return isSupported(fileVersion);
177 }
178
179 @Override
180 public boolean isImageSupported(String mimeType) {
181 return isSupported(mimeType);
182 }
183
184 @Override
185 public boolean isSupported(String mimeType) {
186 return _imageMimeTypes.contains(mimeType);
187 }
188
189 @Override
190 public void storeThumbnail(
191 long companyId, long groupId, long fileEntryId, long fileVersionId,
192 long custom1ImageId, long custom2ImageId, InputStream is,
193 String type)
194 throws Exception {
195
196 _storeThumbnail(
197 companyId, groupId, fileEntryId, fileVersionId, custom1ImageId,
198 custom2ImageId, is, type);
199 }
200
201 @Override
202 public void trigger(
203 FileVersion sourceFileVersion, FileVersion destinationFileVersion) {
204
205 super.trigger(sourceFileVersion, destinationFileVersion);
206
207 _queueGeneration(sourceFileVersion, destinationFileVersion);
208 }
209
210 @Override
211 protected void doExportGeneratedFiles(
212 PortletDataContext portletDataContext, FileEntry fileEntry,
213 Element fileEntryElement)
214 throws Exception {
215
216 exportThumbnails(
217 portletDataContext, fileEntry, fileEntryElement, "image");
218
219 exportPreview(portletDataContext, fileEntry, fileEntryElement);
220 }
221
222 @Override
223 protected void doImportGeneratedFiles(
224 PortletDataContext portletDataContext, FileEntry fileEntry,
225 FileEntry importedFileEntry, Element fileEntryElement)
226 throws Exception {
227
228 importThumbnails(
229 portletDataContext, fileEntry, importedFileEntry, fileEntryElement,
230 "image");
231
232 FileVersion importedFileVersion = importedFileEntry.getFileVersion();
233
234 if (!_previewGenerationRequired(importedFileVersion)) {
235 return;
236 }
237
238 importPreview(
239 portletDataContext, fileEntry, importedFileEntry, fileEntryElement,
240 "image", getPreviewType(importedFileVersion));
241 }
242
243 protected void exportPreview(
244 PortletDataContext portletDataContext, FileEntry fileEntry,
245 Element fileEntryElement)
246 throws Exception {
247
248 FileVersion fileVersion = fileEntry.getFileVersion();
249
250 if (!isSupported(fileVersion) ||
251 !_previewGenerationRequired(fileVersion) ||
252 !_hasPreview(fileVersion)) {
253
254 return;
255 }
256
257 exportPreview(
258 portletDataContext, fileEntry, fileEntryElement, "image",
259 getPreviewType(fileVersion));
260 }
261
262 @Override
263 protected List<Long> getFileVersionIds() {
264 return _fileVersionIds;
265 }
266
267 private void _generateImages(
268 FileVersion sourceFileVersion, FileVersion destinationFileVersion)
269 throws Exception {
270
271 InputStream inputStream = null;
272
273 try {
274 if (sourceFileVersion != null) {
275 copy(sourceFileVersion, destinationFileVersion);
276
277 return;
278 }
279
280 if (!PropsValues.DL_FILE_ENTRY_THUMBNAIL_ENABLED &&
281 !PropsValues.DL_FILE_ENTRY_PREVIEW_ENABLED) {
282
283 return;
284 }
285
286 inputStream = destinationFileVersion.getContentStream(false);
287
288 byte[] bytes = FileUtil.getBytes(inputStream);
289
290 ImageBag imageBag = ImageToolUtil.read(bytes);
291
292 RenderedImage renderedImage = imageBag.getRenderedImage();
293
294 if (renderedImage == null) {
295 return;
296 }
297
298 ColorModel colorModel = renderedImage.getColorModel();
299
300 if (colorModel.getNumColorComponents() == 4) {
301 Future<RenderedImage> future = ImageToolUtil.convertCMYKtoRGB(
302 bytes, imageBag.getType());
303
304 if (future == null) {
305 return;
306 }
307
308 String processIdentity = String.valueOf(
309 destinationFileVersion.getFileVersionId());
310
311 futures.put(processIdentity, future);
312
313 RenderedImage convertedRenderedImage = future.get();
314
315 if (convertedRenderedImage != null) {
316 renderedImage = convertedRenderedImage;
317 }
318 }
319
320 if (!_hasPreview(destinationFileVersion)) {
321 _storePreviewImage(destinationFileVersion, renderedImage);
322 }
323
324 if (!hasThumbnails(destinationFileVersion)) {
325 storeThumbnailImages(destinationFileVersion, renderedImage);
326 }
327 }
328 catch (NoSuchFileEntryException nsfee) {
329 if (_log.isDebugEnabled()) {
330 _log.debug(nsfee, nsfee);
331 }
332 }
333 finally {
334 StreamUtil.cleanUp(inputStream);
335
336 _fileVersionIds.remove(destinationFileVersion.getFileVersionId());
337 }
338 }
339
340 private String _getType(FileVersion fileVersion) {
341 String type = "png";
342
343 if (fileVersion == null) {
344 return type;
345 }
346
347 String mimeType = fileVersion.getMimeType();
348
349 if (mimeType.equals(ContentTypes.IMAGE_BMP)) {
350 type = ImageTool.TYPE_BMP;
351 }
352 else if (mimeType.equals(ContentTypes.IMAGE_GIF)) {
353 type = ImageTool.TYPE_GIF;
354 }
355 else if (mimeType.equals(ContentTypes.IMAGE_JPEG)) {
356 type = ImageTool.TYPE_JPEG;
357 }
358 else if (mimeType.equals(ContentTypes.IMAGE_PNG)) {
359 type = ImageTool.TYPE_PNG;
360 }
361 else if (!_previewGenerationRequired(fileVersion)) {
362 type = fileVersion.getExtension();
363 }
364
365 return type;
366 }
367
368 private boolean _hasPreview(FileVersion fileVersion)
369 throws PortalException {
370
371 if (PropsValues.DL_FILE_ENTRY_PREVIEW_ENABLED &&
372 _previewGenerationRequired(fileVersion)) {
373
374 String type = getPreviewType(fileVersion);
375
376 String previewFilePath = getPreviewFilePath(fileVersion, type);
377
378 if (!DLStoreUtil.hasFile(
379 fileVersion.getCompanyId(), REPOSITORY_ID,
380 previewFilePath)) {
381
382 return false;
383 }
384 }
385
386 return true;
387 }
388
389 private boolean _previewGenerationRequired(FileVersion fileVersion) {
390 String mimeType = fileVersion.getMimeType();
391
392 if (mimeType.contains("tiff") || mimeType.contains("tif")) {
393 return true;
394 }
395 else {
396 return false;
397 }
398 }
399
400 private void _queueGeneration(
401 FileVersion sourceFileVersion, FileVersion destinationFileVersion) {
402
403 if (_fileVersionIds.contains(
404 destinationFileVersion.getFileVersionId()) ||
405 !isSupported(destinationFileVersion)) {
406
407 return;
408 }
409
410 _fileVersionIds.add(destinationFileVersion.getFileVersionId());
411
412 sendGenerationMessage(
413 DestinationNames.DOCUMENT_LIBRARY_IMAGE_PROCESSOR,
414 sourceFileVersion, destinationFileVersion);
415 }
416
417 private void _storePreviewImage(
418 FileVersion fileVersion, RenderedImage renderedImage)
419 throws Exception {
420
421 String type = getPreviewType(fileVersion);
422
423 File file = null;
424
425 try {
426 file = FileUtil.createTempFile(type);
427
428 try (FileOutputStream fos = new FileOutputStream(file)) {
429 ImageToolUtil.write(renderedImage, type, fos);
430 }
431
432 addFileToStore(
433 fileVersion.getCompanyId(), PREVIEW_PATH,
434 getPreviewFilePath(fileVersion, type), file);
435 }
436 finally {
437 FileUtil.delete(file);
438 }
439 }
440
441 private void _storeThumbnail(
442 long companyId, long groupId, long fileEntryId, long fileVersionId,
443 long custom1ImageId, long custom2ImageId, InputStream is,
444 String type)
445 throws Exception {
446
447 StringBundler sb = new StringBundler(5);
448
449 sb.append(getPathSegment(groupId, fileEntryId, fileVersionId, false));
450
451 if (custom1ImageId != 0) {
452 sb.append(StringPool.DASH);
453 sb.append(1);
454 }
455 else if (custom2ImageId != 0) {
456 sb.append(StringPool.DASH);
457 sb.append(2);
458 }
459
460 if (Validator.isNotNull(type)) {
461 sb.append(StringPool.PERIOD);
462 sb.append(type);
463 }
464
465 String filePath = sb.toString();
466
467 File file = null;
468
469 try {
470 file = FileUtil.createTempFile(is);
471
472 addFileToStore(companyId, THUMBNAIL_PATH, filePath, file);
473 }
474 finally {
475 FileUtil.delete(file);
476 }
477 }
478
479 private static final Log _log = LogFactoryUtil.getLog(
480 ImageProcessorImpl.class);
481
482 private final List<Long> _fileVersionIds = new Vector<>();
483 private final Set<String> _imageMimeTypes = SetUtil.fromArray(
484 PropsValues.DL_FILE_ENTRY_PREVIEW_IMAGE_MIME_TYPES);
485
486 }