You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ofbiz.apache.org by Adam Heath <do...@brainfood.com> on 2009/03/02 16:46:53 UTC

Re: svn commit: r739042 - in /ofbiz/trunk/applications/product: config/ data/ entitydef/ src/org/ofbiz/image/ src/org/ofbiz/product/product/ webapp/catalog/WEB-INF/actions/product/ webapp/catalog/product/

jleroux@apache.org wrote:

> Added: ofbiz/trunk/applications/product/src/org/ofbiz/image/ImageTransform.java
> URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/src/org/ofbiz/image/ImageTransform.java?rev=739042&view=auto
> ==============================================================================
> --- ofbiz/trunk/applications/product/src/org/ofbiz/image/ImageTransform.java (added)
> +++ ofbiz/trunk/applications/product/src/org/ofbiz/image/ImageTransform.java Thu Jan 29 22:06:32 2009

I don't think this file should be in product.  It's too generic.


> @@ -0,0 +1,451 @@
> +/*******************************************************************************
> + * Licensed to the Apache Software Foundation (ASF) under one
> + * or more contributor license agreements.  See the NOTICE file
> + * distributed with this work for additional information
> + * regarding copyright ownership.  The ASF licenses this file
> + * to you 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.
> + *******************************************************************************/
> +package org.ofbiz.image;
> +
> +import java.awt.geom.AffineTransform;
> +import java.awt.image.AffineTransformOp;
> +import java.awt.image.BufferedImage;
> +import java.awt.image.ImagingOpException;
> +import java.awt.RenderingHints;
> +import java.awt.RenderingHints.Key;
> +import java.io.File;
> +import java.io.IOException;
> +import java.lang.IllegalArgumentException;
> +import java.lang.Double;
> +import java.lang.Object;
> +import java.lang.String;
> +import java.lang.System;
> +import java.util.Iterator;
> +import java.util.LinkedHashMap;
> +import java.util.List;
> +import java.util.Map;
> +
> +import javax.imageio.ImageIO;
> +
> +import javolution.util.FastList;
> +import javolution.util.FastMap;
> +
> +import org.jdom.Document;
> +import org.jdom.Element;
> +import org.jdom.input.SAXBuilder;
> +import org.jdom.filter.Filter;
> +import org.jdom.JDOMException;

Please do not use jdom, there's no need to.  UtilXml does everything that
you need in this file(which is just parsing xml from java.io.File).  The
looping over the elements is standard dom.

