Package org.apache.batik.test.svg

Source Code of org.apache.batik.test.svg.SVGRenderingAccuracyTest

/*****************************************************************************
* Copyright (C) The Apache Software Foundation. All rights reserved.        *
* ------------------------------------------------------------------------- *
* This software is published under the terms of the Apache Software License *
* version 1.1, a copy of which has been included with this distribution in  *
* the LICENSE file.                                                         *
*****************************************************************************/

package org.apache.batik.test.svg;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.io.PrintWriter;

import java.net.URL;

import java.util.Locale;
import java.util.ResourceBundle;
import java.util.Vector;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;

import org.apache.batik.ext.awt.image.CompositeRule;
import org.apache.batik.ext.awt.image.rendered.CompositeRed;
import org.apache.batik.ext.awt.image.rendered.BufferedImageCachableRed;

import org.apache.batik.ext.awt.image.ImageLoader;

import org.apache.batik.ext.awt.image.codec.PNGImageEncoder;
import org.apache.batik.ext.awt.image.codec.PNGEncodeParam;

import org.apache.batik.transcoder.TranscoderException;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;

import org.apache.batik.transcoder.image.ImageTranscoder;
import org.apache.batik.transcoder.image.PNGTranscoder;

import org.apache.batik.test.DefaultTestReport;
import org.apache.batik.test.Test;
import org.apache.batik.test.TestReport;


/**
* Checks for regressions in rendering a specific SVG document.
* The <tt>Test</tt> will rasterize and SVG document and
* compare it to a reference image. The test passes if the
* rasterized SVG and the reference image match exactly (i.e.,
* all pixel values are the same).
*
* @author <a href="mailto:vhardy@apache.lorg">Vincent Hardy</a>
* @version $Id: SVGRenderingAccuracyTest.java,v 1.6 2001/04/16 22:42:37 vhardy Exp $
*/
public class SVGRenderingAccuracyTest implements Test{
    /**
     * Error when temp file cannot be created
     * {0} = IOException message
     */
    public static final String ERROR_CANNOT_CREATE_TEMP_FILE       
        = "SVGRenderingAccuracyTest.error.cannot.create.temp.file";

    /**
     * Error when temp file stream cannot be created
     * {0} = temp file's cannonical path
     * {1} = IOException message
     */
    public static final String ERROR_CANNOT_CREATE_TEMP_FILE_STREAM
        = "SVGRenderingAccuracyTest.error.cannot.create.temp.file.stream";

    /**
     * Error when transcoding the SVG document generates an error
     * {0} = URI of the transcoded SVG file
     * {1} = Exception class
     * {2} = Exception message
     * {3} = Stack trace.
     */
    public static final String ERROR_CANNOT_TRANSCODE_SVG          
        = "SVGRenderingAccuracyTest.error.cannot.transcode.svg";

    /**
     * Error when the reference image cannot be opened
     * {0} = URI of the reference image
     * {1} = IOException message
     */
    public static final String ERROR_CANNOT_OPEN_REFERENCE_IMAGE   
        = "SVGRenderingAccuracyTest.error.cannot.open.reference.image";

    /**
     * Error when the generated image cannot be read
     * {0} = Cannonical path of the temp generated image
     * {1} = IOException message
     */
    public static final String ERROR_CANNOT_OPEN_GENERATED_IMAGE   
        = "SVGRenderingAccuracyTest.error.cannot.open.genereted.image";

    /**
     * Error when there is an IOException while comparing the
     * two reference raster image with the new raster image built
     * from the SVG.
     * {0} = URI of the reference image
     * {1} = Connical path for the temp generated image
     * {2} = IOException message.
     */
    public static final String ERROR_ERROR_WHILE_COMPARING_FILES   
        = "SVGRenderingAccuracyTest.error.while.comparing.files";

    /**
     * Error when the generated image from the SVG file differs from
     * the reference image.
     */
    public static final String ERROR_SVG_RENDERING_NOT_ACCURATE    
        = "SVGRenderingAccuracyTest.error.svg.rendering.not.accurate";

    /**
     * Entry describing the error
     */
    public static final String ENTRY_KEY_ERROR_DESCRIPTION
        = "SVGRenderingAccuracyTest.entry.key.error.description";

