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