/*
* (C) Copyright 2006-2013 Nuxeo SA (http://nuxeo.com/) and others.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Contributors:
* Laurent Doguin
* Florent Guillaume
*/
package org.nuxeo.ecm.platform.picture.core.im;
import java.io.File;
import java.io.IOException;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.nuxeo.ecm.core.api.Blob;
import org.nuxeo.ecm.core.api.Blobs;
import org.nuxeo.ecm.platform.commandline.executor.api.CommandAvailability;
import org.nuxeo.ecm.platform.commandline.executor.api.CommandException;
import org.nuxeo.ecm.platform.commandline.executor.api.CommandLineExecutorService;
import org.nuxeo.ecm.platform.commandline.executor.api.CommandNotAvailable;
import org.nuxeo.ecm.platform.picture.core.ImageUtils;
import org.nuxeo.ecm.platform.picture.magick.utils.ImageConverter;
import org.nuxeo.ecm.platform.picture.magick.utils.ImageCropper;
import org.nuxeo.ecm.platform.picture.magick.utils.ImageIdentifier;
import org.nuxeo.ecm.platform.picture.magick.utils.ImageResizer;
import org.nuxeo.ecm.platform.picture.magick.utils.ImageRotater;
import org.nuxeo.runtime.api.Framework;
public class IMImageUtils implements ImageUtils {
private static final Log log = LogFactory.getLog(IMImageUtils.class);
public static abstract class ImageMagickCaller {
protected File sourceFile;
// a tmp file is needed if the blob doesn't have a file, or
// if it has one but with an incorrect extension
protected File tmpFile;
protected File targetFile;
public Blob call(Blob blob, String targetExt, String commandName) {
CommandLineExecutorService cles = Framework.getLocalService(CommandLineExecutorService.class);
CommandAvailability availability = cles.getCommandAvailability(commandName);
if (!availability.isAvailable()) {
return null;
}
try {
makeFiles(blob, targetExt);
callImageMagick();
Blob targetBlob = Blobs.createBlob(targetFile);
Framework.trackFile(targetFile, targetBlob);
return targetBlob;
} catch (CommandNotAvailable | CommandException | IOException e) {
log.error("ImageMagick failed on command: " + commandName, e);
return null;
} finally {
if (tmpFile != null) {
tmpFile.delete();
}
}
}
protected void makeFiles(Blob blob, String targetExt) throws CommandNotAvailable, CommandException, IOException {
sourceFile = blob.getFile();
// check extension
String ext = FilenameUtils.getExtension(blob.getFilename());
if (ext == null || "".equals(ext)) {
// no known extension
if (sourceFile == null) {
sourceFile = createTempSource(blob, "tmp");
}
// detect extension
ext = ImageIdentifier.getInfo(sourceFile.getPath()).getFormat();
if (tmpFile == null) {
// copy source with proper name
sourceFile = createTempSource(blob, ext);
} else {
// rename tmp file
File newTmpFile = new File(FilenameUtils.removeExtension(tmpFile.getPath()) + "." + ext);
tmpFile.renameTo(newTmpFile);
tmpFile = newTmpFile;
sourceFile = newTmpFile;
}
} else {
// check that extension on source is correct
if (sourceFile != null && !ext.equals(FilenameUtils.getExtension(sourceFile.getName()))) {
sourceFile = null;
}
}
if (sourceFile == null) {
sourceFile = createTempSource(blob, ext);
}
if (targetExt == null) {
targetExt = ext;
}
targetFile = Framework.createTempFile("nuxeoImageTarget", "." + targetExt);
}
protected File createTempSource(Blob blob, String ext) throws IOException {
tmpFile = Framework.createTempFile("nuxeoImageSource", "." + ext);
blob.transferTo(tmpFile);
return tmpFile;
}
public abstract void callImageMagick() throws CommandNotAvailable, CommandException;
}
@Override
public Blob crop(Blob blob, final int x, final int y, final int width, final int height) {
return new ImageMagickCaller() {
@Override
public void callImageMagick() throws CommandNotAvailable, CommandException {
ImageCropper.crop(sourceFile.getAbsolutePath(), targetFile.getAbsolutePath(), width, height, x, y);
}
}.call(blob, null, "resizer");
}
@Override
public Blob resize(Blob blob, String finalFormat, final int width, final int height, final int depth) {
return new ImageMagickCaller() {
@Override
public void callImageMagick() throws CommandNotAvailable, CommandException {
ImageResizer.resize(sourceFile.getAbsolutePath(), targetFile.getAbsolutePath(), width, height, depth);
}
}.call(blob, finalFormat, "resizer");
}
@Override
public Blob rotate(Blob blob, final int angle) {
return new ImageMagickCaller() {
@Override
public void callImageMagick() throws CommandNotAvailable, CommandException {
ImageRotater.rotate(sourceFile.getAbsolutePath(), targetFile.getAbsolutePath(), angle);
}
}.call(blob, null, "rotate");
}
@Override
public Blob convertToPDF(Blob blob) {
return new ImageMagickCaller() {
@Override
public void callImageMagick() throws CommandNotAvailable, CommandException {
ImageConverter.convert(sourceFile.getAbsolutePath(), targetFile.getAbsolutePath());
}
}.call(blob, "pdf", "converter");
}
@Override
public boolean isAvailable() {
CommandLineExecutorService cles = Framework.getLocalService(CommandLineExecutorService.class);
CommandAvailability commandAvailability = cles.getCommandAvailability("identify");
return commandAvailability.isAvailable();
}
}