> +
> +import org.ofbiz.base.util.Debug;
> +import org.ofbiz.base.util.string.FlexibleStringExpander;
> +import org.ofbiz.base.util.UtilMisc;
> +import org.ofbiz.base.util.UtilProperties;
> +import org.ofbiz.service.ServiceUtil;
> +
> +
> +/**
> + * ImageTransform Class
> + * <p>
> + * Services to apply tranformation for images
> + */
> +public class ImageTransform {
> +
> +    public static final String module = ImageTransform.class.getName();
> +//    public static final String err_resource = "ContentErrorUiLabels";
> +
> +    public ImageTransform() {}
> +    
> +
> +    /**
> +     * getBufferedImage
> +     * <p>
> +     * Set a buffered image
> +     *
> +     * @param   context
> +     * @param   fileLocation    Full file Path or Url
> +     * @return                  Url images for all different size types
> +     * @throws  IOException Error prevents the document from being fully parsed
> +     * @throws  JDOMException Errors occur in parsing
> +     */
> +    public Map getBufferedImage(String fileLocation)
> +        throws IllegalArgumentException, IOException {
> +        
> +        /* VARIABLES */
> +        BufferedImage bufImg;
> +        FastMap result = new FastMap();
> +        
> +        /* BUFFERED IMAGE */
> +        try{
> +            bufImg = ImageIO.read(new File(fileLocation));
> +        }catch(IllegalArgumentException e){
> +            String errMsg = "Input is null : " + fileLocation + " ; " + e.toString();
> +            Debug.logError(errMsg, module);
> +            result.put("errorMessage", errMsg);
> +            return result;
> +        }catch(IOException e){
> +            String errMsg = "Error occurs during reading : " + fileLocation + " ; " + e.toString();
> +            Debug.logError(errMsg, module);
> +            result.put("errorMessage", errMsg);
> +            return result;
> +        }
> +
> +        result.put("responseMessage", "success");
> +        result.put("bufferedImage", bufImg); 
> +        return result;        
> +    
> +    } // getBufferedImage
> +    
> +    
> +    /**
> +     * scaleImageInAllSize
> +     * <p>
> +     * Scale the original image into all different size Types (small, medium, large, detail)
> +     *
> +     * @param   context                     Context
> +     * @param   filenameToUse               Filename of future image files
> +     * @param   viewType                    "Main" view or "additional" view
> +     * @param   viewNumber                  If it's the main view, viewNumber = "0"
> +     * @return                              Url images for all different size types
> +     * @throws  IllegalArgumentException    Any parameter is null
> +     * @throws  ImagingOpException          The transform is non-invertible
> +     * @throws  IOException                 Error prevents the document from being fully parsed
> +     * @throws  JDOMException               Errors occur in parsing
> +     */
> +    public Map scaleImageInAllSize(Map<String, ? extends Object> context, String filenameToUse, String viewType, String viewNumber)
> +        throws IllegalArgumentException, ImagingOpException, IOException, JDOMException {
> +    
> +        /* VARIABLES */
> +        List<String> sizeTypeList = UtilMisc.toList("small", "medium", "large", "detail");
> +        List<String> extensionList = UtilMisc.toList("jpeg", "jpg", "png");
> +        int index;
> +        LinkedHashMap<String, LinkedHashMap<String, String>> imgPropertyMap = new LinkedHashMap<String, LinkedHashMap<String, String>>();
> +        BufferedImage bufImg, bufNewImg;
> +        double imgHeight, imgWidth, defaultHeight, defaultWidth, scaleFactor;
> +        AffineTransformOp op;
> +        LinkedHashMap<String, String> imgUrlMap = new LinkedHashMap<String, String>(); 
> +        LinkedHashMap resultXMLMap = new LinkedHashMap(); 
> +        LinkedHashMap resultBufImgMap = new LinkedHashMap();
> +        LinkedHashMap resultScaleImgMap = new LinkedHashMap();
> +        FastMap result = new FastMap();
> +           
> +        /* ImageProperties.xml */
> +        String imgPropertyFullPath = System.getProperty("ofbiz.home") + "/applications/product/config/ImageProperties.xml";
> +        resultXMLMap.putAll(getXMLValue(imgPropertyFullPath));
> +        if(resultXMLMap.containsKey("responseMessage") && resultXMLMap.get("responseMessage").equals("success")){
> +            imgPropertyMap.putAll((LinkedHashMap) resultXMLMap.get("xml"));
> +        }else{
> +            String errMsg = "Impossible to parse ImageProperties.xml ";
> +            Debug.logError(errMsg, module);
> +            result.put("errorMessage", errMsg);
> +            return result;
> +        }
> +        
> +        /* IMAGE */
> +        // get Name and Extension
> +        index = filenameToUse.lastIndexOf(".");
> +        String imgName = filenameToUse.substring(0, index - 1);
> +        String imgExtension = filenameToUse.substring(index + 1);
> +        // paths
> +        String mainFilenameFormat = UtilProperties.getPropertyValue("catalog", "image.filename.format");
> +        String imageServerPath = FlexibleStringExpander.expandString(UtilProperties.getPropertyValue("catalog", "image.server.path"), context);
> +        String imageUrlPrefix = UtilProperties.getPropertyValue("catalog", "image.url.prefix");
> +        
> +        String id = new String();
> +        String type = new String();
> +        if(viewType.toLowerCase().contains("main")){
> +            type = "original";
> +            id = imgName;
> +        }else if(viewType.toLowerCase().contains("additional") && viewNumber != null && !viewNumber.equals("0")){
> +            type = "additional";
> +            id = imgName + "_View_" + viewNumber;
> +        }else{
> +            return ServiceUtil.returnError("View Type : " + type + " is wrong");
> +        }
> +        FlexibleStringExpander mainFilenameExpander = FlexibleStringExpander.getInstance(mainFilenameFormat);
> +        String fileLocation = mainFilenameExpander.expandString(UtilMisc.toMap("location", "products", "type", type, "id", filenameToUse));
> +        String filePathPrefix = "";
> +        if (fileLocation.lastIndexOf("/") != -1) {
> +            filePathPrefix = fileLocation.substring(0, fileLocation.lastIndexOf("/") + 1); // adding 1 to include the trailing slash
> +        }
> +        
> +        
> +      
> +        /* get original BUFFERED IMAGE */
> +        resultBufImgMap.putAll(this.getBufferedImage(imageServerPath + "/" + filePathPrefix + filenameToUse));
> +        
> +        if(resultBufImgMap.containsKey("responseMessage") && resultBufImgMap.get("responseMessage").equals("success")){
> +            bufImg = (BufferedImage) resultBufImgMap.get("bufferedImage");
> +            
> +            // get Dimensions    
> +            imgHeight = (double) bufImg.getHeight();
> +            imgWidth = (double) bufImg.getWidth();
> +            if(imgHeight == 0.0 || imgWidth == 0.0){
> +                String errMsg = "Any current image dimension is null : imgHeight = " + imgHeight + " ; imgWidth = " + imgWidth + ";";
> +                Debug.logError(errMsg, module);
> +                result.put("errorMessage", errMsg);
> +                return result;
> +            }
> +            
> +            // new Filename Format
> +            FlexibleStringExpander addFilenameExpander = mainFilenameExpander;
> +            if(viewType.toLowerCase().contains("additional")){
> +                String addFilenameFormat = UtilProperties.getPropertyValue("catalog", "image.filename.additionalviewsize.format");
> +                addFilenameExpander = FlexibleStringExpander.getInstance(addFilenameFormat);
> +            }
> +        
> +            /* scale Image for each Size Type */
> +            Iterator<String> sizeIter = sizeTypeList.iterator();
> +            while(sizeIter.hasNext()){
> +                String sizeType = sizeIter.next();
> +        
> +                resultScaleImgMap.putAll(this.scaleImage(bufImg, imgHeight, imgWidth, imgPropertyMap, sizeType));
> +                 
> +                if(resultScaleImgMap.containsKey("responseMessage") && resultScaleImgMap.get("responseMessage").equals("success")){
> +                    bufNewImg = (BufferedImage) resultScaleImgMap.get("bufferedImage"); 
> +                    Double scaleFactorDb = (Double) resultScaleImgMap.get("scaleFactor"); 
> +                    scaleFactor = scaleFactorDb.doubleValue();
> +        
> +                    // define Interpolation
> +                    LinkedHashMap<RenderingHints.Key, Object> rhMap = new LinkedHashMap<RenderingHints.Key, Object>();
> +                        rhMap.put(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
> +                        rhMap.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
> +                        rhMap.put(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
> +                        rhMap.put(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DISABLE);
> +                        rhMap.put(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
> +                        rhMap.put(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
> +                        rhMap.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
> +                        //rhMap.put(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
> +                        rhMap.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
> +                    RenderingHints rh = new RenderingHints(rhMap);
> +                    
> +                    /* IMAGE TRANFORMATION */ 
> +                    AffineTransform tx = new AffineTransform();
> +                    tx.scale(scaleFactor, scaleFactor);
> +                    
> +                    
> +                    try{
> +                        op = new AffineTransformOp(tx, rh);
> +                    }catch(ImagingOpException e){
> +                        String errMsg = "The transform is non-invertible" + e.toString();
> +                        Debug.logError(errMsg, module);
> +                        result.put("errorMessage", errMsg);
> +                        return result;
> +                    }
> +        
> +                    // write the New Scaled Image
> +                    String newFileLocation = new String();
> +                    if(viewType.toLowerCase().contains("main")){
> +                        newFileLocation = mainFilenameExpander.expandString(UtilMisc.toMap("location", "products", "type", sizeType, "id", id));
> +                    }else if(viewType.toLowerCase().contains("additional")){
> +                        newFileLocation = addFilenameExpander.expandString(UtilMisc.toMap("location", "products", "viewtype", viewType, "sizetype", sizeType,"id", id));
> +                    }
> +                    String newFilePathPrefix = "";
> +                    if (newFileLocation.lastIndexOf("/") != -1) {
> +                        newFilePathPrefix = newFileLocation.substring(0, newFileLocation.lastIndexOf("/") + 1); // adding 1 to include the trailing slash
> +                    }
> +                    
> +                    // choose final extension
> +                    String finalExtension = new String();
> +                    if(!extensionList.contains(imgExtension.toLowerCase())){
> +                        finalExtension = imgPropertyMap.get("format").get("extension");
> +                    }else{
> +                        finalExtension = imgExtension;
> +                    }
> +
> +                    String targetDirectory = imageServerPath + "/" + newFilePathPrefix;
> +                    File targetDir = new File(targetDirectory);
> +                    if (!targetDir.exists()) {
> +                        boolean created = targetDir.mkdirs();
> +                        if (!created) {
> +                            Debug.logFatal("Unable to create target directory - " + targetDirectory, module);
> +                            return ServiceUtil.returnError("Unable to create target directory - " + targetDirectory);
> +                        }
> +                    }
> +
> +                    // write new image
> +                    try{
> +                        ImageIO.write(op.filter(bufImg, bufNewImg), imgExtension, new File(imageServerPath + "/" + newFilePathPrefix + filenameToUse));
> +                    }catch(IllegalArgumentException e){
> +                        String errMsg = "Any parameter is null" + e.toString();
> +                        Debug.logError(errMsg, module);
> +                        result.put("errorMessage", errMsg);
> +                        return result;
> +                    }catch(IOException e){
> +                        String errMsg = "An error occurs during writing" + e.toString();
> +                        Debug.logError(errMsg, module);
> +                        result.put("errorMessage", errMsg);
> +                        return result;
> +                    }
> +            
> +                    /* write Return Result */
> +                    String imageUrl = imageUrlPrefix + "/" + newFilePathPrefix + filenameToUse;
> +                    imgUrlMap.put(sizeType, imageUrl);
> +        
> +                } // scaleImgMap
> +            } // sizeIter 
> +        }
> +        
> +        result.put("responseMessage", "success");
> +        result.put("imageUrlMap", imgUrlMap);
> +        result.put("original", resultBufImgMap);
> +        return result;    
> +        
> +    } // scaleImageInAllSize 
> +
> +    
> +    /**
> +     * scaleImage
> +     * <p>
> +     * scale original image related to the ImageProperties.xml dimensions
> +     *
> +     * @param   bufImg          Buffered image to scale
> +     * @param   imgHeight       Original image height
> +     * @param   imgwidth        Original image width
> +     * @param   dimensionMap    Image dimensions by size type
> +     * @param   sizeType        Size type to scale
> +     * @return                  New scaled buffered image 
> +     */
> +    private Map scaleImage(BufferedImage bufImg, double imgHeight, double imgWidth, LinkedHashMap<String, LinkedHashMap<String, String>> dimensionMap, String sizeType){
> +    
> +        /* VARIABLES */
> +        BufferedImage bufNewImg;
> +        double defaultHeight, defaultWidth, scaleFactor;
> +        FastMap result = new FastMap();
> +       
> +        /* DIMENSIONS from ImageProperties */     
> +        defaultHeight = Double.parseDouble(dimensionMap.get(sizeType).get("height").toString());
> +        defaultWidth = Double.parseDouble(dimensionMap.get(sizeType).get("width").toString());
> +        if(defaultHeight == 0.0 || defaultWidth == 0.0){
> +            String errMsg = "Any default dimension is null : defaultHeight = " + defaultHeight + " ; defaultWidth = " + defaultWidth + ";";
> +            Debug.logError(errMsg, module);
> +            result.put("errorMessage", errMsg);
> +            return result;
> +        }
> +        
> +        /* SCALE FACTOR */
> +        // find the right Scale Factor related to the Image Dimensions
> +        if(imgHeight > imgWidth){
> +            scaleFactor = defaultHeight / imgHeight;
> +            if(scaleFactor == 0.0){
> +                String errMsg = "Height scaleFactor is null (defaultHeight = " + defaultHeight + "; imgHeight = " + imgHeight + ";";
> +                Debug.logError(errMsg, module);
> +                result.put("errorMessage", errMsg);
> +                return result;
> +            }
> +            // get scaleFactor from the smallest width
> +            if(defaultWidth < (imgWidth * scaleFactor)){
> +                scaleFactor = defaultWidth / imgWidth;    
> +            }
> +        }else{
> +            scaleFactor = defaultWidth / imgWidth;
> +            if(scaleFactor == 0.0){
> +                String errMsg = "Width scaleFactor is null (defaultWidth = " + defaultWidth + "; imgWidth = " + imgWidth + ";";
> +                Debug.logError(errMsg, module);
> +                result.put("errorMessage", errMsg);
> +                return result;
> +            }
> +            // get scaleFactor from the smallest height
> +            if(defaultHeight < (imgHeight * scaleFactor)){
> +                scaleFactor = defaultHeight / imgHeight;    
> +            }   
> +        }
> +            
> +        if(scaleFactor == 0.0){
> +            String errMsg = "Final scaleFactor is null = " + scaleFactor + ";";
> +            Debug.logError(errMsg, module);
> +            result.put("errorMessage", errMsg);
> +            return result;
> +        }
> +        
> +        bufNewImg = new BufferedImage( (int) (imgWidth * scaleFactor), (int) (imgHeight * scaleFactor), bufImg.getType());
> + 
> +        result.put("responseMessage", "success");
> +        result.put("bufferedImage", bufNewImg);
> +        result.put("scaleFactor", scaleFactor);
> +        return result;
> +
> +    } // scaleImage
> +    
> +    
> +    /**
> +     * getXMLValue
> +     * <p>
> +     * From a XML element, get a values map
> +     *
> +     * @param fileFullPath      File path to parse
> +     * @return Map contains asked attribute values by attribute name
> +     */
> +    private Map getXMLValue(String fileFullPath)
> +        throws IllegalStateException, IOException, JDOMException {
> +
> +        /* VARIABLES */
> +        Document document;
> +        Element rootElt;
> +        List<Element> eltList;
> +        LinkedHashMap<String, LinkedHashMap> valueMap = new LinkedHashMap<String, LinkedHashMap>();
> +        FastMap result = new FastMap();
> +        
> +        /* PARSING */
> +        SAXBuilder sxb = new SAXBuilder();
> +        try{
> +            // JDOM
> +            document = sxb.build(new File(fileFullPath));
> +        }catch(JDOMException e){
> +            String errMsg = "Errors occur in parsing ImageProperties.xml" + e.toString();
> +            Debug.logError(errMsg, module);
> +            result.put("errorMessage", "error");
> +            return result;
> +        }catch(IOException e){
> +            String errMsg = "Error prevents the document from being fully parsed" + e.toString();
> +            Debug.logError(errMsg, module);
> +            result.put("errorMessage", "error");
> +            return result;
> +        }
> +        // set Root Element
> +        try{
> +            rootElt = document.getRootElement();
> +        }catch(IllegalStateException e){
> +            String errMsg = "Root element hasn't been set" + e.toString();
> +            Debug.logError(errMsg, module);
> +            result.put("errorMessage", "error");
> +            return result;
> +        } 
> +           
> +        /* get NAME and VALUE */
> +        Iterator<Element> eltIter = rootElt.getChildren().iterator();
> +        while(eltIter.hasNext()){
> +            Element currentElt = eltIter.next();              
> +            LinkedHashMap<String, String> eltMap = new LinkedHashMap<String, String>();
> +            if(currentElt.getContentSize() > 0){
> +                LinkedHashMap<String, String> childMap = new LinkedHashMap<String, String>();
> +                // loop over Children 1st level
> +                Iterator<Element> childrenIter = currentElt.getChildren().iterator();
> +                while(childrenIter.hasNext()){
> +                    Element currentChild = childrenIter.next(); 
> +                    childMap.put(currentChild.getAttributeValue("name"), currentChild.getAttributeValue("value"));  
> +                }    
> +                valueMap.put(currentElt.getAttributeValue("name"), childMap);
> +            }else{
> +                eltMap.put(currentElt.getAttributeValue("name"), currentElt.getAttributeValue("value"));
> +                valueMap.put(currentElt.getName(), eltMap);   
> +            }
> +        } // eltIter  
> +        
> +        result.put("responseMessage", "success");
> +        result.put("xml", valueMap);
> +        return result; 
> +        
> +    } // getXMLValue
> +    
> +} // ImageTransform Class
> 


Re: svn commit: r739042 - in /ofbiz/trunk/applications/product: config/ data/ entitydef/ src/org/ofbiz/image/ src/org/ofbiz/product/product/ webapp/catalog/WEB-INF/actions/product/ webapp/catalog/product/

Posted by Jacques Le Roux <ja...@les7arts.com>.
Done at revision: 750018  

I did not used UtilXml  or JAXP directly yet, will hopefully do it later...
If you think more should be done please proceed...

Jacques

From: "Jacques Le Roux" <ja...@les7arts.com>
>I had a closer look, I think we should keep scaleImageInAllSize() in product component as it's specific to it (I will rename the 
> package org.ofbiz.product.image.ImageTransform)
> Hence some errors labels should be kept in ProductErrorUiLabels.xml and some other put in a new CommonErrorUiLabels.xml file
> Also, I will try to use UtilXml methods as much as possible...
> 
> Anything else ?
> 
> Jacques
> 
> From: "Adam Heath" <do...@brainfood.com>
>> Jacques Le Roux wrote:
>>> We cross 2 issues if we want to move ImageTransform to common
>>> 1) ImageTransform. depends on jdom which is in webapp/lib => should we
>>> move it to common/lib also (makes sense IMO)
>>
>> It doesn't really depend on jdom.  Look at the source, it's doing nothing
>> special with jdom at all.  Switch this to standard java xml classes, and
>> this problem goes away.
>>
>>> 2) I think we shoul aldo move all the keys '<property
>>> key="ImageTransform." from ProductErrorUiLabels.xml  to
>>> CommonUiLabels.xml (or should we rather create a CommonErrorUiLabels.xml
>>> file ?)
>>
>> Er, no, don't like this.  Common* is too big, split it up.
>> 
> 
>


Re: svn commit: r739042 - in /ofbiz/trunk/applications/product: config/ data/ entitydef/ src/org/ofbiz/image/ src/org/ofbiz/product/product/ webapp/catalog/WEB-INF/actions/product/ webapp/catalog/product/

Posted by Jacques Le Roux <ja...@les7arts.com>.
I had a closer look, I think we should keep scaleImageInAllSize() in product component as it's specific to it (I will rename the 
package org.ofbiz.product.image.ImageTransform)
Hence some errors labels should be kept in ProductErrorUiLabels.xml and some other put in a new CommonErrorUiLabels.xml file
Also, I will try to use UtilXml methods as much as possible...

