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.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 }
328 finally {
329 StreamUtil.cleanUp(inputStream);
330
331 _fileVersionIds.remove(destinationFileVersion.getFileVersionId());
332 }
333 }
334
335 private String _getType(FileVersion fileVersion) {
336 String type = "png";
337
338 if (fileVersion == null) {
339 return type;
340 }
341
342 String mimeType = fileVersion.getMimeType();
343
344 if (mimeType.equals(ContentTypes.IMAGE_BMP)) {
345 type = ImageTool.TYPE_BMP;
346 }
347 else if (mimeType.equals(ContentTypes.IMAGE_GIF)) {
348 type = ImageTool.TYPE_GIF;
349 }
350 else if (mimeType.equals(ContentTypes.IMAGE_JPEG)) {
351 type = ImageTool.TYPE_JPEG;
352 }
353 else if (mimeType.equals(ContentTypes.IMAGE_PNG)) {
354 type = ImageTool.TYPE_PNG;
355 }
356 else if (!_previewGenerationRequired(fileVersion)) {
357 type = fileVersion.getExtension();
358 }
359
360 return type;
361 }
362
363 private boolean _hasPreview(FileVersion fileVersion)
364 throws PortalException {
365
366 if (PropsValues.DL_FILE_ENTRY_PREVIEW_ENABLED &&
367 _previewGenerationRequired(fileVersion)) {
368
369 String type = getPreviewType(fileVersion);
370
371 String previewFilePath = getPreviewFilePath(fileVersion, type);
372
373 if (!DLStoreUtil.hasFile(
374 fileVersion.getCompanyId(), REPOSITORY_ID,
375 previewFilePath)) {
376
377 return false;
378 }
379 }
380
381 return true;
382 }
383
384 private boolean _previewGenerationRequired(FileVersion fileVersion) {
385 String mimeType = fileVersion.getMimeType();
386
387 if (mimeType.contains("tiff") || mimeType.contains("tif")) {
388 return true;
389 }
390 else {
391 return false;
392 }
393 }
394
395 private void _queueGeneration(
396 FileVersion sourceFileVersion, FileVersion destinationFileVersion) {
397
398 if (_fileVersionIds.contains(
399 destinationFileVersion.getFileVersionId()) ||
400 !isSupported(destinationFileVersion)) {
401
402 return;
403 }
404
405 _fileVersionIds.add(destinationFileVersion.getFileVersionId());
406
407 sendGenerationMessage(
408 DestinationNames.DOCUMENT_LIBRARY_IMAGE_PROCESSOR,
409 sourceFileVersion, destinationFileVersion);
410 }
411
412 private void _storePreviewImage(
413 FileVersion fileVersion, RenderedImage renderedImage)
414 throws Exception {
415
416 String type = getPreviewType(fileVersion);
417
418 File file = null;
419
420 try {
421 file = FileUtil.createTempFile(type);
422
423 try (FileOutputStream fos = new FileOutputStream(file)) {
424 ImageToolUtil.write(renderedImage, type, fos);
425 }
426
427 addFileToStore(
428 fileVersion.getCompanyId(), PREVIEW_PATH,
429 getPreviewFilePath(fileVersion, type), file);
430 }
431 finally {
432 FileUtil.delete(file);
433 }
434 }
435
436 private void _storeThumbnail(
437 long companyId, long groupId, long fileEntryId, long fileVersionId,
438 long custom1ImageId, long custom2ImageId, InputStream is,
439 String type)
440 throws Exception {
441
442 StringBundler sb = new StringBundler(5);
443
444 sb.append(getPathSegment(groupId, fileEntryId, fileVersionId, false));
445
446 if (custom1ImageId != 0) {
447 sb.append(StringPool.DASH);
448 sb.append(1);
449 }
450 else if (custom2ImageId != 0) {
451 sb.append(StringPool.DASH);
452 sb.append(2);
453 }
454
455 if (Validator.isNotNull(type)) {
456 sb.append(StringPool.PERIOD);
457 sb.append(type);
458 }
459
460 String filePath = sb.toString();
461
462 File file = null;
463
464 try {
465 file = FileUtil.createTempFile(is);
466
467 addFileToStore(companyId, THUMBNAIL_PATH, filePath, file);
468 }
469 finally {
470 FileUtil.delete(file);
471 }
472 }
473
474 private static final Log _log = LogFactoryUtil.getLog(
475 ImageProcessorImpl.class);
476
477 private final List<Long> _fileVersionIds = new Vector<>();
478 private final Set<String> _imageMimeTypes = SetUtil.fromArray(
479 PropsValues.DL_FILE_ENTRY_PREVIEW_IMAGE_MIME_TYPES);
480
481 }