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}