/* * (C) Copyright 2006-2016 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: * Nuxeo - initial API and implementation */ package org.nuxeo.ecm.platform.picture.api.adapters; import static org.nuxeo.ecm.platform.picture.api.ImagingConvertConstants.OPERATION_CROP; import static org.nuxeo.ecm.platform.picture.api.ImagingConvertConstants.OPTION_CROP_X; import static org.nuxeo.ecm.platform.picture.api.ImagingConvertConstants.OPTION_CROP_Y; import static org.nuxeo.ecm.platform.picture.api.ImagingConvertConstants.OPTION_RESIZE_HEIGHT; import static org.nuxeo.ecm.platform.picture.api.ImagingConvertConstants.OPTION_RESIZE_WIDTH; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_BY_LINE; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_BY_LINE_TITLE; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_CAPTION; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_CATEGORY; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_CITY; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_COLORSPACE; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_COMMENT; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_COPYRIGHT; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_COPYRIGHT_NOTICE; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_COUNTRY_OR_PRIMARY_LOCATION; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_CREDIT; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_DATE_CREATED; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_DESCRIPTION; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_EQUIPMENT; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_EXPOSURE; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_FNUMBER; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_FOCALLENGTH; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_HEADLINE; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_HEIGHT; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_HRESOLUTION; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_ICCPROFILE; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_ISOSPEED; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_KEYWORDS; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_LANGUAGE; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_OBJECT_NAME; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_ORIENTATION; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_ORIGINALDATE; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_ORIGINAL_TRANSMISSION_REFERENCE; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_ORIGINATING_PROGRAM; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_PIXEL_XDIMENSION; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_PIXEL_YDIMENSION; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_PROVINCE_OR_STATE; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_RECORD_VERSION; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_RELEASE_DATE; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_RELEASE_TIME; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_SOURCE; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_SPECIAL_INSTRUCTIONS; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_SUPPLEMENTAL_CATEGORIES; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_TIME_CREATED; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_URGENCY; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_VRESOLUTION; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_WHITEBALANCE; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_WIDTH; import static org.nuxeo.ecm.platform.picture.api.MetadataConstants.META_WRITER; import java.awt.color.ICC_Profile; import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.List; import java.util.Map; import org.nuxeo.ecm.core.api.Blob; import org.nuxeo.ecm.core.api.Blobs; import org.nuxeo.ecm.core.api.CoreSession; import org.nuxeo.ecm.core.api.DocumentModel; import org.nuxeo.ecm.core.api.NuxeoException; import org.nuxeo.ecm.core.api.blobholder.BlobHolder; import org.nuxeo.ecm.core.api.blobholder.SimpleBlobHolder; import org.nuxeo.ecm.core.convert.api.ConversionService; import org.nuxeo.ecm.platform.picture.api.ImageInfo; import org.nuxeo.ecm.platform.picture.api.ImagingService; import org.nuxeo.ecm.platform.picture.api.PictureConversion; import org.nuxeo.ecm.platform.picture.api.PictureView; import org.nuxeo.runtime.api.Framework; public abstract class AbstractPictureAdapter implements PictureResourceAdapter { public static final String VIEWS_PROPERTY = "picture:views"; public static final String CONTENT_XPATH = "picture:views/view[%d]/content"; public static final String FIELD_HEADLINE = "headline"; public static final String FIELD_SUBHEADLINE = "subheadline"; public static final String FIELD_BYLINE = "byline"; public static final String FIELD_DATELINE = "dateline"; public static final String FIELD_SLUGLINE = "slugline"; public static final String FIELD_CREDIT = "credit"; public static final String FIELD_LANGUAGE = "language"; public static final String FIELD_SOURCE = "source"; public static final String FIELD_ORIGIN = "origin"; public static final String FIELD_GENRE = "genre"; public static final String FIELD_CAPTION = "caption"; public static final String FIELD_TYPAGE = "typage"; public static final String SCHEMA_NAME = "picture"; public static final int MEDIUM_SIZE = 1200; public static final int SMALL_SIZE = 350; public static final int THUMB_SIZE = 150; protected DocumentModel doc; protected Integer width; protected Integer height; protected Integer depth; protected String description; protected String type; protected Blob fileContent; /** @since 5.9.5 */ protected ImageInfo imageInfo; private CoreSession session; private ConversionService converionService; @Override public void setDocumentModel(DocumentModel doc) { this.doc = doc; } protected ImagingService getImagingService() { return Framework.getLocalService(ImagingService.class); } protected ConversionService getConversionService() { if (converionService == null) { converionService = Framework.getService(ConversionService.class); } return converionService; } protected CoreSession getSession() { if (session == null) { if (doc == null) { return null; } session = doc.getCoreSession(); } return session; } protected void setMetadata() throws IOException { boolean imageInfoUsed = false; ImageInfo imageInfo = getImageInfo(); if (imageInfo != null) { width = imageInfo.getWidth(); height = imageInfo.getHeight(); depth = imageInfo.getDepth(); imageInfoUsed = true; } Map<String, Object> metadata = getImagingService().getImageMetadata(fileContent); description = (String) metadata.get(META_DESCRIPTION); if (!imageInfoUsed) { width = (Integer) metadata.get(META_WIDTH); height = (Integer) metadata.get(META_HEIGHT); } doc.setPropertyValue("picture:" + FIELD_BYLINE, (String) metadata.get(META_BY_LINE)); doc.setPropertyValue("picture:" + FIELD_CAPTION, (String) metadata.get(META_CAPTION)); doc.setPropertyValue("picture:" + FIELD_CREDIT, (String) metadata.get(META_CREDIT)); if (metadata.containsKey(META_DATE_CREATED)) { doc.setPropertyValue("picture:" + FIELD_DATELINE, metadata.get(META_DATE_CREATED).toString()); } doc.setPropertyValue("picture:" + FIELD_HEADLINE, (String) metadata.get(META_HEADLINE)); doc.setPropertyValue("picture:" + FIELD_LANGUAGE, (String) metadata.get(META_LANGUAGE)); doc.setPropertyValue("picture:" + FIELD_ORIGIN, (String) metadata.get(META_OBJECT_NAME)); doc.setPropertyValue("picture:" + FIELD_SOURCE, (String) metadata.get(META_SOURCE)); // Set EXIF info doc.setPropertyValue("imd:image_description", (String) metadata.get(META_DESCRIPTION)); doc.setPropertyValue("imd:user_comment", (String) metadata.get(META_COMMENT)); doc.setPropertyValue("imd:equipment", (String) metadata.get(META_EQUIPMENT)); Date dateTimeOriginal = (Date) metadata.get(META_ORIGINALDATE); if (dateTimeOriginal != null) { Calendar calendar = new GregorianCalendar(); calendar.setTime(dateTimeOriginal); doc.setPropertyValue("imd:date_time_original", calendar); } doc.setPropertyValue("imd:xresolution", (Integer) metadata.get(META_HRESOLUTION)); doc.setPropertyValue("imd:yresolution", (Integer) metadata.get(META_VRESOLUTION)); doc.setPropertyValue("imd:pixel_xdimension", (Integer) metadata.get(META_PIXEL_XDIMENSION)); doc.setPropertyValue("imd:pixel_ydimension", (Integer) metadata.get(META_PIXEL_YDIMENSION)); doc.setPropertyValue("imd:copyright", (String) metadata.get(META_COPYRIGHT)); doc.setPropertyValue("imd:exposure_time", (String) metadata.get(META_EXPOSURE)); doc.setPropertyValue("imd:iso_speed_ratings", (String) metadata.get(META_ISOSPEED)); doc.setPropertyValue("imd:focal_length", (Double) metadata.get(META_FOCALLENGTH)); doc.setPropertyValue("imd:color_space", (String) metadata.get(META_COLORSPACE)); doc.setPropertyValue("imd:white_balance", (String) metadata.get(META_WHITEBALANCE)); ICC_Profile iccProfile = (ICC_Profile) metadata.get(META_ICCPROFILE); if (iccProfile != null) { doc.setPropertyValue("imd:icc_profile", iccProfile.toString()); } doc.setPropertyValue("imd:orientation", (String) metadata.get(META_ORIENTATION)); doc.setPropertyValue("imd:fnumber", (Double) metadata.get(META_FNUMBER)); // Set IPTC info doc.setPropertyValue("iptc:by_line", (String) metadata.get(META_BY_LINE)); doc.setPropertyValue("iptc:by_line_title", (String) metadata.get(META_BY_LINE_TITLE)); doc.setPropertyValue("iptc:caption", (String) metadata.get(META_CAPTION)); doc.setPropertyValue("iptc:category", (String) metadata.get(META_CATEGORY)); doc.setPropertyValue("iptc:city", (String) metadata.get(META_CITY)); doc.setPropertyValue("iptc:copyright_notice", (String) metadata.get(META_COPYRIGHT_NOTICE)); doc.setPropertyValue("iptc:country_or_primary_location", (String) metadata.get(META_COUNTRY_OR_PRIMARY_LOCATION)); doc.setPropertyValue("iptc:credit", (String) metadata.get(META_CREDIT)); Date dateCreated = (Date) metadata.get(META_DATE_CREATED); if (dateCreated != null) { Calendar calendar = new GregorianCalendar(); calendar.setTime(dateCreated); doc.setPropertyValue("iptc:date_created", calendar); } doc.setPropertyValue("iptc:headline", (String) metadata.get(META_HEADLINE)); doc.setPropertyValue("iptc:keywords", (String) metadata.get(META_KEYWORDS)); doc.setPropertyValue("iptc:language", (String) metadata.get(META_LANGUAGE)); doc.setPropertyValue("iptc:object_name", (String) metadata.get(META_OBJECT_NAME)); doc.setPropertyValue("iptc:original_transmission_ref", (String) metadata.get(META_ORIGINAL_TRANSMISSION_REFERENCE)); doc.setPropertyValue("iptc:originating_program", (String) metadata.get(META_ORIGINATING_PROGRAM)); doc.setPropertyValue("iptc:province_or_state", (String) metadata.get(META_PROVINCE_OR_STATE)); doc.setPropertyValue("iptc:record_version", (String) metadata.get(META_RECORD_VERSION)); Date releaseDate = (Date) metadata.get(META_RELEASE_DATE); if (releaseDate != null) { Calendar calendar = new GregorianCalendar(); calendar.setTime(releaseDate); doc.setPropertyValue("iptc:release_date", calendar); } doc.setPropertyValue("iptc:release_time", (String) metadata.get(META_RELEASE_TIME)); doc.setPropertyValue("iptc:source", (String) metadata.get(META_SOURCE)); doc.setPropertyValue("iptc:special_instructions", (String) metadata.get(META_SPECIAL_INSTRUCTIONS)); doc.setPropertyValue("iptc:supplemental_categories", (String) metadata.get(META_SUPPLEMENTAL_CATEGORIES)); doc.setPropertyValue("iptc:time_created", (String) metadata.get(META_TIME_CREATED)); doc.setPropertyValue("iptc:urgency", (String) metadata.get(META_URGENCY)); doc.setPropertyValue("iptc:writer", (String) metadata.get(META_WRITER)); } protected void clearViews() { List<Map<String, Object>> viewsList = new ArrayList<>(); doc.getProperty(VIEWS_PROPERTY).setValue(viewsList); } protected void addViews(List<Map<String, Object>> pictureConversions, String filename, String title) throws IOException { doc.setProperty("dublincore", "title", title); if (pictureConversions != null) { // Use PictureBook Properties for (Map<String, Object> view : pictureConversions) { Integer maxsize; if (view.get("maxsize") == null) { maxsize = MEDIUM_SIZE; } else { maxsize = ((Long) view.get("maxsize")).intValue(); } createPictureimpl((String) view.get("description"), (String) view.get("tag"), (String) view.get("title"), maxsize, filename, width, height, depth, fileContent); } } else { List<PictureView> pictureViews = getImagingService().computeViewsFor(doc, fileContent, getImageInfo(), true); addPictureViews(pictureViews, true); } } public void createPictureimpl(String description, String tag, String title, Integer maxsize, String filename, Integer width, Integer height, Integer depth, Blob fileContent) throws IOException { if (fileContent.getFilename() == null) { fileContent.setFilename(filename); } if (maxsize == null) { maxsize = 0; } PictureConversion pictureConversion = new PictureConversion(title, description, tag, maxsize); pictureConversion.setChainId("Image.Blob.Resize"); PictureView view = getImagingService().computeViewFor(fileContent, pictureConversion, getImageInfo(), true); addPictureView(view); } /** * Attach new picture views with the document * * @since 7.1 */ protected void addPictureViews(List<PictureView> pictureViews, boolean clearPictureViews) { if (clearPictureViews) { clearViews(); } List<Map<String, Serializable>> views = getPictureViews(); for (PictureView pictureView : pictureViews) { views.add(pictureView.asMap()); } doc.setPropertyValue(VIEWS_PROPERTY, (Serializable) views); } @Override public boolean fillPictureViews(Blob blob, String filename, String title) throws IOException { return fillPictureViews(blob, filename, title, null); } /** * Returns the picture views attached to the document if present, an empty list otherwise. * * @since 7.1 */ @SuppressWarnings("unchecked") protected List<Map<String, Serializable>> getPictureViews() { List<Map<String, Serializable>> views = (List<Map<String, Serializable>>) doc.getPropertyValue(VIEWS_PROPERTY); if (views == null) { views = new ArrayList<>(); } return views; } /** * Add a pictureView to the existing picture views attached with the document * * @since 7.1 */ protected void addPictureView(PictureView view) { List<Map<String, Serializable>> views = getPictureViews(); views.add(view.asMap()); doc.setPropertyValue(VIEWS_PROPERTY, (Serializable) views); } /** * Returns the {@link ImageInfo} for the main Blob ({@code fileContent}). * * @since 5.9.5. */ protected ImageInfo getImageInfo() { if (imageInfo == null) { imageInfo = getImagingService().getImageInfo(fileContent); } return imageInfo; } protected Blob getContentFromViews(Integer i) { return (Blob) doc.getPropertyValue(String.format(CONTENT_XPATH, i)); } protected Blob crop(Blob blob, Map<String, Serializable> coords) { try { BlobHolder bh = new SimpleBlobHolder(blob); String type = blob.getMimeType(); Map<String, Serializable> options = new HashMap<>(); options.put(OPTION_CROP_X, coords.get("x")); options.put(OPTION_CROP_Y, coords.get("y")); options.put(OPTION_RESIZE_HEIGHT, coords.get("h")); options.put(OPTION_RESIZE_WIDTH, coords.get("w")); if (!"image/png".equals(type)) { bh = getConversionService().convert(OPERATION_CROP, bh, options); return Blobs.createBlob(bh.getBlob().getStream(), type); } } catch (IOException e) { throw new NuxeoException("Crop failed", e); } return null; } }