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