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.pictures.tiles.magick.tiler;
023
024import java.util.HashMap;
025import java.util.Map;
026
027import org.nuxeo.common.utils.Path;
028import org.nuxeo.ecm.core.api.NuxeoException;
029import org.nuxeo.ecm.platform.commandline.executor.api.CommandException;
030import org.nuxeo.ecm.platform.commandline.executor.api.CommandNotAvailable;
031import org.nuxeo.ecm.platform.picture.api.ImageInfo;
032import org.nuxeo.ecm.platform.picture.magick.utils.ImageCropperAndResizer;
033import org.nuxeo.ecm.platform.pictures.tiles.api.PictureTiles;
034import org.nuxeo.ecm.platform.pictures.tiles.api.PictureTilesImpl;
035import org.nuxeo.ecm.platform.pictures.tiles.helpers.StringMaker;
036import org.nuxeo.ecm.platform.pictures.tiles.tilers.PictureTiler;
037
038/**
039 * ImageMagic based Tiler Uses several ImageMagick command lines to extract a tile form a picture file
040 *
041 * @author tiry
042 */
043public class MagickTiler implements PictureTiler {
044
045    /** @since 5.9.5. */
046    public static final String CMYK_MAP_COMPONENTS = "cmyk";
047
048    public boolean needsSync() {
049        return false;
050    }
051
052    public String getName() {
053        return "MagicTiler";
054    }
055
056    static int[] computeCropCoords(ImageInfo input, int maxTiles, int tileWidth, int tileHeight, int xCenter,
057            int yCenter) {
058        int startX = 0;
059        int startY = 0;
060        int cropWidth = 0;
061        int cropHeight = 0;
062        int ntx = 0;
063        int nty = 0;
064
065        if (input.getWidth() > input.getHeight()) {
066            cropWidth = input.getWidth() / maxTiles;
067            if ((input.getWidth() % maxTiles) > 0) {
068                cropWidth += 1;
069            }
070            Double exactCropHeight = (new Double(tileHeight)) / tileWidth * cropWidth;
071            if (exactCropHeight - exactCropHeight.intValue() > 0) {
072                cropHeight = exactCropHeight.intValue() + 1;
073            } else {
074                cropHeight = exactCropHeight.intValue();
075            }
076            ntx = maxTiles;
077            nty = input.getHeight() / cropHeight;
078            if ((input.getHeight() % cropHeight) > 0) {
079                nty += 1;
080            }
081        } else {
082            cropHeight = input.getHeight() / maxTiles;
083            if ((input.getHeight() % maxTiles) > 0) {
084                cropHeight += 1;
085            }
086            Double exactCropWidth = (new Double(tileWidth)) / tileHeight * cropHeight;
087            if (exactCropWidth - exactCropWidth.intValue() > 0) {
088                cropWidth = exactCropWidth.intValue() + 1;
089            } else {
090                cropWidth = exactCropWidth.intValue();
091            }
092            nty = maxTiles;
093            ntx = input.getWidth() / cropWidth;
094            if ((input.getWidth() % cropWidth) > 0) {
095                ntx += 1;
096            }
097        }
098
099        startX = xCenter * cropWidth;
100        startY = yCenter * cropHeight;
101
102        double widthRatio = new Double(tileWidth) / cropWidth;
103        double heightRatio = new Double(tileHeight) / cropHeight;
104
105        if (xCenter == ntx - 1) {
106            cropWidth = input.getWidth() - (xCenter) * cropWidth;
107            tileWidth = (int) Math.round(cropWidth * widthRatio);
108        }
109        if (yCenter == nty - 1) {
110            cropHeight = input.getHeight() - (yCenter) * cropHeight;
111            tileHeight = (int) Math.round(cropHeight * heightRatio);
112        }
113
114        int[] result = { startX, startY, cropWidth, cropHeight, ntx, nty, tileWidth, tileHeight };
115
116        return result;
117    }
118
119    public PictureTiles getTilesFromFile(ImageInfo input, String outputDirPath, int tileWidth, int tileHeight,
120            int maxTiles, int xCenter, int yCenter, long lastModificationTime, boolean fullGeneration)
121            {
122
123        int[] cropCoords = computeCropCoords(input, maxTiles, tileWidth, tileHeight, xCenter, yCenter);
124
125        String fileName = StringMaker.getTileFileName(xCenter, yCenter, lastModificationTime);
126        String outputFilePath = new Path(outputDirPath).append(fileName).toString();
127
128        try {
129            String mapComponents = null;
130            if (CMYK_MAP_COMPONENTS.equalsIgnoreCase(input.getColorSpace())) {
131                mapComponents = CMYK_MAP_COMPONENTS;
132            }
133
134            ImageCropperAndResizer.cropAndResize(input.getFilePath(), outputFilePath, cropCoords[2], cropCoords[3],
135                    cropCoords[0], cropCoords[1], cropCoords[6], cropCoords[7], mapComponents);
136        } catch (CommandNotAvailable | CommandException e) {
137            throw new NuxeoException(e);
138        }
139
140        Map<String, String> infoMap = new HashMap<String, String>();
141        infoMap.put(PictureTilesImpl.TILE_OUTPUT_DIR_KEY, outputDirPath);
142        infoMap.put(PictureTilesImpl.X_TILES_KEY, Integer.toString(cropCoords[4]));
143        infoMap.put(PictureTilesImpl.Y_TILES_KEY, Integer.toString(cropCoords[5]));
144
145        return new PictureTilesImpl(infoMap);
146    }
147
148}