/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.portlet.documentlibrary.util;
import com.liferay.document.library.kernel.exception.NoSuchFileEntryException;
import com.liferay.document.library.kernel.model.DLProcessorConstants;
import com.liferay.document.library.kernel.store.DLStoreUtil;
import com.liferay.document.library.kernel.util.DLPreviewableProcessor;
import com.liferay.document.library.kernel.util.ImageProcessor;
import com.liferay.exportimport.kernel.lar.PortletDataContext;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.image.ImageBag;
import com.liferay.portal.kernel.image.ImageTool;
import com.liferay.portal.kernel.image.ImageToolUtil;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.messaging.DestinationNames;
import com.liferay.portal.kernel.repository.model.FileEntry;
import com.liferay.portal.kernel.repository.model.FileVersion;
import com.liferay.portal.kernel.util.ContentTypes;
import com.liferay.portal.kernel.util.FileUtil;
import com.liferay.portal.kernel.util.SetUtil;
import com.liferay.portal.kernel.util.StreamUtil;
import com.liferay.portal.kernel.util.StringBundler;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.kernel.xml.Element;
import com.liferay.portal.util.PropsValues;
import java.awt.image.ColorModel;
import java.awt.image.RenderedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.List;
import java.util.Set;
import java.util.Vector;
import java.util.concurrent.Future;
/**
* @author Sergio González
* @author Alexander Chow
* @author Ivica Cardic
*/
public class ImageProcessorImpl
extends DLPreviewableProcessor implements ImageProcessor {
@Override
public void afterPropertiesSet() {
}
@Override
public void cleanUp(FileEntry fileEntry) {
deleteFiles(fileEntry, null);
}
@Override
public void cleanUp(FileVersion fileVersion) {
String type = getThumbnailType(fileVersion);
deleteFiles(fileVersion, type);
}
@Override
public void generateImages(
FileVersion sourceFileVersion, FileVersion destinationFileVersion)
throws Exception {
_generateImages(sourceFileVersion, destinationFileVersion);
}
@Override
public Set<String> getImageMimeTypes() {
return _imageMimeTypes;
}
@Override
public InputStream getPreviewAsStream(FileVersion fileVersion)
throws Exception {
if (_previewGenerationRequired(fileVersion)) {
String type = getPreviewType(fileVersion);
return doGetPreviewAsStream(fileVersion, type);
}
return fileVersion.getContentStream(false);
}
@Override
public long getPreviewFileSize(FileVersion fileVersion) throws Exception {
if (_previewGenerationRequired(fileVersion)) {
String type = getPreviewType(fileVersion);
return doGetPreviewFileSize(fileVersion, type);
}
return fileVersion.getSize();
}
@Override
public String getPreviewType(FileVersion fileVersion) {
return _getType(fileVersion);
}
@Override
public InputStream getThumbnailAsStream(FileVersion fileVersion, int index)
throws Exception {
return doGetThumbnailAsStream(fileVersion, index);
}
@Override
public long getThumbnailFileSize(FileVersion fileVersion, int index)
throws Exception {
return doGetThumbnailFileSize(fileVersion, index);
}
@Override
public String getThumbnailType(FileVersion fileVersion) {
return _getType(fileVersion);
}
@Override
public String getType() {
return DLProcessorConstants.IMAGE_PROCESSOR;
}
@Override
public boolean hasImages(FileVersion fileVersion) {
if (!PropsValues.DL_FILE_ENTRY_PREVIEW_ENABLED &&
!PropsValues.DL_FILE_ENTRY_THUMBNAIL_ENABLED) {
return false;
}
if (fileVersion.getSize() == 0) {
return false;
}
boolean hasImages = false;
try {
if (_hasPreview(fileVersion) && hasThumbnails(fileVersion)) {
hasImages = true;
}
if (!hasImages && isSupported(fileVersion)) {
_queueGeneration(null, fileVersion);
}
}
catch (Exception e) {
_log.error(e, e);
}
return hasImages;
}
@Override
public boolean isImageSupported(FileVersion fileVersion) {
return isSupported(fileVersion);
}
@Override
public boolean isImageSupported(String mimeType) {
return isSupported(mimeType);
}
@Override
public boolean isSupported(String mimeType) {
return _imageMimeTypes.contains(mimeType);
}
@Override
public void storeThumbnail(
long companyId, long groupId, long fileEntryId, long fileVersionId,
long custom1ImageId, long custom2ImageId, InputStream is,
String type)
throws Exception {
_storeThumbnail(
companyId, groupId, fileEntryId, fileVersionId, custom1ImageId,
custom2ImageId, is, type);
}
@Override
public void trigger(
FileVersion sourceFileVersion, FileVersion destinationFileVersion) {
super.trigger(sourceFileVersion, destinationFileVersion);
_queueGeneration(sourceFileVersion, destinationFileVersion);
}
@Override
protected void doExportGeneratedFiles(
PortletDataContext portletDataContext, FileEntry fileEntry,
Element fileEntryElement)
throws Exception {
exportThumbnails(
portletDataContext, fileEntry, fileEntryElement, "image");
exportPreview(portletDataContext, fileEntry, fileEntryElement);
}
@Override
protected void doImportGeneratedFiles(
PortletDataContext portletDataContext, FileEntry fileEntry,
FileEntry importedFileEntry, Element fileEntryElement)
throws Exception {
importThumbnails(
portletDataContext, fileEntry, importedFileEntry, fileEntryElement,
"image");
FileVersion importedFileVersion = importedFileEntry.getFileVersion();
if (!_previewGenerationRequired(importedFileVersion)) {
return;
}
importPreview(
portletDataContext, fileEntry, importedFileEntry, fileEntryElement,
"image", getPreviewType(importedFileVersion));
}
protected void exportPreview(
PortletDataContext portletDataContext, FileEntry fileEntry,
Element fileEntryElement)
throws Exception {
FileVersion fileVersion = fileEntry.getFileVersion();
if (!isSupported(fileVersion) ||
!_previewGenerationRequired(fileVersion) ||
!_hasPreview(fileVersion)) {
return;
}
exportPreview(
portletDataContext, fileEntry, fileEntryElement, "image",
getPreviewType(fileVersion));
}
@Override
protected List<Long> getFileVersionIds() {
return _fileVersionIds;
}
private void _generateImages(
FileVersion sourceFileVersion, FileVersion destinationFileVersion)
throws Exception {
InputStream inputStream = null;
try {
if (sourceFileVersion != null) {
copy(sourceFileVersion, destinationFileVersion);
return;
}
if (!PropsValues.DL_FILE_ENTRY_THUMBNAIL_ENABLED &&
!PropsValues.DL_FILE_ENTRY_PREVIEW_ENABLED) {
return;
}
inputStream = destinationFileVersion.getContentStream(false);
byte[] bytes = FileUtil.getBytes(inputStream);
ImageBag imageBag = ImageToolUtil.read(bytes);
RenderedImage renderedImage = imageBag.getRenderedImage();
if (renderedImage == null) {
return;
}
ColorModel colorModel = renderedImage.getColorModel();
if (colorModel.getNumColorComponents() == 4) {
Future<RenderedImage> future = ImageToolUtil.convertCMYKtoRGB(
bytes, imageBag.getType());
if (future == null) {
return;
}
String processIdentity = String.valueOf(
destinationFileVersion.getFileVersionId());
futures.put(processIdentity, future);
RenderedImage convertedRenderedImage = future.get();
if (convertedRenderedImage != null) {
renderedImage = convertedRenderedImage;
}
}
if (!_hasPreview(destinationFileVersion)) {
_storePreviewImage(destinationFileVersion, renderedImage);
}
if (!hasThumbnails(destinationFileVersion)) {
storeThumbnailImages(destinationFileVersion, renderedImage);
}
}
catch (NoSuchFileEntryException nsfee) {
if (_log.isDebugEnabled()) {
_log.debug(nsfee, nsfee);
}
}
finally {
StreamUtil.cleanUp(inputStream);
_fileVersionIds.remove(destinationFileVersion.getFileVersionId());
}
}
private String _getType(FileVersion fileVersion) {
String type = "png";
if (fileVersion == null) {
return type;
}
String mimeType = fileVersion.getMimeType();
if (mimeType.equals(ContentTypes.IMAGE_BMP)) {
type = ImageTool.TYPE_BMP;
}
else if (mimeType.equals(ContentTypes.IMAGE_GIF)) {
type = ImageTool.TYPE_GIF;
}
else if (mimeType.equals(ContentTypes.IMAGE_JPEG)) {
type = ImageTool.TYPE_JPEG;
}
else if (mimeType.equals(ContentTypes.IMAGE_PNG)) {
type = ImageTool.TYPE_PNG;
}
else if (!_previewGenerationRequired(fileVersion)) {
type = fileVersion.getExtension();
}
return type;
}
private boolean _hasPreview(FileVersion fileVersion)
throws PortalException {
if (PropsValues.DL_FILE_ENTRY_PREVIEW_ENABLED &&
_previewGenerationRequired(fileVersion)) {
String type = getPreviewType(fileVersion);
String previewFilePath = getPreviewFilePath(fileVersion, type);
if (!DLStoreUtil.hasFile(
fileVersion.getCompanyId(), REPOSITORY_ID,
previewFilePath)) {
return false;
}
}
return true;
}
private boolean _previewGenerationRequired(FileVersion fileVersion) {
String mimeType = fileVersion.getMimeType();
if (mimeType.contains("tiff") || mimeType.contains("tif")) {
return true;
}
else {
return false;
}
}
private void _queueGeneration(
FileVersion sourceFileVersion, FileVersion destinationFileVersion) {
if (_fileVersionIds.contains(
destinationFileVersion.getFileVersionId()) ||
!isSupported(destinationFileVersion)) {
return;
}
_fileVersionIds.add(destinationFileVersion.getFileVersionId());
sendGenerationMessage(
DestinationNames.DOCUMENT_LIBRARY_IMAGE_PROCESSOR,
sourceFileVersion, destinationFileVersion);
}
private void _storePreviewImage(
FileVersion fileVersion, RenderedImage renderedImage)
throws Exception {
String type = getPreviewType(fileVersion);
File file = null;
try {
file = FileUtil.createTempFile(type);
try (FileOutputStream fos = new FileOutputStream(file)) {
ImageToolUtil.write(renderedImage, type, fos);
}
addFileToStore(
fileVersion.getCompanyId(), PREVIEW_PATH,
getPreviewFilePath(fileVersion, type), file);
}
finally {
FileUtil.delete(file);
}
}
private void _storeThumbnail(
long companyId, long groupId, long fileEntryId, long fileVersionId,
long custom1ImageId, long custom2ImageId, InputStream is,
String type)
throws Exception {
StringBundler sb = new StringBundler(5);
sb.append(getPathSegment(groupId, fileEntryId, fileVersionId, false));
if (custom1ImageId != 0) {
sb.append(StringPool.DASH);
sb.append(1);
}
else if (custom2ImageId != 0) {
sb.append(StringPool.DASH);
sb.append(2);
}
if (Validator.isNotNull(type)) {
sb.append(StringPool.PERIOD);
sb.append(type);
}
String filePath = sb.toString();
File file = null;
try {
file = FileUtil.createTempFile(is);
addFileToStore(companyId, THUMBNAIL_PATH, filePath, file);
}
finally {
FileUtil.delete(file);
}
}
private static final Log _log = LogFactoryUtil.getLog(
ImageProcessorImpl.class);
private final List<Long> _fileVersionIds = new Vector<>();
private final Set<String> _imageMimeTypes = SetUtil.fromArray(
PropsValues.DL_FILE_ENTRY_PREVIEW_IMAGE_MIME_TYPES);
}