001/*
002 * (C) Copyright 2006-2008 Nuxeo SAS (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     Nuxeo - initial API and implementation
016 *
017 * $Id$
018 */
019
020package org.nuxeo.ecm.platform.picture.api.adapters;
021
022import static org.nuxeo.ecm.platform.picture.api.ImagingDocumentConstants.PICTURE_INFO_PROPERTY;
023
024import java.io.File;
025import java.io.IOException;
026import java.io.Serializable;
027import java.util.ArrayList;
028import java.util.Collection;
029import java.util.HashMap;
030import java.util.List;
031import java.util.Map;
032
033import org.apache.commons.logging.Log;
034import org.apache.commons.logging.LogFactory;
035import org.nuxeo.common.utils.FileUtils;
036import org.nuxeo.ecm.core.api.Blob;
037import org.nuxeo.ecm.core.api.Blobs;
038import org.nuxeo.ecm.core.api.PropertyException;
039import org.nuxeo.ecm.core.api.blobholder.BlobHolder;
040import org.nuxeo.ecm.core.api.blobholder.SimpleBlobHolder;
041import org.nuxeo.ecm.core.api.model.Property;
042import org.nuxeo.ecm.platform.commandline.executor.api.CommandLineExecutorService;
043import org.nuxeo.ecm.platform.picture.api.ImageInfo;
044import org.nuxeo.ecm.platform.picture.api.ImagingConvertConstants;
045import org.nuxeo.ecm.platform.picture.api.ImagingService;
046import org.nuxeo.ecm.platform.picture.api.PictureConversion;
047import org.nuxeo.ecm.platform.picture.api.PictureView;
048import org.nuxeo.runtime.api.Framework;
049
050public class DefaultPictureAdapter extends AbstractPictureAdapter {
051    private static final Log log = LogFactory.getLog(DefaultPictureAdapter.class);
052
053    // needs trailing slash
054    private static final String VIEW_XPATH = "picture:views/item[%d]/";
055
056    private static final String TITLE_PROPERTY = "title";
057
058    private static final String FILENAME_PROPERTY = "filename";
059
060    @Override
061    public boolean createPicture(Blob blob, String filename, String title,
062            ArrayList<Map<String, Object>> pictureConversions) throws IOException {
063        return fillPictureViews(blob, filename, title, pictureConversions);
064    }
065
066    @Override
067    public boolean fillPictureViews(Blob blob, String filename, String title,
068            ArrayList<Map<String, Object>> pictureConversions) throws IOException {
069        if (blob == null) {
070            clearViews();
071            return true;
072        }
073
074        File file = blob.getFile();
075        CommandLineExecutorService commandLineExecutorService = Framework.getLocalService(CommandLineExecutorService.class);
076        boolean validFilename = file != null && commandLineExecutorService.isValidParameter(file.getName());
077        if (file == null || !validFilename) {
078            String extension;
079            if (file != null) {
080                extension = "." + FileUtils.getFileExtension(file.getName());
081            } else {
082                extension = ".jpg";
083            }
084            file = File.createTempFile("nuxeoImage", extension);
085            Framework.trackFile(file, this);
086            blob.transferTo(file);
087            // use a persistent blob with our file
088            if (!validFilename) {
089                String digest = blob.getDigest();
090                blob = Blobs.createBlob(file, blob.getMimeType(), blob.getEncoding(), blob.getFilename());
091                blob.setDigest(digest);
092            }
093        }
094
095        fileContent = blob;
096
097        type = blob.getMimeType();
098        if (type == null || type.equals("application/octet-stream")) {
099            // TODO : use MimetypeRegistry instead
100            type = getImagingService().getImageMimeType(file);
101            blob.setMimeType(type);
102        }
103        if (type == null || type.equals("application/octet-stream")) {
104            return false;
105        }
106
107        ImageInfo imageInfo = getImageInfo();
108        if (imageInfo != null) {
109            doc.setPropertyValue(PICTURE_INFO_PROPERTY, (Serializable) imageInfo.toMap());
110        }
111
112        if (imageInfo != null) {
113            width = imageInfo.getWidth();
114            height = imageInfo.getHeight();
115            depth = imageInfo.getDepth();
116        }
117
118        if (width != null && height != null) {
119            clearViews();
120            addViews(pictureConversions, filename, title);
121        }
122        return true;
123    }
124
125    @Override
126    public void preFillPictureViews(Blob blob, List<Map<String, Object>> pictureConversions, ImageInfo imageInfo)
127            throws IOException {
128        ImagingService imagingService = getImagingService();
129        List<PictureView> pictureViews;
130
131        if (pictureConversions != null) {
132            List<PictureConversion> conversions = new ArrayList<PictureConversion>(pictureConversions.size());
133            for (Map<String, Object> template : pictureConversions) {
134                conversions.add(new PictureConversion((String) template.get("title"),
135                        (String) template.get("description"), (String) template.get("tag"), 0));
136            }
137
138            pictureViews = imagingService.computeViewsFor(blob, conversions, imageInfo, false);
139        } else {
140            pictureViews = imagingService.computeViewsFor(doc, blob, imageInfo, false);
141        }
142
143        addPictureViews(pictureViews, true);
144    }
145
146    @Override
147    public void doRotate(int angle) {
148        int size = doc.getProperty(VIEWS_PROPERTY).size();
149        for (int i = 0; i < size; i++) {
150            String xpath = "picture:views/view[" + i + "]/";
151            BlobHolder blob = new SimpleBlobHolder(doc.getProperty(xpath + "content").getValue(Blob.class));
152            String type = blob.getBlob().getMimeType();
153            if (type != "image/png") {
154                Map<String, Serializable> options = new HashMap<String, Serializable>();
155                options.put(ImagingConvertConstants.OPTION_ROTATE_ANGLE, angle);
156                blob = getConversionService().convert(ImagingConvertConstants.OPERATION_ROTATE, blob, options);
157                doc.getProperty(xpath + "content").setValue(blob.getBlob());
158                Long height = (Long) doc.getProperty(xpath + "height").getValue();
159                Long width = (Long) doc.getProperty(xpath + "width").getValue();
160                doc.getProperty(xpath + "height").setValue(width);
161                doc.getProperty(xpath + "width").setValue(height);
162            }
163        }
164    }
165
166    @Override
167    public void doCrop(String coords) {
168        doc.setPropertyValue("picture:cropCoords", coords);
169    }
170
171    @Override
172    public Blob getPictureFromTitle(String title) throws PropertyException {
173        if (title == null) {
174            return null;
175        }
176        Collection<Property> views = doc.getProperty(VIEWS_PROPERTY).getChildren();
177        for (Property property : views) {
178            if (title.equals(property.getValue(TITLE_PROPERTY))) {
179                Blob blob = (Blob) property.getValue("content");
180                if (blob != null) {
181                    blob.setFilename((String) property.getValue(FILENAME_PROPERTY));
182                }
183                return blob;
184            }
185        }
186        return null;
187    }
188
189    @Override
190    public String getFirstViewXPath() {
191        return getViewXPathFor(0);
192    }
193
194    @Override
195    public String getViewXPath(String viewName) {
196        Property views = doc.getProperty(VIEWS_PROPERTY);
197        for (int i = 0; i < views.size(); i++) {
198            if (views.get(i).getValue(TITLE_PROPERTY).equals(viewName)) {
199                return getViewXPathFor(i);
200            }
201        }
202        return null;
203    }
204
205    protected String getViewXPathFor(int index) {
206        return String.format(VIEW_XPATH, index);
207    }
208
209}