Anything else ?

Jacques

From: "Adam Heath" <do...@brainfood.com>
> Jacques Le Roux wrote:
>> We cross 2 issues if we want to move ImageTransform to common
>> 1) ImageTransform. depends on jdom which is in webapp/lib => should we
>> move it to common/lib also (makes sense IMO)
>
> It doesn't really depend on jdom.  Look at the source, it's doing nothing
> special with jdom at all.  Switch this to standard java xml classes, and
> this problem goes away.
>
>> 2) I think we shoul aldo move all the keys '<property
>> key="ImageTransform." from ProductErrorUiLabels.xml  to
>> CommonUiLabels.xml (or should we rather create a CommonErrorUiLabels.xml
>> file ?)
>
> Er, no, don't like this.  Common* is too big, split it up.
> 



Re: svn commit: r739042 - in /ofbiz/trunk/applications/product: config/ data/ entitydef/ src/org/ofbiz/image/ src/org/ofbiz/product/product/ webapp/catalog/WEB-INF/actions/product/ webapp/catalog/product/

Posted by Adam Heath <do...@brainfood.com>.
Jacques Le Roux wrote:
> We cross 2 issues if we want to move ImageTransform to common
> 1) ImageTransform. depends on jdom which is in webapp/lib => should we
> move it to common/lib also (makes sense IMO)

It doesn't really depend on jdom.  Look at the source, it's doing nothing
special with jdom at all.  Switch this to standard java xml classes, and
this problem goes away.

> 2) I think we shoul aldo move all the keys '<property
> key="ImageTransform." from ProductErrorUiLabels.xml  to
> CommonUiLabels.xml (or should we rather create a CommonErrorUiLabels.xml
> file ?)

Er, no, don't like this.  Common* is too big, split it up.

Re: svn commit: r739042 - in /ofbiz/trunk/applications/product: config/ data/ entitydef/ src/org/ofbiz/image/ src/org/ofbiz/product/product/ webapp/catalog/WEB-INF/actions/product/ webapp/catalog/product/

Posted by Jacques Le Roux <ja...@les7arts.com>.
We cross 2 issues if we want to move ImageTransform to common
1) ImageTransform. depends on jdom which is in webapp/lib => should we move it to common/lib also (makes sense IMO)
2) I think we shoul aldo move all the keys '<property key="ImageTransform." from ProductErrorUiLabels.xml  to CommonUiLabels.xml (or 
should we rather create a CommonErrorUiLabels.xml file ?)

What do you think ?

Jacques

