1 18 package org.apache.batik.test.svg; 19 20 import java.io.BufferedInputStream ; 21 import java.io.File ; 22 import java.io.FileInputStream ; 23 import java.io.FileOutputStream ; 24 import java.io.InputStream ; 25 import java.io.IOException ; 26 import java.io.OutputStream ; 27 import java.io.PrintWriter ; 28 import java.io.StringWriter ; 29 30 import java.net.URL ; 31 import java.net.MalformedURLException ; 32 33 import java.util.Locale ; 34 import java.util.ResourceBundle ; 35 36 import java.awt.Color ; 37 import java.awt.Graphics2D ; 38 import java.awt.image.BufferedImage ; 39 import java.awt.image.RenderedImage ; 40 import java.awt.image.WritableRaster ; 41 import java.awt.image.ColorModel ; 42 43 import org.apache.batik.ext.awt.image.GraphicsUtil; 44 45 import org.apache.batik.ext.awt.image.spi.ImageTagRegistry; 46 import org.apache.batik.ext.awt.image.renderable.Filter; 47 48 import org.apache.batik.ext.awt.image.codec.PNGImageEncoder; 49 import org.apache.batik.ext.awt.image.codec.PNGEncodeParam; 50 51 import org.apache.batik.util.ParsedURL; 52 53 import org.apache.batik.test.AbstractTest; 54 import org.apache.batik.test.DefaultTestReport; 55 import org.apache.batik.test.TestReport; 56 57 67 public abstract class AbstractRenderingAccuracyTest extends AbstractTest { 68 72 public static final String ERROR_CANNOT_CREATE_TEMP_FILE 73 = "SVGRenderingAccuracyTest.error.cannot.create.temp.file"; 74 75 80 public static final String ERROR_CANNOT_CREATE_TEMP_FILE_STREAM 81 = "SVGRenderingAccuracyTest.error.cannot.create.temp.file.stream"; 82 83 88 public static final String ERROR_CANNOT_OPEN_REFERENCE_IMAGE 89 = "SVGRenderingAccuracyTest.error.cannot.open.reference.image"; 90 91 96 public static final String ERROR_CANNOT_OPEN_GENERATED_IMAGE 97 = "SVGRenderingAccuracyTest.error.cannot.open.genereted.image"; 98 99 107 public static final String ERROR_ERROR_WHILE_COMPARING_FILES 108 = "SVGRenderingAccuracyTest.error.while.comparing.files"; 109 110 114 public static final String ERROR_SVG_RENDERING_NOT_ACCURATE 115 = "SVGRenderingAccuracyTest.error.svg.rendering.not.accurate"; 116 117 120 public static final String ENTRY_KEY_ERROR_DESCRIPTION 121 = "SVGRenderingAccuracyTest.entry.key.error.description"; 122 123 126 public static final String ENTRY_KEY_REFERENCE_GENERATED_IMAGE_URI 127 = "SVGRenderingAccuracyTest.entry.key.reference.generated.image.file"; 128 129 132 public static final String ENTRY_KEY_DIFFERENCE_IMAGE 133 = "SVGRenderingAccuracyTest.entry.key.difference.image"; 134 135 139 public static final String ENTRY_KEY_INTERNAL_ERROR 140 = "SVGRenderingAccuracyTest.entry.key.internal.error"; 141 142 149 public static final String COULD_NOT_GENERATE_COMPARISON_IMAGES 150 = "SVGRenderingAccuracyTest.message.error.could.not.generate.comparison.images"; 151 152 156 public static final String COULD_NOT_LOAD_IMAGE 157 = "SVGRenderingAccuracyTest.message.error.could.not.load.image"; 158 159 163 public static final String COULD_NOT_OPEN_VARIATION_URL 164 = "SVGRenderingAccuracyTest.message.warning.could.not.open.variation.url"; 165 166 169 public final static String CONFIGURATION_RESOURCES = 170 "org.apache.batik.test.svg.resources.Configuration"; 171 172 175 public final static String IMAGE_TYPE_COMPARISON = "_cmp"; 176 177 180 public final static String IMAGE_TYPE_DIFF = "_diff"; 181 182 185 public final static String IMAGE_FILE_EXTENSION = ".png"; 186 187 190 protected static ResourceBundle configuration; 191 static { 192 configuration = ResourceBundle.getBundle(CONFIGURATION_RESOURCES, 193 Locale.getDefault()); 194 } 195 196 200 public static final String TEMP_FILE_PREFIX 201 = configuration.getString("temp.file.prefix"); 202 203 207 public static final String TEMP_FILE_SUFFIX 208 = configuration.getString("temp.file.suffix"); 209 210 213 protected URL svgURL; 214 215 218 protected URL refImgURL; 219 220 224 protected URL variationURL; 225 226 231 protected File saveVariation; 232 233 238 protected File candidateReference; 239 240 243 protected static File tempDirectory; 244 245 248 public static File getTempDirectory(){ 249 if(tempDirectory == null){ 250 String tmpDir = System.getProperty("java.io.tmpdir"); 251 if(tmpDir == null){ 252 throw new Error (); 253 } 254 255 tempDirectory = new File (tmpDir); 256 if(!tempDirectory.exists()){ 257 throw new Error (); 258 } 259 } 260 return tempDirectory; 261 } 262 263 268 public AbstractRenderingAccuracyTest(String svgURL, 269 String refImgURL){ 270 setConfig(svgURL, refImgURL); 271 } 272 273 276 protected AbstractRenderingAccuracyTest(){ 277 } 278 279 282 public void setConfig(String svgURL, 283 String refImgURL){ 284 if(svgURL == null){ 285 throw new IllegalArgumentException (); 286 } 287 288 if(refImgURL == null){ 289 throw new IllegalArgumentException (); 290 } 291 292 this.svgURL = resolveURL(svgURL); 293 this.refImgURL = resolveURL(refImgURL); 294 } 295 296 304 protected URL resolveURL(String url){ 305 File f = (new File (url)).getAbsoluteFile(); 307 if(f.getParentFile().exists()){ 308 try{ 309 return f.toURL(); 310 }catch(MalformedURLException e){ 311 throw new IllegalArgumentException (); 312 } 313 } 314 315 try{ 317 return new URL (url); 318 }catch(MalformedURLException e){ 319 throw new IllegalArgumentException (url); 320 } 321 } 322 323 327 public void setSaveVariation(File saveVariation){ 328 this.saveVariation = saveVariation; 329 } 330 331 public File getSaveVariation(){ 332 return saveVariation; 333 } 334 335 public String getVariationURL(){ 336 return variationURL.toString(); 337 } 338 339 343 public void setVariationURL(String variationURL){ 344 this.variationURL = resolveURL(variationURL); 345 } 346 347 350 public void setCandidateReference(File candidateReference){ 351 this.candidateReference = candidateReference; 352 } 353 354 public File getCandidateReference(){ 355 return candidateReference; 356 } 357 358 362 public String getName(){ 363 if(this.name == null){ 364 return svgURL.toString(); 365 } 366 return name; 367 } 368 369 374 public TestReport run() { 375 DefaultTestReport report = new DefaultTestReport(this); 376 377 if (candidateReference != null){ 381 if (candidateReference.exists()){ 382 candidateReference.delete(); 383 } 384 } 385 386 387 File tmpFile = null; 392 393 try{ 394 if (candidateReference != null) 395 tmpFile = candidateReference; 396 else 397 tmpFile = File.createTempFile(TEMP_FILE_PREFIX, 398 TEMP_FILE_SUFFIX, 399 null); 400 }catch(IOException e){ 401 report.setErrorCode(ERROR_CANNOT_CREATE_TEMP_FILE); 402 report.setDescription(new TestReport.Entry[] { 403 new TestReport.Entry 404 (Messages.formatMessage(ENTRY_KEY_ERROR_DESCRIPTION, null), 405 Messages.formatMessage(ERROR_CANNOT_CREATE_TEMP_FILE, 406 new Object []{e.getMessage()})) 407 }); 408 report.setPassed(false); 409 return report; 410 } 411 412 413 FileOutputStream tmpFileOS = null; 414 415 try{ 416 tmpFileOS = new FileOutputStream (tmpFile); 417 }catch(IOException e){ 418 report.setErrorCode(ERROR_CANNOT_CREATE_TEMP_FILE_STREAM); 419 report.setDescription(new TestReport.Entry[] { 420 new TestReport.Entry 421 (Messages.formatMessage(ENTRY_KEY_ERROR_DESCRIPTION, null), 422 Messages.formatMessage(ERROR_CANNOT_CREATE_TEMP_FILE_STREAM, 423 new String []{tmpFile.getAbsolutePath(), 424 e.getMessage()})) }); 425 report.setPassed(false); 426 tmpFile.deleteOnExit(); 427 return report; 428 } 429 430 { 434 TestReport encodeTR = encode(svgURL, tmpFileOS); 435 if ((encodeTR != null) && 436 (encodeTR.hasPassed() == false)) { 437 tmpFile.deleteOnExit(); 438 return encodeTR; 439 } 440 } 441 442 InputStream refStream = null; 446 InputStream newStream = null; 447 try { 448 refStream = new BufferedInputStream (refImgURL.openStream()); 449 }catch(IOException e){ 450 report.setErrorCode(ERROR_CANNOT_OPEN_REFERENCE_IMAGE); 451 report.setDescription(new TestReport.Entry[]{ 452 new TestReport.Entry 453 (Messages.formatMessage(ENTRY_KEY_ERROR_DESCRIPTION, null), 454 Messages.formatMessage(ERROR_CANNOT_OPEN_REFERENCE_IMAGE, 455 new Object []{refImgURL.toString(), 456 e.getMessage()})) 457 }); 458 report.setPassed(false); 459 if (candidateReference == null){ 461 tmpFile.delete(); 462 } 463 return report; 464 } 465 466 try{ 467 newStream = new BufferedInputStream (new FileInputStream (tmpFile)); 468 }catch(IOException e){ 469 report.setErrorCode(ERROR_CANNOT_OPEN_GENERATED_IMAGE); 470 report.setDescription(new TestReport.Entry[]{ 471 new TestReport.Entry 472 (Messages.formatMessage(ENTRY_KEY_ERROR_DESCRIPTION, null), 473 Messages.formatMessage(ERROR_CANNOT_OPEN_GENERATED_IMAGE, 474 new Object []{tmpFile.getAbsolutePath(), 475 e.getMessage()}))}); 476 report.setPassed(false); 477 tmpFile.delete(); 478 return report; 479 } 480 481 boolean accurate = false; 482 try{ 483 accurate = compare(refStream, newStream); 484 } catch(IOException e) { 485 report.setErrorCode(ERROR_ERROR_WHILE_COMPARING_FILES); 486 report.setDescription(new TestReport.Entry[]{ 487 new TestReport.Entry 488 (Messages.formatMessage(ENTRY_KEY_ERROR_DESCRIPTION, null), 489 Messages.formatMessage(ERROR_ERROR_WHILE_COMPARING_FILES, 490 new Object []{refImgURL.toString(), 491 tmpFile.getAbsolutePath(), 492 e.getMessage()}))}); 493 report.setPassed(false); 494 if (candidateReference == null){ 495 tmpFile.delete(); 496 } 497 return report; 498 } 499 500 501 if(accurate){ 502 report.setPassed(true); 506 tmpFile.delete(); 507 return report; 508 } 509 510 try { 516 BufferedImage ref = getImage(refImgURL); 517 BufferedImage gen = getImage(tmpFile); 518 BufferedImage diff = buildDiffImage(ref, gen); 519 520 if(variationURL != null) { 525 File tmpDiff = imageToFile(diff, IMAGE_TYPE_DIFF); 526 527 InputStream variationURLStream = null; 528 try{ 529 variationURLStream = variationURL.openStream(); 530 }catch(IOException e){ 531 System.err.println(Messages.formatMessage(COULD_NOT_OPEN_VARIATION_URL, 533 new Object []{variationURL.toString()})); 534 } 535 536 if(variationURLStream != null){ 537 InputStream refDiffStream = 538 new BufferedInputStream (variationURLStream); 539 540 InputStream tmpDiffStream = 541 new BufferedInputStream (new FileInputStream (tmpDiff)); 542 543 if(compare(refDiffStream, tmpDiffStream)){ 544 accurate = true; 546 } 547 } 548 } 549 550 if (accurate) { 551 report.setPassed(true); 555 tmpFile.delete(); 556 return report; 557 } 558 559 System.err.println(">>>>>>>>>>>>>>>>>>>>>> "+ 560 "Rendering is not accurate"); 561 if(saveVariation != null){ 562 saveImage(diff, saveVariation); 566 } 567 568 BufferedImage cmp = makeCompareImage(ref, gen); 573 File cmpFile = imageToFile(cmp, IMAGE_TYPE_COMPARISON); 574 File diffFile = imageToFile(diff, IMAGE_TYPE_DIFF); 575 576 report.setErrorCode(ERROR_SVG_RENDERING_NOT_ACCURATE); 577 report.setDescription(new TestReport.Entry[]{ 578 new TestReport.Entry 579 (Messages.formatMessage(ENTRY_KEY_ERROR_DESCRIPTION, null), 580 Messages.formatMessage(ERROR_SVG_RENDERING_NOT_ACCURATE, null)), 581 new TestReport.Entry 582 (Messages.formatMessage(ENTRY_KEY_REFERENCE_GENERATED_IMAGE_URI, 583 null), cmpFile), 584 new TestReport.Entry 585 (Messages.formatMessage(ENTRY_KEY_DIFFERENCE_IMAGE, null), 586 diffFile) }); 587 }catch(Exception e){ 588 report.setErrorCode(ERROR_SVG_RENDERING_NOT_ACCURATE); 589 StringWriter trace = new StringWriter (); 590 e.printStackTrace(new PrintWriter (trace)); 591 592 report.setDescription(new TestReport.Entry[]{ 593 new TestReport.Entry 594 (Messages.formatMessage(ENTRY_KEY_ERROR_DESCRIPTION, null), 595 Messages.formatMessage(ERROR_SVG_RENDERING_NOT_ACCURATE, null)), 596 new TestReport.Entry 597 (Messages.formatMessage(ENTRY_KEY_INTERNAL_ERROR, null), 598 Messages.formatMessage(COULD_NOT_GENERATE_COMPARISON_IMAGES, 599 new Object []{e.getClass().getName(), 600 e.getMessage(), 601 trace.toString()})) }); 602 } 603 604 if (candidateReference == null){ 605 tmpFile.delete(); 606 } 607 608 report.setPassed(false); 609 return report; 610 } 611 612 public abstract TestReport encode(URL srcURL, FileOutputStream fos); 613 614 617 protected boolean compare(InputStream refStream, 618 InputStream newStream) 619 throws IOException { 620 int b, nb; 621 do { 622 b = refStream.read(); 623 nb = newStream.read(); 624 } while (b != -1 && nb != -1 && b == nb); 625 refStream.close(); 626 newStream.close(); 627 return (b == nb); 628 } 629 630 633 protected void saveImage(BufferedImage img, File imgFile) 634 throws IOException { 635 if(!imgFile.exists()){ 636 imgFile.createNewFile(); 637 } 638 saveImage(img, new FileOutputStream (imgFile)); 639 } 640 641 644 protected void saveImage(BufferedImage img, OutputStream os) 645 throws IOException { 646 PNGImageEncoder encoder = new PNGImageEncoder 647 (os, PNGEncodeParam.getDefaultEncodeParam(img)); 648 649 encoder.encode(img); 650 } 651 652 656 public static BufferedImage buildDiffImage(BufferedImage ref, 657 BufferedImage gen) { 658 BufferedImage diff = new BufferedImage (ref.getWidth(), 659 ref.getHeight(), 660 BufferedImage.TYPE_INT_ARGB); 661 WritableRaster refWR = ref.getRaster(); 662 WritableRaster genWR = gen.getRaster(); 663 WritableRaster dstWR = diff.getRaster(); 664 665 boolean refPre = ref.isAlphaPremultiplied(); 666 if (!refPre) { 667 ColorModel cm = ref.getColorModel(); 668 cm = GraphicsUtil.coerceData(refWR, cm, true); 669 ref = new BufferedImage (cm, refWR, true, null); 670 } 671 boolean genPre = gen.isAlphaPremultiplied(); 672 if (!genPre) { 673 ColorModel cm = gen.getColorModel(); 674 cm = GraphicsUtil.coerceData(genWR, cm, true); 675 gen = new BufferedImage (cm, genWR, true, null); 676 } 677 678 679 int w=ref.getWidth(); 680 int h=ref.getHeight(); 681 int y, i,val; 682 int [] refPix = null; 683 int [] genPix = null; 684 for (y=0; y<h; y++) { 685 refPix = refWR.getPixels (0, y, w, 1, refPix); 686 genPix = genWR.getPixels (0, y, w, 1, genPix); 687 for (i=0; i<refPix.length; i++) { 688 val = ((genPix[i]-refPix[i])*10)+128; 689 if ((val & 0xFFFFFF00) != 0) 690 if ((val & 0x80000000) != 0) val = 0; 691 else val = 255; 692 genPix[i] = val; 693 } 694 dstWR.setPixels(0, y, w, 1, genPix); 695 } 696 697 if (!genPre) { 698 ColorModel cm = gen.getColorModel(); 699 cm = GraphicsUtil.coerceData(genWR, cm, false); 700 } 701 702 if (!refPre) { 703 ColorModel cm = ref.getColorModel(); 704 cm = GraphicsUtil.coerceData(refWR, cm, false); 705 } 706 707 return diff; 708 } 709 710 713 protected BufferedImage getImage(File file) 714 throws Exception { 715 return getImage(file.toURL()); 716 } 717 718 721 protected BufferedImage getImage(URL url) 722 throws IOException { 723 ImageTagRegistry reg = ImageTagRegistry.getRegistry(); 724 Filter filt = reg.readURL(new ParsedURL(url)); 725 if(filt == null) 726 throw new IOException (Messages.formatMessage 727 (COULD_NOT_LOAD_IMAGE, 728 new Object []{url.toString()})); 729 730 RenderedImage red = filt.createDefaultRendering(); 731 if(red == null) 732 throw new IOException (Messages.formatMessage 733 (COULD_NOT_LOAD_IMAGE, 734 new Object []{url.toString()})); 735 736 BufferedImage img = new BufferedImage (red.getWidth(), 737 red.getHeight(), 738 BufferedImage.TYPE_INT_ARGB); 739 red.copyData(img.getRaster()); 740 741 return img; 742 } 743 744 747 protected BufferedImage makeCompareImage(BufferedImage ref, 748 BufferedImage gen){ 749 BufferedImage cmp = new BufferedImage (ref.getWidth()*2, 750 ref.getHeight(), 751 BufferedImage.TYPE_INT_ARGB); 752 753 Graphics2D g = cmp.createGraphics(); 754 g.setPaint(Color.white); 755 g.fillRect(0, 0, cmp.getWidth(), cmp.getHeight()); 756 g.drawImage(ref, 0, 0, null); 757 g.translate(ref.getWidth(), 0); 758 g.drawImage(gen, 0, 0, null); 759 g.dispose(); 760 761 return cmp; 762 } 763 764 772 protected File imageToFile(BufferedImage img, 773 String imageType) 774 throws IOException { 775 String file = getURLFile(svgURL); 776 777 File imageFile = null; 778 if( !"".equals(file) ){ 779 imageFile = makeTempFileName(file, imageType); 780 } 781 else{ 782 imageFile = makeRandomFileName(imageType); 783 } 784 785 imageFile.deleteOnExit(); 786 787 PNGImageEncoder encoder = new PNGImageEncoder 788 (new FileOutputStream (imageFile), 789 PNGEncodeParam.getDefaultEncodeParam(img)); 790 791 encoder.encode(img); 792 793 return imageFile; 794 } 795 796 799 protected String getURLFile(URL url){ 800 String path = url.getPath(); 801 int n = path.lastIndexOf('/'); 802 if(n == -1){ 803 return path; 804 } 805 else{ 806 if(n<path.length()){ 807 return path.substring(n+1, path.length()); 808 } 809 else{ 810 return ""; 811 } 812 } 813 } 814 815 protected File makeTempFileName(String svgFileName, 816 String imageType){ 817 int dotIndex = svgFileName.lastIndexOf('.'); 818 if( dotIndex == -1){ 819 return getNextTempFileName(svgFileName + imageType); 820 } 821 else{ 822 return getNextTempFileName 823 (svgFileName.substring(0, dotIndex) + 824 imageType + IMAGE_FILE_EXTENSION); 825 } 826 } 827 828 protected File getNextTempFileName(String fileName){ 829 File f = new File (getTempDirectory(), fileName); 830 if(!f.exists()){ 831 return f; 832 } 833 else{ 834 return getNextTempFileName(fileName, 835 1); 836 } 837 } 838 839 protected File getNextTempFileName(String fileName, 840 int instance){ 841 int n = fileName.lastIndexOf('.'); 843 String iFileName = fileName + instance; 844 if(n != -1){ 845 iFileName = fileName.substring(0, n) + instance 846 + fileName.substring(n, fileName.length()); 847 } 848 849 File r = new File (getTempDirectory(), iFileName); 850 if(!r.exists()){ 851 return r; 852 } 853 else{ 854 return getNextTempFileName(fileName, 855 instance + 1); 856 } 857 } 858 859 863 protected File makeRandomFileName(String imageType) 864 throws IOException { 865 866 return File.createTempFile(TEMP_FILE_PREFIX, 867 TEMP_FILE_SUFFIX + imageType, 868 null); 869 } 870 } 871 | Popular Tags |