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 return _imageMimeTypes.contains(mimeType);
177 }
178
179 @Override
180 public void storeThumbnail(
181 long companyId, long groupId, long fileEntryId, long fileVersionId,
182 long custom1ImageId, long custom2ImageId, InputStream is,
183 String type)
184 throws Exception {
185
186 _storeThumbnail(
187 companyId, groupId, fileEntryId, fileVersionId, custom1ImageId,
188 custom2ImageId, is, type);
189 }
190
191 @Override
192 public void trigger(
193 FileVersion sourceFileVersion, FileVersion destinationFileVersion) {
194
195 super.trigger(sourceFileVersion, destinationFileVersion);
196
197 _queueGeneration(sourceFileVersion, destinationFileVersion);
198 }
199
200 @Override
201 protected void doExportGeneratedFiles(
202 PortletDataContext portletDataContext, FileEntry fileEntry,
203 Element fileEntryElement)
204 throws Exception {
205
206 exportThumbnails(
207 portletDataContext, fileEntry, fileEntryElement, "image");
208
209 exportPreview(portletDataContext, fileEntry, fileEntryElement);
210 }
211
212 @Override
213 protected void doImportGeneratedFiles(
214 PortletDataContext portletDataContext, FileEntry fileEntry,
215 FileEntry importedFileEntry, Element fileEntryElement)
216 throws Exception {
217
218 importThumbnails(
219 portletDataContext, fileEntry, importedFileEntry, fileEntryElement,
220 "image");
221
222 FileVersion importedFileVersion = importedFileEntry.getFileVersion();
223
224 if (!_previewGenerationRequired(importedFileVersion)) {
225 return;
226 }
227
228 importPreview(
229 portletDataContext, fileEntry, importedFileEntry, fileEntryElement,
230 "image", getPreviewType(importedFileVersion));
231 }
232
233 protected void exportPreview(
234 PortletDataContext portletDataContext, FileEntry fileEntry,
235 Element fileEntryElement)
236 throws Exception {
237
238 FileVersion fileVersion = fileEntry.getFileVersion();
239
240 if (!isSupported(fileVersion) ||
241 !_previewGenerationRequired(fileVersion) ||
242 !_hasPreview(fileVersion)) {
243
244 return;
245 }
246
247 exportPreview(
248 portletDataContext, fileEntry, fileEntryElement, "image",
249 getPreviewType(fileVersion));
250 }
251
252 @Override
253 protected List<Long> getFileVersionIds() {
254 return _fileVersionIds;
255 }
256
257 private void _generateImages(
258 FileVersion sourceFileVersion, FileVersion destinationFileVersion)
259 throws Exception {
260
261 InputStream inputStream = null;
262
263 try {
264 if (sourceFileVersion != null) {
265 copy(sourceFileVersion, destinationFileVersion);
266
267 return;
268 }
269
270 if (!PropsValues.DL_FILE_ENTRY_THUMBNAIL_ENABLED &&
271 !PropsValues.DL_FILE_ENTRY_PREVIEW_ENABLED) {
272
273 return;
274 }
275
276 inputStream = destinationFileVersion.getContentStream(false);
277
278 byte[] bytes = FileUtil.getBytes(inputStream);
279
280 ImageBag imageBag = ImageToolUtil.read(bytes);
281
282 RenderedImage renderedImage = imageBag.getRenderedImage();
283
284 if (renderedImage == null) {
285 return;
286 }
287
288 ColorModel colorModel = renderedImage.getColorModel();
289
290 if (colorModel.getNumColorComponents() == 4) {
291 Future<RenderedImage> future = ImageToolUtil.convertCMYKtoRGB(
292 bytes, imageBag.getType());
293
294 if (future == null) {
295 return;
296 }
297
298 String processIdentity = String.valueOf(
299 destinationFileVersion.getFileVersionId());
300
301 futures.put(processIdentity, future);
302
303 RenderedImage convertedRenderedImage = future.get();
304
305 if (convertedRenderedImage != null) {
306 renderedImage = convertedRenderedImage;
307 }
308 }
309
310 if (!_hasPreview(destinationFileVersion)) {
311 _storePreviewImage(destinationFileVersion, renderedImage);
312 }
313
314 if (!hasThumbnails(destinationFileVersion)) {
315 storeThumbnailImages(destinationFileVersion, renderedImage);
316 }
317 }
318 catch (NoSuchFileEntryException nsfee) {
319 }
320 finally {
321 StreamUtil.cleanUp(inputStream);
322
323 _fileVersionIds.remove(destinationFileVersion.getFileVersionId());
324 }
325 }
326
327 private String _getType(FileVersion fileVersion) {
328 String type = "png";
329
330 if (fileVersion == null) {
331 return type;
332 }
333
334 String extension = fileVersion.getExtension();
335
336 if (extension.equals("jpeg")) {
337 type = "jpg";
338 }
339 else if (!_previewGenerationRequired(fileVersion)) {
340 type = extension;
341 }
342
343 return type;
344 }
345
346 private boolean _hasPreview(FileVersion fileVersion)
347 throws PortalException {
348
349 if (PropsValues.DL_FILE_ENTRY_PREVIEW_ENABLED &&
350 _previewGenerationRequired(fileVersion)) {
351
352 String type = getPreviewType(fileVersion);
353
354 String previewFilePath = getPreviewFilePath(fileVersion, type);
355
356 if (!DLStoreUtil.hasFile(
357 fileVersion.getCompanyId(), REPOSITORY_ID,
358 previewFilePath)) {
359
360 return false;
361 }
362 }
363
364 return true;
365 }
366
367 private boolean _previewGenerationRequired(FileVersion fileVersion) {
368 String type = fileVersion.getExtension();
369
370 if (type.equals("tiff") || type.equals("tif")) {
371 return true;
372 }
373 else {
374 return false;
375 }
376 }
377
378 private void _queueGeneration(
379 FileVersion sourceFileVersion, FileVersion destinationFileVersion) {
380
381 if (_fileVersionIds.contains(
382 destinationFileVersion.getFileVersionId()) ||
383 !isSupported(destinationFileVersion)) {
384
385 return;
386 }
387
388 _fileVersionIds.add(destinationFileVersion.getFileVersionId());
389
390 sendGenerationMessage(
391 DestinationNames.DOCUMENT_LIBRARY_IMAGE_PROCESSOR,
392 sourceFileVersion, destinationFileVersion);
393 }
394
395 private void _storePreviewImage(
396 FileVersion fileVersion, RenderedImage renderedImage)
397 throws Exception {
398
399 String type = getPreviewType(fileVersion);
400
401 File file = null;
402
403 try {
404 file = FileUtil.createTempFile(type);
405
406 try (FileOutputStream fos = new FileOutputStream(file)) {
407 ImageToolUtil.write(renderedImage, type, fos);
408 }
409
410 addFileToStore(
411 fileVersion.getCompanyId(), PREVIEW_PATH,
412 getPreviewFilePath(fileVersion, type), file);
413 }
414 finally {
415 FileUtil.delete(file);
416 }
417 }
418
419 private void _storeThumbnail(
420 long companyId, long groupId, long fileEntryId, long fileVersionId,
421 long custom1ImageId, long custom2ImageId, InputStream is,
422 String type)
423 throws Exception {
424
425 StringBundler sb = new StringBundler(5);
426
427 sb.append(getPathSegment(groupId, fileEntryId, fileVersionId, false));
428
429 if (custom1ImageId != 0) {
430 sb.append(StringPool.DASH);
431 sb.append(1);
432 }
433 else if (custom2ImageId != 0) {
434 sb.append(StringPool.DASH);
435 sb.append(2);
436 }
437
438 if (Validator.isNotNull(type)) {
439 sb.append(StringPool.PERIOD);
440 sb.append(type);
441 }
442
443 String filePath = sb.toString();
444
445 File file = null;
446
447 try {
448 file = FileUtil.createTempFile(is);
449
450 addFileToStore(companyId, THUMBNAIL_PATH, filePath, file);
451 }
452 finally {
453 FileUtil.delete(file);
454 }
455 }
456
457 private static final Log _log = LogFactoryUtil.getLog(
458 ImageProcessorImpl.class);
459
460 private final List<Long> _fileVersionIds = new Vector<Long>();
461 private final Set<String> _imageMimeTypes = SetUtil.fromArray(
462 PropsValues.DL_FILE_ENTRY_PREVIEW_IMAGE_MIME_TYPES);
463
464 }