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