    /**
     * Entry describing the reference/generated image file
     */
    public static final String ENTRY_KEY_REFERENCE_GENERATED_IMAGE_URI
        = "SVGRenderingAccuracyTest.entry.key.reference.generated.image.file";

    /**
     * Entry describing the generated difference image
     */
    public static final String ENTRY_KEY_DIFFERENCE_IMAGE
        = "SVGRenderingAccuracyTest.entry.key.difference.image";

    /**
     * Entry describing that an internal error occured while
     * generating the test failure description
     */
    public static final String ENTRY_KEY_INTERNAL_ERROR
        = "SVGRenderingAccuracyTest.entry.key.internal.error";

    /**
     * Messages expressing that comparison images could not be
     * created:
     * {0} : exception class
     * {1} : exception message
     * {2} : exception stack trace.
     */
    public static final String COULD_NOT_GENERATE_COMPARISON_IMAGES
        = "SVGRenderingAccuracyTest.message.error.could.not.generate.comparison.images";

    /**
     * Messages expressing that an image could not be loaded.
     * {0} : URL for the reference image.
     */
    public static final String COULD_NOT_LOAD_IMAGE
        = "SVGRenderingAccuracyTest.message.error.could.not.load.image";

    /**
     * Message expressing that the variation URL could not be open
     * {0} : URL
     */
    public static final String COULD_NOT_OPEN_VARIATION_URL
        = "SVGRenderingAccuracyTest.message.warning.could.not.open.variation.url";

    /**
     * The gui resources file name
     */
    public final static String CONFIGURATION_RESOURCES =
        "org.apache.batik.test.svg.resources.Configuration";

    /**
     * The configuration resource bundle
     */
    protected static ResourceBundle configuration;
    static {
        configuration = ResourceBundle.getBundle(CONFIGURATION_RESOURCES,
                                                 Locale.getDefault());
    }

    /**
     * Prefix for the temporary files created by Tests
     * of this class
     */
    public static final String TEMP_FILE_PREFIX
        = configuration.getString("temp.file.prefix");

    /**
     * Suffix for the temporary files created by
     * Tests of this class
     */
    public static final String TEMP_FILE_SUFFIX
        = configuration.getString("temp.file.suffix");

    /**
     * Parser class name
     */
    public static final String PARSER_CLASS_NAME
        = configuration.getString("org.xml.sax.driver");

    /**
     * The URL where the SVG can be found.
     */
    protected URL svgURL;

    /**
     * The URL for the reference image
     */
    protected URL refImgURL;

    /**
     * The URL of a file containing an 'accepted'
     * variation from the reference image.
     */
    protected URL variationURL;

    /**
     * The File where the newly computed variation
     * should be saved if different from the
     * variationURL
     */
    protected File saveVariation;

    /**
     * Constructor.
     * @param svgURL the URL for the SVG document being tested.
     * @param refImgURL the URL for the reference image.
     */
    public SVGRenderingAccuracyTest(URL svgURL,
                                    URL refImgURL){
        if(svgURL == null){
            throw new IllegalArgumentException();
        }

        if(refImgURL == null){
            throw new IllegalArgumentException();
        }

        this.svgURL = svgURL;
        this.refImgURL = refImgURL;
        this.variationURL = variationURL;
        this.saveVariation = saveVariation;
    }

    /**
     * Sets the File where the variation from the reference image should be
     * stored
     */
    public void setSaveVariation(File saveVariation){
        this.saveVariation = saveVariation;
    }

    public File getSaveVariation(){
        return saveVariation;
    }

    public URL getVariationURL(){
        return variationURL;
    }

    /**
     * Sets the URL where an acceptable variation fron the reference
     * image can be found.
     */
    public void setVariationURL(URL variationURL){
        this.variationURL = variationURL;
    }

    /**
     * Returns this <tt>Test</tt>'s name. The name is the
     * URL of the SVG being rendered.
     */
    public String getName(){
        return svgURL.toString();
    }