From: "Jacques Le Roux" <ja...@les7arts.com>
> Yes, I thought about that too. Where do you think we should put it ? framework/images is mostly for static content, rather common 
> I guess ?
> BTW, I have refactored the code below since...
>
> Jacques
>
> From: "Adam Heath" <do...@brainfood.com>
>> jleroux@apache.org wrote:
>>
>>> Added: ofbiz/trunk/applications/product/src/org/ofbiz/image/ImageTransform.java
>>> URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/src/org/ofbiz/image/ImageTransform.java?rev=739042&view=auto
>>> ==============================================================================
>>> --- ofbiz/trunk/applications/product/src/org/ofbiz/image/ImageTransform.java (added)
>>> +++ ofbiz/trunk/applications/product/src/org/ofbiz/image/ImageTransform.java Thu Jan 29 22:06:32 2009
>>
>> I don't think this file should be in product.  It's too generic.
>>
>>
>>> @@ -0,0 +1,451 @@
>>> +/*******************************************************************************
>>> + * Licensed to the Apache Software Foundation (ASF) under one
>>> + * or more contributor license agreements.  See the NOTICE file
>>> + * distributed with this work for additional information
>>> + * regarding copyright ownership.  The ASF licenses this file
>>> + * to you 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.
>>> + *******************************************************************************/
>>> +package org.ofbiz.image;
>>> +
>>> +import java.awt.geom.AffineTransform;
>>> +import java.awt.image.AffineTransformOp;
>>> +import java.awt.image.BufferedImage;
>>> +import java.awt.image.ImagingOpException;
>>> +import java.awt.RenderingHints;
>>> +import java.awt.RenderingHints.Key;
>>> +import java.io.File;
>>> +import java.io.IOException;
>>> +import java.lang.IllegalArgumentException;
>>> +import java.lang.Double;
>>> +import java.lang.Object;
>>> +import java.lang.String;
>>> +import java.lang.System;
>>> +import java.util.Iterator;
>>> +import java.util.LinkedHashMap;
>>> +import java.util.List;
>>> +import java.util.Map;
>>> +
>>> +import javax.imageio.ImageIO;
>>> +
>>> +import javolution.util.FastList;
>>> +import javolution.util.FastMap;
>>> +
>>> +import org.jdom.Document;
>>> +import org.jdom.Element;
>>> +import org.jdom.input.SAXBuilder;
>>> +import org.jdom.filter.Filter;
>>> +import org.jdom.JDOMException;
>>
>> Please do not use jdom, there's no need to.  UtilXml does everything that
>> you need in this file(which is just parsing xml from java.io.File).  The
>> looping over the elements is standard dom.
>>
>>> +
>>> +import org.ofbiz.base.util.Debug;
>>> +import org.ofbiz.base.util.string.FlexibleStringExpander;
>>> +import org.ofbiz.base.util.UtilMisc;
>>> +import org.ofbiz.base.util.UtilProperties;
>>> +import org.ofbiz.service.ServiceUtil;
>>> +
>>> +
>>> +/**
>>> + * ImageTransform Class
>>> + * <p>
>>> + * Services to apply tranformation for images
>>> + */
>>> +public class ImageTransform {
>>> +
>>> +    public static final String module = ImageTransform.class.getName();
>>> +//    public static final String err_resource = "ContentErrorUiLabels";
>>> +
>>> +    public ImageTransform() {}
>>> +
>>> +
>>> +    /**
>>> +     * getBufferedImage
>>> +     * <p>
>>> +     * Set a buffered image
>>> +     *
>>> +     * @param   context
>>> +     * @param   fileLocation    Full file Path or Url
>>> +     * @return                  Url images for all different size types
>>> +     * @throws  IOException Error prevents the document from being fully parsed
>>> +     * @throws  JDOMException Errors occur in parsing
>>> +     */
>>> +    public Map getBufferedImage(String fileLocation)
>>> +        throws IllegalArgumentException, IOException {
>>> +
>>> +        /* VARIABLES */
>>> +        BufferedImage bufImg;
>>> +        FastMap result = new FastMap();
>>> +
>>> +        /* BUFFERED IMAGE */
>>> +        try{
>>> +            bufImg = ImageIO.read(new File(fileLocation));
>>> +        }catch(IllegalArgumentException e){
>>> +            String errMsg = "Input is null : " + fileLocation + " ; " + e.toString();
>>> +            Debug.logError(errMsg, module);
>>> +            result.put("errorMessage", errMsg);
>>> +            return result;
>>> +        }catch(IOException e){
>>> +            String errMsg = "Error occurs during reading : " + fileLocation + " ; " + e.toString();
>>> +            Debug.logError(errMsg, module);
>>> +            result.put("errorMessage", errMsg);
>>> +            return result;
>>> +        }
>>> +
>>> +        result.put("responseMessage", "success");
>>> +        result.put("bufferedImage", bufImg);
>>> +        return result;
>>> +
>>> +    } // getBufferedImage
>>> +
>>> +
>>> +    /**
>>> +     * scaleImageInAllSize
>>> +     * <p>
>>> +     * Scale the original image into all different size Types (small, medium, large, detail)
>>> +     *
>>> +     * @param   context                     Context
>>> +     * @param   filenameToUse               Filename of future image files
>>> +     * @param   viewType                    "Main" view or "additional" view
>>> +     * @param   viewNumber                  If it's the main view, viewNumber = "0"
>>> +     * @return                              Url images for all different size types
>>> +     * @throws  IllegalArgumentException    Any parameter is null
>>> +     * @throws  ImagingOpException          The transform is non-invertible
>>> +     * @throws  IOException                 Error prevents the document from being fully parsed
>>> +     * @throws  JDOMException               Errors occur in parsing
>>> +     */
>>> +    public Map scaleImageInAllSize(Map<String, ? extends Object> context, String filenameToUse, String viewType, String 
>>> viewNumber)
>>> +        throws IllegalArgumentException, ImagingOpException, IOException, JDOMException {
>>> +
>>> +        /* VARIABLES */
>>> +        List<String> sizeTypeList = UtilMisc.toList("small", "medium", "large", "detail");
>>> +        List<String> extensionList = UtilMisc.toList("jpeg", "jpg", "png");
>>> +        int index;
>>> +        LinkedHashMap<String, LinkedHashMap<String, String>> imgPropertyMap = new LinkedHashMap<String, LinkedHashMap<String, 
>>> String>>();
>>> +        BufferedImage bufImg, bufNewImg;
>>> +        double imgHeight, imgWidth, defaultHeight, defaultWidth, scaleFactor;
>>> +        AffineTransformOp op;
>>> +        LinkedHashMap<String, String> imgUrlMap = new LinkedHashMap<String, String>();
>>> +        LinkedHashMap resultXMLMap = new LinkedHashMap();
>>> +        LinkedHashMap resultBufImgMap = new LinkedHashMap();
>>> +        LinkedHashMap resultScaleImgMap = new LinkedHashMap();
>>> +        FastMap result = new FastMap();
>>> +
>>> +        /* ImageProperties.xml */
>>> +        String imgPropertyFullPath = System.getProperty("ofbiz.home") + "/applications/product/config/ImageProperties.xml";
>>> +        resultXMLMap.putAll(getXMLValue(imgPropertyFullPath));
>>> +        if(resultXMLMap.containsKey("responseMessage") && resultXMLMap.get("responseMessage").equals("success")){
>>> +            imgPropertyMap.putAll((LinkedHashMap) resultXMLMap.get("xml"));
>>> +        }else{
>>> +            String errMsg = "Impossible to parse ImageProperties.xml ";
>>> +            Debug.logError(errMsg, module);
>>> +            result.put("errorMessage", errMsg);
>>> +            return result;
>>> +        }
>>> +
>>> +        /* IMAGE */
>>> +        // get Name and Extension
>>> +        index = filenameToUse.lastIndexOf(".");
>>> +        String imgName = filenameToUse.substring(0, index - 1);
>>> +        String imgExtension = filenameToUse.substring(index + 1);
>>> +        // paths
>>> +        String mainFilenameFormat = UtilProperties.getPropertyValue("catalog", "image.filename.format");
>>> +        String imageServerPath = FlexibleStringExpander.expandString(UtilProperties.getPropertyValue("catalog", 
>>> "image.server.path"), context);
>>> +        String imageUrlPrefix = UtilProperties.getPropertyValue("catalog", "image.url.prefix");
>>> +
>>> +        String id = new String();
>>> +        String type = new String();
>>> +        if(viewType.toLowerCase().contains("main")){
>>> +            type = "original";
>>> +            id = imgName;
>>> +        }else if(viewType.toLowerCase().contains("additional") && viewNumber != null && !viewNumber.equals("0")){
>>> +            type = "additional";
>>> +            id = imgName + "_View_" + viewNumber;
>>> +        }else{
>>> +            return ServiceUtil.returnError("View Type : " + type + " is wrong");
>>> +        }
>>> +        FlexibleStringExpander mainFilenameExpander = FlexibleStringExpander.getInstance(mainFilenameFormat);
>>> +        String fileLocation = mainFilenameExpander.expandString(UtilMisc.toMap("location", "products", "type", type, "id", 
>>> filenameToUse));
>>> +        String filePathPrefix = "";
>>> +        if (fileLocation.lastIndexOf("/") != -1) {
>>> +            filePathPrefix = fileLocation.substring(0, fileLocation.lastIndexOf("/") + 1); // adding 1 to include the trailing 
>>> slash
>>> +        }
>>> +
>>> +
>>> +
>>> +        /* get original BUFFERED IMAGE */
>>> +        resultBufImgMap.putAll(this.getBufferedImage(imageServerPath + "/" + filePathPrefix + filenameToUse));
>>> +
>>> +        if(resultBufImgMap.containsKey("responseMessage") && resultBufImgMap.get("responseMessage").equals("success")){
>>> +            bufImg = (BufferedImage) resultBufImgMap.get("bufferedImage");
>>> +
>>> +            // get Dimensions
>>> +            imgHeight = (double) bufImg.getHeight();
>>> +            imgWidth = (double) bufImg.getWidth();
>>> +            if(imgHeight == 0.0 || imgWidth == 0.0){
>>> +                String errMsg = "Any current image dimension is null : imgHeight = " + imgHeight + " ; imgWidth = " + imgWidth 
>>> + ";";
>>> +                Debug.logError(errMsg, module);
>>> +                result.put("errorMessage", errMsg);
>>> +                return result;
>>> +            }
>>> +
>>> +            // new Filename Format
>>> +            FlexibleStringExpander addFilenameExpander = mainFilenameExpander;
>>> +            if(viewType.toLowerCase().contains("additional")){
>>> +                String addFilenameFormat = UtilProperties.getPropertyValue("catalog", 
>>> "image.filename.additionalviewsize.format");
>>> +                addFilenameExpander = FlexibleStringExpander.getInstance(addFilenameFormat);
>>> +            }
>>> +
>>> +            /* scale Image for each Size Type */
>>> +            Iterator<String> sizeIter = sizeTypeList.iterator();
>>> +            while(sizeIter.hasNext()){
>>> +                String sizeType = sizeIter.next();
>>> +
>>> +                resultScaleImgMap.putAll(this.scaleImage(bufImg, imgHeight, imgWidth, imgPropertyMap, sizeType));
>>> +
>>> +                if(resultScaleImgMap.containsKey("responseMessage") && 
>>> resultScaleImgMap.get("responseMessage").equals("success")){
>>> +                    bufNewImg = (BufferedImage) resultScaleImgMap.get("bufferedImage");
>>> +                    Double scaleFactorDb = (Double) resultScaleImgMap.get("scaleFactor");
>>> +                    scaleFactor = scaleFactorDb.doubleValue();
>>> +
>>> +                    // define Interpolation
>>> +                    LinkedHashMap<RenderingHints.Key, Object> rhMap = new LinkedHashMap<RenderingHints.Key, Object>();
>>> +                        rhMap.put(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
>>> +                        rhMap.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
>>> +                        rhMap.put(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
>>> +                        rhMap.put(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DISABLE);
>>> +                        rhMap.put(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
>>> +                        rhMap.put(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
>>> +                        rhMap.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
>>> +                        //rhMap.put(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
>>> +                        rhMap.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
>>> +                    RenderingHints rh = new RenderingHints(rhMap);
>>> +
>>> +                    /* IMAGE TRANFORMATION */
>>> +                    AffineTransform tx = new AffineTransform();
>>> +                    tx.scale(scaleFactor, scaleFactor);
>>> +
>>> +
>>> +                    try{
>>> +                        op = new AffineTransformOp(tx, rh);
>>> +                    }catch(ImagingOpException e){
>>> +                        String errMsg = "The transform is non-invertible" + e.toString();
>>> +                        Debug.logError(errMsg, module);
>>> +                        result.put("errorMessage", errMsg);
>>> +                        return result;
>>> +                    }
>>> +
>>> +                    // write the New Scaled Image
>>> +                    String newFileLocation = new String();
>>> +                    if(viewType.toLowerCase().contains("main")){
>>> +                        newFileLocation = mainFilenameExpander.expandString(UtilMisc.toMap("location", "products", "type", 
>>> sizeType, "id", id));
>>> +                    }else if(viewType.toLowerCase().contains("additional")){
>>> +                        newFileLocation = addFilenameExpander.expandString(UtilMisc.toMap("location", "products", "viewtype", 
>>> viewType, "sizetype", sizeType,"id", id));
>>> +                    }
>>> +                    String newFilePathPrefix = "";
>>> +                    if (newFileLocation.lastIndexOf("/") != -1) {
>>> +                        newFilePathPrefix = newFileLocation.substring(0, newFileLocation.lastIndexOf("/") + 1); // adding 1 to 
>>> include the trailing slash
>>> +                    }
>>> +
>>> +                    // choose final extension
>>> +                    String finalExtension = new String();
>>> +                    if(!extensionList.contains(imgExtension.toLowerCase())){
>>> +                        finalExtension = imgPropertyMap.get("format").get("extension");
>>> +                    }else{
>>> +                        finalExtension = imgExtension;
>>> +                    }
>>> +
>>> +                    String targetDirectory = imageServerPath + "/" + newFilePathPrefix;
>>> +                    File targetDir = new File(targetDirectory);
>>> +                    if (!targetDir.exists()) {
>>> +                        boolean created = targetDir.mkdirs();
>>> +                        if (!created) {
>>> +                            Debug.logFatal("Unable to create target directory - " + targetDirectory, module);
>>> +                            return ServiceUtil.returnError("Unable to create target directory - " + targetDirectory);
>>> +                        }
>>> +                    }
>>> +
>>> +                    // write new image
>>> +                    try{
>>> +                        ImageIO.write(op.filter(bufImg, bufNewImg), imgExtension, new File(imageServerPath + "/" + 
>>> newFilePathPrefix + filenameToUse));
>>> +                    }catch(IllegalArgumentException e){
>>> +                        String errMsg = "Any parameter is null" + e.toString();
>>> +                        Debug.logError(errMsg, module);
>>> +                        result.put("errorMessage", errMsg);
>>> +                        return result;
>>> +                    }catch(IOException e){
>>> +                        String errMsg = "An error occurs during writing" + e.toString();
>>> +                        Debug.logError(errMsg, module);
>>> +                        result.put("errorMessage", errMsg);
>>> +                        return result;
>>> +                    }
>>> +
>>> +                    /* write Return Result */
>>> +                    String imageUrl = imageUrlPrefix + "/" + newFilePathPrefix + filenameToUse;
>>> +                    imgUrlMap.put(sizeType, imageUrl);
>>> +
>>> +                } // scaleImgMap
>>> +            } // sizeIter
>>> +        }
>>> +
>>> +        result.put("responseMessage", "success");
>>> +        result.put("imageUrlMap", imgUrlMap);
>>> +        result.put("original", resultBufImgMap);
>>> +        return result;
>>> +
>>> +    } // scaleImageInAllSize
>>> +
>>> +
>>> +    /**
>>> +     * scaleImage
>>> +     * <p>
>>> +     * scale original image related to the ImageProperties.xml dimensions
>>> +     *
>>> +     * @param   bufImg          Buffered image to scale
>>> +     * @param   imgHeight       Original image height
>>> +     * @param   imgwidth        Original image width
>>> +     * @param   dimensionMap    Image dimensions by size type
>>> +     * @param   sizeType        Size type to scale
>>> +     * @return                  New scaled buffered image
>>> +     */
>>> +    private Map scaleImage(BufferedImage bufImg, double imgHeight, double imgWidth, LinkedHashMap<String, LinkedHashMap<String, 
>>> String>> dimensionMap, String sizeType){
>>> +
>>> +        /* VARIABLES */
>>> +        BufferedImage bufNewImg;
>>> +        double defaultHeight, defaultWidth, scaleFactor;
>>> +        FastMap result = new FastMap();
>>> +
>>> +        /* DIMENSIONS from ImageProperties */
>>> +        defaultHeight = Double.parseDouble(dimensionMap.get(sizeType).get("height").toString());
>>> +        defaultWidth = Double.parseDouble(dimensionMap.get(sizeType).get("width").toString());
>>> +        if(defaultHeight == 0.0 || defaultWidth == 0.0){
>>> +            String errMsg = "Any default dimension is null : defaultHeight = " + defaultHeight + " ; defaultWidth = " + 
>>> defaultWidth + ";";
>>> +            Debug.logError(errMsg, module);
>>> +            result.put("errorMessage", errMsg);
>>> +            return result;
>>> +        }
>>> +
>>> +        /* SCALE FACTOR */
>>> +        // find the right Scale Factor related to the Image Dimensions
>>> +        if(imgHeight > imgWidth){
>>> +            scaleFactor = defaultHeight / imgHeight;
>>> +            if(scaleFactor == 0.0){
>>> +                String errMsg = "Height scaleFactor is null (defaultHeight = " + defaultHeight + "; imgHeight = " + imgHeight + 
>>> ";";
>>> +                Debug.logError(errMsg, module);
>>> +                result.put("errorMessage", errMsg);
>>> +                return result;
>>> +            }
>>> +            // get scaleFactor from the smallest width
>>> +            if(defaultWidth < (imgWidth * scaleFactor)){
>>> +                scaleFactor = defaultWidth / imgWidth;
>>> +            }
>>> +        }else{
>>> +            scaleFactor = defaultWidth / imgWidth;
>>> +            if(scaleFactor == 0.0){
>>> +                String errMsg = "Width scaleFactor is null (defaultWidth = " + defaultWidth + "; imgWidth = " + imgWidth + ";";
>>> +                Debug.logError(errMsg, module);
>>> +                result.put("errorMessage", errMsg);
>>> +                return result;
>>> +            }
>>> +            // get scaleFactor from the smallest height
>>> +            if(defaultHeight < (imgHeight * scaleFactor)){
>>> +                scaleFactor = defaultHeight / imgHeight;
>>> +            }
>>> +        }
>>> +
>>> +        if(scaleFactor == 0.0){
>>> +            String errMsg = "Final scaleFactor is null = " + scaleFactor + ";";
>>> +            Debug.logError(errMsg, module);
>>> +            result.put("errorMessage", errMsg);
>>> +            return result;
>>> +        }
>>> +
>>> +        bufNewImg = new BufferedImage( (int) (imgWidth * scaleFactor), (int) (imgHeight * scaleFactor), bufImg.getType());
>>> +
>>> +        result.put("responseMessage", "success");
>>> +        result.put("bufferedImage", bufNewImg);
>>> +        result.put("scaleFactor", scaleFactor);
>>> +        return result;
>>> +
>>> +    } // scaleImage
>>> +
>>> +
>>> +    /**
>>> +     * getXMLValue
>>> +     * <p>
>>> +     * From a XML element, get a values map
>>> +     *
>>> +     * @param fileFullPath      File path to parse
>>> +     * @return Map contains asked attribute values by attribute name
>>> +     */
>>> +    private Map getXMLValue(String fileFullPath)
>>> +        throws IllegalStateException, IOException, JDOMException {
>>> +
>>> +        /* VARIABLES */
>>> +        Document document;
>>> +        Element rootElt;
>>> +        List<Element> eltList;
>>> +        LinkedHashMap<String, LinkedHashMap> valueMap = new LinkedHashMap<String, LinkedHashMap>();
>>> +        FastMap result = new FastMap();
>>> +
>>> +        /* PARSING */
>>> +        SAXBuilder sxb = new SAXBuilder();
>>> +        try{
>>> +            // JDOM
>>> +            document = sxb.build(new File(fileFullPath));
>>> +        }catch(JDOMException e){
>>> +            String errMsg = "Errors occur in parsing ImageProperties.xml" + e.toString();
>>> +            Debug.logError(errMsg, module);
>>> +            result.put("errorMessage", "error");
>>> +            return result;
>>> +        }catch(IOException e){
>>> +            String errMsg = "Error prevents the document from being fully parsed" + e.toString();
>>> +            Debug.logError(errMsg, module);
>>> +            result.put("errorMessage", "error");
>>> +            return result;
>>> +        }
>>> +        // set Root Element
>>> +        try{
>>> +            rootElt = document.getRootElement();
>>> +        }catch(IllegalStateException e){
>>> +            String errMsg = "Root element hasn't been set" + e.toString();
>>> +            Debug.logError(errMsg, module);
>>> +            result.put("errorMessage", "error");
>>> +            return result;
>>> +        }
>>> +
>>> +        /* get NAME and VALUE */
>>> +        Iterator<Element> eltIter = rootElt.getChildren().iterator();
>>> +        while(eltIter.hasNext()){
>>> +            Element currentElt = eltIter.next();
>>> +            LinkedHashMap<String, String> eltMap = new LinkedHashMap<String, String>();
>>> +            if(currentElt.getContentSize() > 0){
>>> +                LinkedHashMap<String, String> childMap = new LinkedHashMap<String, String>();
>>> +                // loop over Children 1st level
>>> +                Iterator<Element> childrenIter = currentElt.getChildren().iterator();
>>> +                while(childrenIter.hasNext()){
>>> +                    Element currentChild = childrenIter.next();
>>> +                    childMap.put(currentChild.getAttributeValue("name"), currentChild.getAttributeValue("value"));
>>> +                }
>>> +                valueMap.put(currentElt.getAttributeValue("name"), childMap);
>>> +            }else{
>>> +                eltMap.put(currentElt.getAttributeValue("name"), currentElt.getAttributeValue("value"));
>>> +                valueMap.put(currentElt.getName(), eltMap);
>>> +            }
>>> +        } // eltIter
>>> +
>>> +        result.put("responseMessage", "success");
>>> +        result.put("xml", valueMap);
>>> +        return result;
>>> +
>>> +    } // getXMLValue
>>> +
>>> +} // ImageTransform Class
>>>
>>
>
> 



Re: svn commit: r739042 - in /ofbiz/trunk/applications/product: config/ data/ entitydef/ src/org/ofbiz/image/ src/org/ofbiz/product/product/ webapp/catalog/WEB-INF/actions/product/ webapp/catalog/product/

Posted by Jacques Le Roux <ja...@les7arts.com>.
Yes, I thought about that too. Where do you think we should put it ? framework/images is mostly for static content, rather common I 
guess ?
BTW, I have refactored the code below since...

Jacques

From: "Adam Heath" <do...@brainfood.com>
> jleroux@apache.org wrote:
>
>> Added: ofbiz/trunk/applications/product/src/org/ofbiz/image/ImageTransform.java
>> URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/src/org/ofbiz/image/ImageTransform.java?rev=739042&view=auto
>> ==============================================================================
>> --- ofbiz/trunk/applications/product/src/org/ofbiz/image/ImageTransform.java (added)
>> +++ ofbiz/trunk/applications/product/src/org/ofbiz/image/ImageTransform.java Thu Jan 29 22:06:32 2009
>
> I don't think this file should be in product.  It's too generic.
>
>
>> @@ -0,0 +1,451 @@
>> +/*******************************************************************************
>> + * Licensed to the Apache Software Foundation (ASF) under one
>> + * or more contributor license agreements.  See the NOTICE file
>> + * distributed with this work for additional information
>> + * regarding copyright ownership.  The ASF licenses this file
>> + * to you 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.
>> + *******************************************************************************/
>> +package org.ofbiz.image;
>> +
>> +import java.awt.geom.AffineTransform;
>> +import java.awt.image.AffineTransformOp;
>> +import java.awt.image.BufferedImage;
>> +import java.awt.image.ImagingOpException;
>> +import java.awt.RenderingHints;
>> +import java.awt.RenderingHints.Key;
>> +import java.io.File;
>> +import java.io.IOException;
>> +import java.lang.IllegalArgumentException;
>> +import java.lang.Double;
>> +import java.lang.Object;
>> +import java.lang.String;
>> +import java.lang.System;
>> +import java.util.Iterator;
>> +import java.util.LinkedHashMap;
>> +import java.util.List;
>> +import java.util.Map;
>> +
>> +import javax.imageio.ImageIO;
>> +
>> +import javolution.util.FastList;
>> +import javolution.util.FastMap;
>> +
>> +import org.jdom.Document;
>> +import org.jdom.Element;
>> +import org.jdom.input.SAXBuilder;
>> +import org.jdom.filter.Filter;
>> +import org.jdom.JDOMException;
>
> Please do not use jdom, there's no need to.  UtilXml does everything that
> you need in this file(which is just parsing xml from java.io.File).  The
> looping over the elements is standard dom.
>
>> +
>> +import org.ofbiz.base.util.Debug;
>> +import org.ofbiz.base.util.string.FlexibleStringExpander;
>> +import org.ofbiz.base.util.UtilMisc;
>> +import org.ofbiz.base.util.UtilProperties;
>> +import org.ofbiz.service.ServiceUtil;
>> +
>> +
>> +/**
>> + * ImageTransform Class
>> + * <p>
>> + * Services to apply tranformation for images
>> + */
>> +public class ImageTransform {
>> +
>> +    public static final String module = ImageTransform.class.getName();
>> +//    public static final String err_resource = "ContentErrorUiLabels";
>> +
>> +    public ImageTransform() {}
>> +
>> +
>> +    /**
>> +     * getBufferedImage
>> +     * <p>
>> +     * Set a buffered image
>> +     *
>> +     * @param   context
>> +     * @param   fileLocation    Full file Path or Url
>> +     * @return                  Url images for all different size types
>> +     * @throws  IOException Error prevents the document from being fully parsed
>> +     * @throws  JDOMException Errors occur in parsing
>> +     */
>> +    public Map getBufferedImage(String fileLocation)
>> +        throws IllegalArgumentException, IOException {
>> +
>> +        /* VARIABLES */
>> +        BufferedImage bufImg;
>> +        FastMap result = new FastMap();
>> +
>> +        /* BUFFERED IMAGE */
>> +        try{
>> +            bufImg = ImageIO.read(new File(fileLocation));
>> +        }catch(IllegalArgumentException e){
>> +            String errMsg = "Input is null : " + fileLocation + " ; " + e.toString();
>> +            Debug.logError(errMsg, module);
>> +            result.put("errorMessage", errMsg);
>> +            return result;
>> +        }catch(IOException e){
>> +            String errMsg = "Error occurs during reading : " + fileLocation + " ; " + e.toString();
>> +            Debug.logError(errMsg, module);
>> +            result.put("errorMessage", errMsg);
>> +            return result;
>> +        }
>> +
>> +        result.put("responseMessage", "success");
>> +        result.put("bufferedImage", bufImg);
>> +        return result;
>> +
>> +    } // getBufferedImage
>> +
>> +
>> +    /**
>> +     * scaleImageInAllSize
>> +     * <p>
>> +     * Scale the original image into all different size Types (small, medium, large, detail)
>> +     *
>> +     * @param   context                     Context
>> +     * @param   filenameToUse               Filename of future image files
>> +     * @param   viewType                    "Main" view or "additional" view
>> +     * @param   viewNumber                  If it's the main view, viewNumber = "0"
>> +     * @return                              Url images for all different size types
>> +     * @throws  IllegalArgumentException    Any parameter is null
>> +     * @throws  ImagingOpException          The transform is non-invertible
>> +     * @throws  IOException                 Error prevents the document from being fully parsed
>> +     * @throws  JDOMException               Errors occur in parsing
>> +     */
>> +    public Map scaleImageInAllSize(Map<String, ? extends Object> context, String filenameToUse, String viewType, String 
>> viewNumber)
>> +        throws IllegalArgumentException, ImagingOpException, IOException, JDOMException {
>> +
>> +        /* VARIABLES */
>> +        List<String> sizeTypeList = UtilMisc.toList("small", "medium", "large", "detail");
>> +        List<String> extensionList = UtilMisc.toList("jpeg", "jpg", "png");
>> +        int index;
>> +        LinkedHashMap<String, LinkedHashMap<String, String>> imgPropertyMap = new LinkedHashMap<String, LinkedHashMap<String, 
>> String>>();
>> +        BufferedImage bufImg, bufNewImg;
>> +        double imgHeight, imgWidth, defaultHeight, defaultWidth, scaleFactor;
>> +        AffineTransformOp op;
>> +        LinkedHashMap<String, String> imgUrlMap = new LinkedHashMap<String, String>();
>> +        LinkedHashMap resultXMLMap = new LinkedHashMap();
>> +        LinkedHashMap resultBufImgMap = new LinkedHashMap();
>> +        LinkedHashMap resultScaleImgMap = new LinkedHashMap();
>> +        FastMap result = new FastMap();
>> +
>> +        /* ImageProperties.xml */
>> +        String imgPropertyFullPath = System.getProperty("ofbiz.home") + "/applications/product/config/ImageProperties.xml";
>> +        resultXMLMap.putAll(getXMLValue(imgPropertyFullPath));
>> +        if(resultXMLMap.containsKey("responseMessage") && resultXMLMap.get("responseMessage").equals("success")){
>> +            imgPropertyMap.putAll((LinkedHashMap) resultXMLMap.get("xml"));
>> +        }else{
>> +            String errMsg = "Impossible to parse ImageProperties.xml ";
>> +            Debug.logError(errMsg, module);
>> +            result.put("errorMessage", errMsg);
>> +            return result;
>> +        }
>> +
>> +        /* IMAGE */
>> +        // get Name and Extension
>> +        index = filenameToUse.lastIndexOf(".");
>> +        String imgName = filenameToUse.substring(0, index - 1);
>> +        String imgExtension = filenameToUse.substring(index + 1);
>> +        // paths
>> +        String mainFilenameFormat = UtilProperties.getPropertyValue("catalog", "image.filename.format");
>> +        String imageServerPath = FlexibleStringExpander.expandString(UtilProperties.getPropertyValue("catalog", 
>> "image.server.path"), context);
>> +        String imageUrlPrefix = UtilProperties.getPropertyValue("catalog", "image.url.prefix");
>> +
>> +        String id = new String();
>> +        String type = new String();
>> +        if(viewType.toLowerCase().contains("main")){
>> +            type = "original";
>> +            id = imgName;
>> +        }else if(viewType.toLowerCase().contains("additional") && viewNumber != null && !viewNumber.equals("0")){
>> +            type = "additional";
>> +            id = imgName + "_View_" + viewNumber;
>> +        }else{
>> +            return ServiceUtil.returnError("View Type : " + type + " is wrong");
>> +        }
>> +        FlexibleStringExpander mainFilenameExpander = FlexibleStringExpander.getInstance(mainFilenameFormat);
>> +        String fileLocation = mainFilenameExpander.expandString(UtilMisc.toMap("location", "products", "type", type, "id", 
>> filenameToUse));
>> +        String filePathPrefix = "";
>> +        if (fileLocation.lastIndexOf("/") != -1) {
>> +            filePathPrefix = fileLocation.substring(0, fileLocation.lastIndexOf("/") + 1); // adding 1 to include the trailing 
>> slash
>> +        }
>> +
>> +
>> +
>> +        /* get original BUFFERED IMAGE */
>> +        resultBufImgMap.putAll(this.getBufferedImage(imageServerPath + "/" + filePathPrefix + filenameToUse));
>> +
>> +        if(resultBufImgMap.containsKey("responseMessage") && resultBufImgMap.get("responseMessage").equals("success")){
>> +            bufImg = (BufferedImage) resultBufImgMap.get("bufferedImage");
>> +
>> +            // get Dimensions
>> +            imgHeight = (double) bufImg.getHeight();
>> +            imgWidth = (double) bufImg.getWidth();
>> +            if(imgHeight == 0.0 || imgWidth == 0.0){
>> +                String errMsg = "Any current image dimension is null : imgHeight = " + imgHeight + " ; imgWidth = " + imgWidth + 
>> ";";
>> +                Debug.logError(errMsg, module);
>> +                result.put("errorMessage", errMsg);
>> +                return result;
>> +            }
>> +
>> +            // new Filename Format
>> +            FlexibleStringExpander addFilenameExpander = mainFilenameExpander;
>> +            if(viewType.toLowerCase().contains("additional")){
>> +                String addFilenameFormat = UtilProperties.getPropertyValue("catalog", 
>> "image.filename.additionalviewsize.format");
>> +                addFilenameExpander = FlexibleStringExpander.getInstance(addFilenameFormat);
>> +            }
>> +
>> +            /* scale Image for each Size Type */
>> +            Iterator<String> sizeIter = sizeTypeList.iterator();
>> +            while(sizeIter.hasNext()){
>> +                String sizeType = sizeIter.next();
>> +
>> +                resultScaleImgMap.putAll(this.scaleImage(bufImg, imgHeight, imgWidth, imgPropertyMap, sizeType));
>> +
>> +                if(resultScaleImgMap.containsKey("responseMessage") && 
>> resultScaleImgMap.get("responseMessage").equals("success")){
>> +                    bufNewImg = (BufferedImage) resultScaleImgMap.get("bufferedImage");
>> +                    Double scaleFactorDb = (Double) resultScaleImgMap.get("scaleFactor");
>> +                    scaleFactor = scaleFactorDb.doubleValue();
>> +
>> +                    // define Interpolation
>> +                    LinkedHashMap<RenderingHints.Key, Object> rhMap = new LinkedHashMap<RenderingHints.Key, Object>();
>> +                        rhMap.put(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
>> +                        rhMap.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
>> +                        rhMap.put(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
>> +                        rhMap.put(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DISABLE);
>> +                        rhMap.put(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
>> +                        rhMap.put(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
>> +                        rhMap.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
>> +                        //rhMap.put(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
>> +                        rhMap.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
>> +                    RenderingHints rh = new RenderingHints(rhMap);
>> +
>> +                    /* IMAGE TRANFORMATION */
>> +                    AffineTransform tx = new AffineTransform();
>> +                    tx.scale(scaleFactor, scaleFactor);
>> +
>> +
>> +                    try{
>> +                        op = new AffineTransformOp(tx, rh);
>> +                    }catch(ImagingOpException e){
>> +                        String errMsg = "The transform is non-invertible" + e.toString();
>> +                        Debug.logError(errMsg, module);
>> +                        result.put("errorMessage", errMsg);
>> +                        return result;
>> +                    }
>> +
>> +                    // write the New Scaled Image
>> +                    String newFileLocation = new String();
>> +                    if(viewType.toLowerCase().contains("main")){
>> +                        newFileLocation = mainFilenameExpander.expandString(UtilMisc.toMap("location", "products", "type", 
>> sizeType, "id", id));
>> +                    }else if(viewType.toLowerCase().contains("additional")){
>> +                        newFileLocation = addFilenameExpander.expandString(UtilMisc.toMap("location", "products", "viewtype", 
>> viewType, "sizetype", sizeType,"id", id));
>> +                    }
>> +                    String newFilePathPrefix = "";
>> +                    if (newFileLocation.lastIndexOf("/") != -1) {
>> +                        newFilePathPrefix = newFileLocation.substring(0, newFileLocation.lastIndexOf("/") + 1); // adding 1 to 
>> include the trailing slash
>> +                    }
>> +
>> +                    // choose final extension
>> +                    String finalExtension = new String();
>> +                    if(!extensionList.contains(imgExtension.toLowerCase())){
>> +                        finalExtension = imgPropertyMap.get("format").get("extension");
>> +                    }else{
>> +                        finalExtension = imgExtension;
>> +                    }
>> +
>> +                    String targetDirectory = imageServerPath + "/" + newFilePathPrefix;
>> +                    File targetDir = new File(targetDirectory);
>> +                    if (!targetDir.exists()) {
>> +                        boolean created = targetDir.mkdirs();
>> +                        if (!created) {
>> +                            Debug.logFatal("Unable to create target directory - " + targetDirectory, module);
>> +                            return ServiceUtil.returnError("Unable to create target directory - " + targetDirectory);
>> +                        }
>> +                    }
>> +
>> +                    // write new image
>> +                    try{
>> +                        ImageIO.write(op.filter(bufImg, bufNewImg), imgExtension, new File(imageServerPath + "/" + 
>> newFilePathPrefix + filenameToUse));
>> +                    }catch(IllegalArgumentException e){
>> +                        String errMsg = "Any parameter is null" + e.toString();
>> +                        Debug.logError(errMsg, module);
>> +                        result.put("errorMessage", errMsg);
>> +                        return result;
>> +                    }catch(IOException e){
>> +                        String errMsg = "An error occurs during writing" + e.toString();
>> +                        Debug.logError(errMsg, module);
>> +                        result.put("errorMessage", errMsg);
>> +                        return result;
>> +                    }
>> +
>> +                    /* write Return Result */
>> +                    String imageUrl = imageUrlPrefix + "/" + newFilePathPrefix + filenameToUse;
>> +                    imgUrlMap.put(sizeType, imageUrl);
>> +
>> +                } // scaleImgMap
>> +            } // sizeIter
>> +        }
>> +
>> +        result.put("responseMessage", "success");
>> +        result.put("imageUrlMap", imgUrlMap);
>> +        result.put("original", resultBufImgMap);
>> +        return result;
>> +
>> +    } // scaleImageInAllSize
>> +
>> +
>> +    /**
>> +     * scaleImage
>> +     * <p>
>> +     * scale original image related to the ImageProperties.xml dimensions
>> +     *
>> +     * @param   bufImg          Buffered image to scale
>> +     * @param   imgHeight       Original image height
>> +     * @param   imgwidth        Original image width
>> +     * @param   dimensionMap    Image dimensions by size type
>> +     * @param   sizeType        Size type to scale
>> +     * @return                  New scaled buffered image
>> +     */
>> +    private Map scaleImage(BufferedImage bufImg, double imgHeight, double imgWidth, LinkedHashMap<String, LinkedHashMap<String, 
>> String>> dimensionMap, String sizeType){
>> +
>> +        /* VARIABLES */
>> +        BufferedImage bufNewImg;
>> +        double defaultHeight, defaultWidth, scaleFactor;
>> +        FastMap result = new FastMap();
>> +
>> +        /* DIMENSIONS from ImageProperties */
>> +        defaultHeight = Double.parseDouble(dimensionMap.get(sizeType).get("height").toString());
>> +        defaultWidth = Double.parseDouble(dimensionMap.get(sizeType).get("width").toString());
>> +        if(defaultHeight == 0.0 || defaultWidth == 0.0){
>> +            String errMsg = "Any default dimension is null : defaultHeight = " + defaultHeight + " ; defaultWidth = " + 
>> defaultWidth + ";";
>> +            Debug.logError(errMsg, module);
>> +            result.put("errorMessage", errMsg);
>> +            return result;
>> +        }
>> +
>> +        /* SCALE FACTOR */
>> +        // find the right Scale Factor related to the Image Dimensions
>> +        if(imgHeight > imgWidth){
>> +            scaleFactor = defaultHeight / imgHeight;
>> +            if(scaleFactor == 0.0){
>> +                String errMsg = "Height scaleFactor is null (defaultHeight = " + defaultHeight + "; imgHeight = " + imgHeight + 
>> ";";
>> +                Debug.logError(errMsg, module);
>> +                result.put("errorMessage", errMsg);
>> +                return result;
>> +            }
>> +            // get scaleFactor from the smallest width
>> +            if(defaultWidth < (imgWidth * scaleFactor)){
>> +                scaleFactor = defaultWidth / imgWidth;
>> +            }
>> +        }else{
>> +            scaleFactor = defaultWidth / imgWidth;
>> +            if(scaleFactor == 0.0){
>> +                String errMsg = "Width scaleFactor is null (defaultWidth = " + defaultWidth + "; imgWidth = " + imgWidth + ";";
>> +                Debug.logError(errMsg, module);
>> +                result.put("errorMessage", errMsg);
>> +                return result;
>> +            }
>> +            // get scaleFactor from the smallest height
>> +            if(defaultHeight < (imgHeight * scaleFactor)){
>> +                scaleFactor = defaultHeight / imgHeight;
>> +            }
>> +        }
>> +
>> +        if(scaleFactor == 0.0){
>> +            String errMsg = "Final scaleFactor is null = " + scaleFactor + ";";
>> +            Debug.logError(errMsg, module);
>> +            result.put("errorMessage", errMsg);
>> +            return result;
>> +        }
>> +
>> +        bufNewImg = new BufferedImage( (int) (imgWidth * scaleFactor), (int) (imgHeight * scaleFactor), bufImg.getType());
>> +
>> +        result.put("responseMessage", "success");
>> +        result.put("bufferedImage", bufNewImg);
>> +        result.put("scaleFactor", scaleFactor);
>> +        return result;
>> +
>> +    } // scaleImage
>> +
>> +
>> +    /**
>> +     * getXMLValue
>> +     * <p>
>> +     * From a XML element, get a values map
>> +     *
>> +     * @param fileFullPath      File path to parse
>> +     * @return Map contains asked attribute values by attribute name
>> +     */
>> +    private Map getXMLValue(String fileFullPath)
>> +        throws IllegalStateException, IOException, JDOMException {
>> +
>> +        /* VARIABLES */
>> +        Document document;
>> +        Element rootElt;
>> +        List<Element> eltList;
>> +        LinkedHashMap<String, LinkedHashMap> valueMap = new LinkedHashMap<String, LinkedHashMap>();
>> +        FastMap result = new FastMap();
>> +
>> +        /* PARSING */
>> +        SAXBuilder sxb = new SAXBuilder();
>> +        try{
>> +            // JDOM
>> +            document = sxb.build(new File(fileFullPath));
>> +        }catch(JDOMException e){
>> +            String errMsg = "Errors occur in parsing ImageProperties.xml" + e.toString();
>> +            Debug.logError(errMsg, module);
>> +            result.put("errorMessage", "error");
>> +            return result;
>> +        }catch(IOException e){
>> +            String errMsg = "Error prevents the document from being fully parsed" + e.toString();
>> +            Debug.logError(errMsg, module);
>> +            result.put("errorMessage", "error");
>> +            return result;
>> +        }
>> +        // set Root Element
>> +        try{
>> +            rootElt = document.getRootElement();
>> +        }catch(IllegalStateException e){
>> +            String errMsg = "Root element hasn't been set" + e.toString();
>> +            Debug.logError(errMsg, module);
>> +            result.put("errorMessage", "error");
>> +            return result;
>> +        }
>> +
>> +        /* get NAME and VALUE */
>> +        Iterator<Element> eltIter = rootElt.getChildren().iterator();
>> +        while(eltIter.hasNext()){
>> +            Element currentElt = eltIter.next();
>> +            LinkedHashMap<String, String> eltMap = new LinkedHashMap<String, String>();
>> +            if(currentElt.getContentSize() > 0){
>> +                LinkedHashMap<String, String> childMap = new LinkedHashMap<String, String>();
>> +                // loop over Children 1st level
>> +                Iterator<Element> childrenIter = currentElt.getChildren().iterator();
>> +                while(childrenIter.hasNext()){
>> +                    Element currentChild = childrenIter.next();
>> +                    childMap.put(currentChild.getAttributeValue("name"), currentChild.getAttributeValue("value"));
>> +                }
>> +                valueMap.put(currentElt.getAttributeValue("name"), childMap);
>> +            }else{
>> +                eltMap.put(currentElt.getAttributeValue("name"), currentElt.getAttributeValue("value"));
>> +                valueMap.put(currentElt.getName(), eltMap);
>> +            }
>> +        } // eltIter
>> +
>> +        result.put("responseMessage", "success");
>> +        result.put("xml", valueMap);
>> +        return result;
>> +
>> +    } // getXMLValue
>> +
>> +} // ImageTransform Class
>>
>