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.ecm.core.api.Blob;
036import org.nuxeo.ecm.core.api.Blobs;
037import org.nuxeo.ecm.core.api.PropertyException;
038import org.nuxeo.ecm.core.api.blobholder.BlobHolder;
039import org.nuxeo.ecm.core.api.blobholder.SimpleBlobHolder;
040import org.nuxeo.ecm.core.api.model.Property;
041import org.nuxeo.ecm.platform.picture.api.ImageInfo;
042import org.nuxeo.ecm.platform.picture.api.ImagingConvertConstants;
043import org.nuxeo.ecm.platform.picture.api.ImagingService;
044import org.nuxeo.ecm.platform.picture.api.PictureConversion;
045import org.nuxeo.ecm.platform.picture.api.PictureView;
046import org.nuxeo.runtime.api.Framework;
047
048public class DefaultPictureAdapter extends AbstractPictureAdapter {
049    private static final Log log = LogFactory.getLog(DefaultPictureAdapter.class);
050
051    // needs trailing slash
052    private static final String VIEW_XPATH = "picture:views/item[%d]/";
053
054    private static final String TITLE_PROPERTY = "title";
055
056    private static final String FILENAME_PROPERTY = "filename";
057
058    @Override
059    public boolean createPicture(Blob blob, String filename, String title,
060            ArrayList<Map<String, Object>> pictureConversions) throws IOException {
061        return fillPictureViews(blob, filename, title, pictureConversions);
062    }
063
064    @Override
065    public boolean fillPictureViews(Blob blob, String filename, String title,
066            ArrayList<Map<String, Object>> pictureConversions) throws IOException {
067        if (blob == null) {
068            clearViews();
069            return true;
070        }
071
072        File file = blob.getFile();
073        if (file == null) {
074            file = File.createTempFile("nuxeoImage", ".jpg");
075            Framework.trackFile(file, this);
076            blob.transferTo(file);
077            // use a persistent blob with our file
078            String digest = blob.getDigest();
079            blob = Blobs.createBlob(file, blob.getMimeType(), blob.getEncoding(), blob.getFilename());
080            blob.setDigest(digest);
081        }
082
083        fileContent = blob;
084
085        type = blob.getMimeType();
086        if (type == null || type.equals("application/octet-stream")) {
087            // TODO : use MimetypeRegistry instead
088            type = getImagingService().getImageMimeType(file);
089            blob.setMimeType(type);
090        }
091        if (type == null || type.equals("application/octet-stream")) {
092            return false;
093        }
094
095        ImageInfo imageInfo = getImageInfo();
096        if (imageInfo != null) {
097            doc.setPropertyValue(PICTURE_INFO_PROPERTY, (Serializable) imageInfo.toMap());
098        }
099
100        if (imageInfo != null) {
101            width = imageInfo.getWidth();
102            height = imageInfo.getHeight();
103            depth = imageInfo.getDepth();
104        }
105
106        if (width != null && height != null) {
107            clearViews();
108            addViews(pictureConversions, filename, title);
109        }
110        return true;
111    }
112
113    @Override
114    public void preFillPictureViews(Blob blob, List<Map<String, Object>> pictureConversions, ImageInfo imageInfo)
115            throws IOException {
116        ImagingService imagingService = getImagingService();
117        List<PictureView> pictureViews;
118
119        if (pictureConversions != null) {
120            List<PictureConversion> conversions = new ArrayList<PictureConversion>(pictureConversions.size());
121            for (Map<String, Object> template : pictureConversions) {
122                conversions.add(new PictureConversion((String) template.get("title"),
123                        (String) template.get("description"), (String) template.get("tag"), 0));
124            }
125
126            pictureViews = imagingService.computeViewsFor(blob, conversions, imageInfo, false);
127        } else {
128            pictureViews = imagingService.computeViewsFor(doc, blob, imageInfo, false);
129        }
130
131        addPictureViews(pictureViews, true);
132    }
133
134    @Override
135    public void doRotate(int angle) {
136        int size = doc.getProperty(VIEWS_PROPERTY).size();
137        for (int i = 0; i < size; i++) {
138            String xpath = "picture:views/view[" + i + "]/";
139            BlobHolder blob = new SimpleBlobHolder(doc.getProperty(xpath + "content").getValue(Blob.class));
140            String type = blob.getBlob().getMimeType();
141            if (type != "image/png") {
142                Map<String, Serializable> options = new HashMap<String, Serializable>();
143                options.put(ImagingConvertConstants.OPTION_ROTATE_ANGLE, angle);
144                blob = getConversionService().convert(ImagingConvertConstants.OPERATION_ROTATE, blob, options);
145                doc.getProperty(xpath + "content").setValue(blob.getBlob());
146                Long height = (Long) doc.getProperty(xpath + "height").getValue();
147                Long width = (Long) doc.getProperty(xpath + "width").getValue();
148                doc.getProperty(xpath + "height").setValue(width);
149                doc.getProperty(xpath + "width").setValue(height);
150            }
151        }
152    }
153
154    @Override
155    public void doCrop(String coords) {
156        doc.setPropertyValue("picture:cropCoords", coords);
157    }
158
159    @Override
160    public Blob getPictureFromTitle(String title) throws PropertyException {
161        if (title == null) {
162            return null;
163        }
164        Collection<Property> views = doc.getProperty(VIEWS_PROPERTY).getChildren();
165        for (Property property : views) {
166            if (title.equals(property.getValue(TITLE_PROPERTY))) {
167                Blob blob = (Blob) property.getValue("content");
168                if (blob != null) {
169                    blob.setFilename((String) property.getValue(FILENAME_PROPERTY));
170                }
171                return blob;
172            }
173        }
174        return null;
175    }
176
177    @Override
178    public String getFirstViewXPath() {
179        return getViewXPathFor(0);
180    }
181
182    @Override
183    public String getViewXPath(String viewName) {
184        Property views = doc.getProperty(VIEWS_PROPERTY);
185        for (int i = 0; i < views.size(); i++) {
186            if (views.get(i).getValue(TITLE_PROPERTY).equals(viewName)) {
187                return getViewXPathFor(i);
188            }
189        }
190        return null;
191    }
192
193    protected String getViewXPathFor(int index) {
194        return String.format(VIEW_XPATH, index);
195    }
196
197}