    /**
     * Requests this <tt>Test</tt> to run and produce a
     * report.
     *
     */
    public TestReport run(){
        DefaultTestReport report
            = new DefaultTestReport(this);

        //
        // Render the SVG image into a raster. We use the
        // ImageTranscoder to convert the SVG into a raster in
        // a temporary file.
        //
        File tmpFile = null;

        try{
            tmpFile = File.createTempFile(TEMP_FILE_PREFIX,
                                          TEMP_FILE_SUFFIX,
                                          null);
            tmpFile.deleteOnExit();
        }catch(IOException e){
            report.setErrorCode(ERROR_CANNOT_CREATE_TEMP_FILE);
            report.setDescription(new TestReport.Entry[] {
                new TestReport.Entry(Messages.formatMessage(ENTRY_KEY_ERROR_DESCRIPTION, null),
                          Messages.formatMessage(ERROR_CANNOT_CREATE_TEMP_FILE,
                                                 new Object[]{e.getMessage()}))
                    });
            report.setPassed(false);
            return report;
        }

        FileOutputStream tmpFileOS = null;

        try{
            tmpFileOS = new FileOutputStream(tmpFile);
        }catch(IOException e){
            report.setErrorCode(ERROR_CANNOT_CREATE_TEMP_FILE_STREAM);
            report.setDescription(new TestReport.Entry[] {
                new TestReport.Entry(Messages.formatMessage(ENTRY_KEY_ERROR_DESCRIPTION, null),
                          Messages.formatMessage(ERROR_CANNOT_CREATE_TEMP_FILE_STREAM,
                                                 new String[]{tmpFile.getAbsolutePath(),
                                                              e.getMessage()})) });
            report.setPassed(false);
            return report;
        }

        ImageTranscoder transcoder = getImageTranscoder();
        TranscoderInput src = new TranscoderInput(svgURL.toExternalForm());
        TranscoderOutput dst = new TranscoderOutput(tmpFileOS);
       
        try{
            transcoder.transcode(src, dst);
        }catch(TranscoderException e){
            StringWriter trace = new StringWriter();
            e.printStackTrace(new PrintWriter(trace));
               
            report.setErrorCode(ERROR_CANNOT_TRANSCODE_SVG);
            report.setDescription(new TestReport.Entry[]{
                new TestReport.Entry(Messages.formatMessage(ENTRY_KEY_ERROR_DESCRIPTION, null),
                          Messages.formatMessage(ERROR_CANNOT_TRANSCODE_SVG,
                                                 new String[]{svgURL.toExternalForm(),
                                                              e.getClass().getName(),
                                                              e.getMessage(),
                                                              trace.toString()
                                                 })) });
            report.setPassed(false);
            return report;
        }catch(Exception e){
            StringWriter trace = new StringWriter();
            e.printStackTrace(new PrintWriter(trace));

            report.setErrorCode(ERROR_CANNOT_TRANSCODE_SVG);
            report.setDescription(new TestReport.Entry[]{
                new TestReport.Entry(Messages.formatMessage(ENTRY_KEY_ERROR_DESCRIPTION, null),
                          Messages.formatMessage(ERROR_CANNOT_TRANSCODE_SVG,
                                                 new String[]{svgURL.toExternalForm(),
                                                              e.getClass().getName(),
                                                              e.getMessage(),
                                                              trace.toString()
                                                 })) });
            report.setPassed(false);
            return report;
        }

        //
        // Do a binary comparison of the encoded images.
        //
        InputStream refStream = null;
        InputStream newStream = null;
        try {
            refStream =
                new BufferedInputStream(refImgURL.openStream());
        }catch(IOException e){
            report.setErrorCode(ERROR_CANNOT_OPEN_REFERENCE_IMAGE);
            report.setDescription( new TestReport.Entry[]{
                new TestReport.Entry(Messages.formatMessage(ENTRY_KEY_ERROR_DESCRIPTION, null),
                          Messages.formatMessage(ERROR_CANNOT_OPEN_REFERENCE_IMAGE,
                                                 new Object[]{refImgURL.toExternalForm(),
                                                              e.getMessage()})) });
            report.setPassed(false);
            tmpFile.delete();
            return report;
        }

        try{
            newStream =
                new BufferedInputStream(new FileInputStream(tmpFile));
        }catch(IOException e){
            report.setErrorCode(ERROR_CANNOT_OPEN_GENERATED_IMAGE);
            report.setDescription(new TestReport.Entry[]{
                new TestReport.Entry(Messages.formatMessage(ENTRY_KEY_ERROR_DESCRIPTION, null),
                          Messages.formatMessage(ERROR_CANNOT_OPEN_GENERATED_IMAGE,
                                                 new Object[]{tmpFile.getAbsolutePath(),
                                                              e.getMessage()}))});
            report.setPassed(false);
            tmpFile.delete();
            return report;
        }


        boolean accurate = false;
        try{
            accurate = compare(refStream, newStream);
        } catch(IOException e) {
            report.setErrorCode(ERROR_ERROR_WHILE_COMPARING_FILES);
            report.setDescription(new TestReport.Entry[]{
                new TestReport.Entry(Messages.formatMessage(ENTRY_KEY_ERROR_DESCRIPTION, null),
                          Messages.formatMessage(ERROR_ERROR_WHILE_COMPARING_FILES,
                                                 new Object[]{refImgURL.toExternalForm(),
                                                              tmpFile.getAbsolutePath(),
                                                              e.getMessage()}))});
            report.setPassed(false);
            return report;
        }


        //
        // If the files differ here, it means that even the variation does
        // not account for the difference return an error
        //
        if(!accurate){
            try{
                BufferedImage ref = getImage(refImgURL);
                BufferedImage gen = getImage(tmpFile);
                BufferedImage diff = buildDiffImage(ref, gen);

                //
                // If there is an accepted variation, check if it equals the
                // computed difference.
                //
                if(variationURL != null){
                    File tmpDiff = imageToFile(diff);

                    InputStream variationURLStream = null;
                    try{
                        variationURLStream = variationURL.openStream();
                    }catch(IOException e){
                        // Could not open variationURL stream. Just trace that
                        System.err.println(Messages.formatMessage(COULD_NOT_OPEN_VARIATION_URL,
                                                                  new Object[]{variationURL.toString()}));
                    }

                    if(variationURLStream != null){
                        InputStream refDiffStream =
                            new BufferedInputStream(variationURLStream);
                       
                        InputStream tmpDiffStream =
                            new BufferedInputStream(new FileInputStream(tmpDiff));
                       
                        if(compare(refDiffStream, tmpDiffStream)){
                            // We accept the generated result.
                            accurate = true;
                        }
                    }
                }

                if(!accurate){

                    if(saveVariation != null){
                        // There is a computed variation different from the
                        // referenced variation and there is a place where the new
                        // variation should be saved.
                        saveImage(diff, saveVariation);
                    }
                   
                    // Build two images:
                    // a. One with the reference image and the newly generated image
                    // b. One with the difference between the two images and the set of
                    //    different pixels.
                    BufferedImage cmp = makeCompareImage(ref, gen);
                    File cmpFile = imageToFile(cmp);
                    File diffFile = imageToFile(diff);
                   
                    report.setErrorCode(ERROR_SVG_RENDERING_NOT_ACCURATE);
                   
                    report.setDescription(new TestReport.Entry[]{
                        new TestReport.Entry(Messages.formatMessage(ENTRY_KEY_ERROR_DESCRIPTION, null),
                                             Messages.formatMessage(ERROR_SVG_RENDERING_NOT_ACCURATE, null)),
                        new TestReport.Entry(Messages.formatMessage(ENTRY_KEY_REFERENCE_GENERATED_IMAGE_URI, null),
                                             cmpFile),
                        new TestReport.Entry(Messages.formatMessage(ENTRY_KEY_DIFFERENCE_IMAGE, null),
                                             diffFile) });

               
                    report.setPassed(false);
                    return report;
                }
            }catch(Exception e){
                report.setErrorCode(ERROR_SVG_RENDERING_NOT_ACCURATE);
                StringWriter trace = new StringWriter();
                e.printStackTrace(new PrintWriter(trace));
               
                report.setDescription(new TestReport.Entry[]{
                    new TestReport.Entry(Messages.formatMessage(ENTRY_KEY_ERROR_DESCRIPTION, null),
                                         Messages.formatMessage(ERROR_SVG_RENDERING_NOT_ACCURATE, null)),
                    new TestReport.Entry(Messages.formatMessage(ENTRY_KEY_INTERNAL_ERROR, null),
                                         Messages.formatMessage(COULD_NOT_GENERATE_COMPARISON_IMAGES,
                                                                new Object[]{e.getClass().getName(),
                                                                             e.getMessage(),
                                                                             trace.toString()})) });
                    report.setPassed(false);
                    return report;
            }
        }


        //
        // Yahooooooo! everything worked out well.
        //
        report.setPassed(true);
        return report;
    }

