001/*
002 * (C) Copyright 2006-2008 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Nuxeo - initial API and implementation
018 *
019 * $Id$
020 */
021
022package org.nuxeo.ecm.platform.picture.api.adapters;
023
024import static org.nuxeo.ecm.platform.picture.api.ImagingDocumentConstants.PICTURE_INFO_PROPERTY;
025
026import java.io.File;
027import java.io.IOException;
028import java.io.Serializable;
029import java.util.ArrayList;
030import java.util.Collection;
031import java.util.HashMap;
032import java.util.List;
033import java.util.Map;
034
035import org.apache.commons.logging.Log;
036import org.apache.commons.logging.LogFactory;
037import org.nuxeo.ecm.core.api.Blob;
038import org.nuxeo.ecm.core.api.Blobs;
039import org.nuxeo.ecm.core.api.PropertyException;
040import org.nuxeo.ecm.core.api.blobholder.BlobHolder;
041import org.nuxeo.ecm.core.api.blobholder.SimpleBlobHolder;
042import org.nuxeo.ecm.core.api.model.Property;
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        if (file == null) {
076            file = Framework.createTempFile("nuxeoImage", ".jpg");
077            Framework.trackFile(file, this);
078            blob.transferTo(file);
079            // use a persistent blob with our file
080            String digest = blob.getDigest();
081            blob = Blobs.createBlob(file, blob.getMimeType(), blob.getEncoding(), blob.getFilename());
082            blob.setDigest(digest);
083        }
084
085        fileContent = blob;
086
087        type = blob.getMimeType();
088        if (type == null || type.equals("application/octet-stream")) {
089            // TODO : use MimetypeRegistry instead
090            type = getImagingService().getImageMimeType(file);
091            blob.setMimeType(type);
092        }
093        if (type == null || type.equals("application/octet-stream")) {
094            return false;
095        }
096
097        ImageInfo imageInfo = getImageInfo();
098        if (imageInfo != null) {
099            doc.setPropertyValue(PICTURE_INFO_PROPERTY, (Serializable) imageInfo.toMap());
100        }
101
102        if (imageInfo != null) {
103            width = imageInfo.getWidth();
104            height = imageInfo.getHeight();
105            depth = imageInfo.getDepth();
106        }
107
108        if (width != null && height != null) {
109            clearViews();
110            addViews(pictureConversions, filename, title);
111        }
112        return true;
113    }
114
115    @Override
116    public void preFillPictureViews(Blob blob, List<Map<String, Object>> pictureConversions, ImageInfo imageInfo)
117            throws IOException {
118        ImagingService imagingService = getImagingService();
119        List<PictureView> pictureViews;
120
121        if (pictureConversions != null) {
122            List<PictureConversion> conversions = new ArrayList<PictureConversion>(pictureConversions.size());
123            for (Map<String, Object> template : pictureConversions) {
124                conversions.add(new PictureConversion((String) template.get("title"),
125                        (String) template.get("description"), (String) template.get("tag"), 0));
126            }
127
128            pictureViews = imagingService.computeViewsFor(blob, conversions, imageInfo, false);
129        } else {
130            pictureViews = imagingService.computeViewsFor(doc, blob, imageInfo, false);
131        }
132
133        addPictureViews(pictureViews, true);
134    }
135
136    @Override
137    public void doRotate(int angle) {
138        int size = doc.getProperty(VIEWS_PROPERTY).size();
139        for (int i = 0; i < size; i++) {
140            String xpath = "picture:views/view[" + i + "]/";
141            BlobHolder blob = new SimpleBlobHolder(doc.getProperty(xpath + "content").getValue(Blob.class));
142            String type = blob.getBlob().getMimeType();
143            if (type != "image/png") {
144                Map<String, Serializable> options = new HashMap<String, Serializable>();
145                options.put(ImagingConvertConstants.OPTION_ROTATE_ANGLE, angle);
146                blob = getConversionService().convert(ImagingConvertConstants.OPERATION_ROTATE, blob, options);
147                doc.getProperty(xpath + "content").setValue(blob.getBlob());
148                Long height = (Long) doc.getProperty(xpath + "height").getValue();
149                Long width = (Long) doc.getProperty(xpath + "width").getValue();
150                doc.getProperty(xpath + "height").setValue(width);
151                doc.getProperty(xpath + "width").setValue(height);
152            }
153        }
154    }
155
156    @Override
157    public void doCrop(String coords) {
158        doc.setPropertyValue("picture:cropCoords", coords);
159    }
160
161    @Override
162    public Blob getPictureFromTitle(String title) throws PropertyException {
163        if (title == null) {
164            return null;
165        }
166        Collection<Property> views = doc.getProperty(VIEWS_PROPERTY).getChildren();
167        for (Property property : views) {
168            if (title.equals(property.getValue(TITLE_PROPERTY))) {
169                Blob blob = (Blob) property.getValue("content");
170                if (blob != null) {
171                    blob.setFilename((String) property.getValue(FILENAME_PROPERTY));
172                }
173                return blob;
174            }
175        }
176        return null;
177    }
178
179    @Override
180    public String getFirstViewXPath() {
181        return getViewXPathFor(0);
182    }
183
184    @Override
185    public String getViewXPath(String viewName) {
186        Property views = doc.getProperty(VIEWS_PROPERTY);
187        for (int i = 0; i < views.size(); i++) {
188            if (views.get(i).getValue(TITLE_PROPERTY).equals(viewName)) {
189                return getViewXPathFor(i);
190            }
191        }
192        return null;
193    }
194
195    protected String getViewXPathFor(int index) {
196        return String.format(VIEW_XPATH, index);
197    }
198
199}