    /**
     * Compare the two input streams
     */
    protected boolean compare(InputStream refStream,
                              InputStream newStream)
        throws IOException{
        int b, nb;
        boolean accurate;
        do {
            b = refStream.read();
            nb = newStream.read();
        } while (b != -1 && nb != -1 && b == nb);
        refStream.close();
        newStream.close();
        return (b == nb);
    }

    /**
     * Saves an image in a given File
     */
    protected void saveImage(BufferedImage img, File imgFile)
        throws IOException {
        if(!imgFile.exists()){
            imgFile.createNewFile();
        }

        PNGImageEncoder encoder
            = new PNGImageEncoder(new FileOutputStream(imgFile),
                                  PNGEncodeParam.getDefaultEncodeParam(img));
       
        encoder.encode(img);
    }

    /**
     * Builds a new BufferedImage that is the difference between the two input images
     */
    protected BufferedImage buildDiffImage(BufferedImage ref,
                                           BufferedImage gen){
        BufferedImage diff = new BufferedImage(ref.getWidth(),
                                               ref.getHeight(),
                                               BufferedImage.TYPE_INT_ARGB);

        Vector src = new Vector();
        src.addElement(new BufferedImageCachableRed(ref));
        src.addElement(new BufferedImageCachableRed(gen));

        CompositeRed cr = new CompositeRed(src,
                                           CompositeRule.ARITHMETIC(0, 10, -10, 0.5f));

        cr.copyToRaster(diff.getRaster());
        return diff;
    }

    /**
     * Loads an image from a File
     */
    protected BufferedImage getImage(File file)
        throws Exception {
        return getImage(file.toURL());
    }

    /**
     * Loads an image from a URL
     */
    protected BufferedImage getImage(URL url)
        throws IOException {
        BufferedImage img = ImageLoader.loadImage(url,
                                                  BufferedImage.TYPE_INT_ARGB);
       
        if(img == null){
            throw new IOException(Messages.formatMessage(COULD_NOT_LOAD_IMAGE,
                                                         new Object[]{url.toString()}));
        }

        return img;
    }

    /**
     *
     */
    protected BufferedImage makeCompareImage(BufferedImage ref,
                                             BufferedImage gen){
        BufferedImage cmp = new BufferedImage(ref.getWidth()*2,
                                              ref.getHeight(),
                                              BufferedImage.TYPE_INT_ARGB);

        Graphics2D g = cmp.createGraphics();
        g.setPaint(Color.white);
        g.fillRect(0, 0, cmp.getWidth(), cmp.getHeight());
        g.drawImage(ref, 0, 0, null);
        g.translate(ref.getWidth(), 0);
        g.drawImage(gen, 0, 0, null);
        g.dispose();

        return cmp;
    }

    /**
     * Creates a temporary File into which the input image is
     * saved.
     */
    protected File imageToFile(BufferedImage img)
        throws IOException {

        File imgFile
            = File.createTempFile(TEMP_FILE_PREFIX,
                                  TEMP_FILE_SUFFIX,
                                  null);
        imgFile.deleteOnExit();

        PNGImageEncoder encoder
            = new PNGImageEncoder(new FileOutputStream(imgFile),
                             PNGEncodeParam.getDefaultEncodeParam(img));

        encoder.encode(img);

        return imgFile;
    }

    /**
     * Returns the <tt>ImageTranscoder</tt> the Test should
     * use
     */
    public static ImageTranscoder getImageTranscoder(){
        ImageTranscoder t = new PNGTranscoder();
        t.addTranscodingHint(PNGTranscoder.KEY_XML_PARSER_CLASSNAME,
                             PARSER_CLASS_NAME);
        return t;
    }
}
TOP

Related Classes of org.apache.batik.test.svg.SVGRenderingAccuracyTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.