You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

BitmapComparator.java 7.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. /*
  2. * Copyright 1999-2005 The Apache Software Foundation.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /* $Id$ */
  17. package org.apache.fop.visual;
  18. import java.awt.Color;
  19. import java.awt.Graphics2D;
  20. import java.awt.image.BufferedImage;
  21. import java.awt.image.ColorModel;
  22. import java.awt.image.RenderedImage;
  23. import java.awt.image.WritableRaster;
  24. import java.io.File;
  25. import java.io.IOException;
  26. import java.io.InputStream;
  27. import java.net.URL;
  28. import org.apache.batik.ext.awt.image.GraphicsUtil;
  29. import org.apache.batik.ext.awt.image.renderable.Filter;
  30. import org.apache.batik.ext.awt.image.spi.ImageTagRegistry;
  31. import org.apache.batik.util.ParsedURL;
  32. import org.apache.commons.io.IOUtils;
  33. /**
  34. * Helper class to visually compare two bitmap images.
  35. * <p>
  36. * This class was created by extracting reusable code from
  37. * org.apache.batik.test.util.ImageCompareText (Apache Batik)
  38. * into this separate class.
  39. * <p>
  40. * TODO Move as utility class to XML Graphics Commons when possible
  41. */
  42. public class BitmapComparator {
  43. /**
  44. * Builds a new BufferedImage that is the difference between the two input images
  45. * @param ref the reference bitmap
  46. * @param gen the newly generated bitmap
  47. * @return the diff bitmap
  48. */
  49. public static BufferedImage buildDiffImage(BufferedImage ref,
  50. BufferedImage gen) {
  51. BufferedImage diff = new BufferedImage(ref.getWidth(),
  52. ref.getHeight(),
  53. BufferedImage.TYPE_INT_ARGB);
  54. WritableRaster refWR = ref.getRaster();
  55. WritableRaster genWR = gen.getRaster();
  56. WritableRaster dstWR = diff.getRaster();
  57. boolean refPre = ref.isAlphaPremultiplied();
  58. if (!refPre) {
  59. ColorModel cm = ref.getColorModel();
  60. cm = GraphicsUtil.coerceData(refWR, cm, true);
  61. ref = new BufferedImage(cm, refWR, true, null);
  62. }
  63. boolean genPre = gen.isAlphaPremultiplied();
  64. if (!genPre) {
  65. ColorModel cm = gen.getColorModel();
  66. cm = GraphicsUtil.coerceData(genWR, cm, true);
  67. gen = new BufferedImage(cm, genWR, true, null);
  68. }
  69. int w = ref.getWidth();
  70. int h = ref.getHeight();
  71. int y, i, val;
  72. int [] refPix = null;
  73. int [] genPix = null;
  74. for (y = 0; y < h; y++) {
  75. refPix = refWR.getPixels (0, y, w, 1, refPix);
  76. genPix = genWR.getPixels (0, y, w, 1, genPix);
  77. for (i = 0; i < refPix.length; i++) {
  78. // val = ((genPix[i] - refPix[i]) * 5) + 128;
  79. val = ((refPix[i] - genPix[i]) * 10) + 128;
  80. if ((val & 0xFFFFFF00) != 0) {
  81. if ((val & 0x80000000) != 0) {
  82. val = 0;
  83. } else {
  84. val = 255;
  85. }
  86. }
  87. genPix[i] = val;
  88. }
  89. dstWR.setPixels(0, y, w, 1, genPix);
  90. }
  91. if (!genPre) {
  92. ColorModel cm = gen.getColorModel();
  93. cm = GraphicsUtil.coerceData(genWR, cm, false);
  94. }
  95. if (!refPre) {
  96. ColorModel cm = ref.getColorModel();
  97. cm = GraphicsUtil.coerceData(refWR, cm, false);
  98. }
  99. return diff;
  100. }
  101. /**
  102. * Builds a combined image that places a number of images next to each other for
  103. * manual, visual comparison.
  104. * @param images the array of bitmaps
  105. * @return the combined image
  106. */
  107. public static BufferedImage buildCompareImage(BufferedImage[] images) {
  108. BufferedImage cmp = new BufferedImage(
  109. images[0].getWidth() * images.length,
  110. images[0].getHeight(), BufferedImage.TYPE_INT_ARGB);
  111. Graphics2D g = cmp.createGraphics();
  112. g.setPaint(Color.white);
  113. g.fillRect(0, 0, cmp.getWidth(), cmp.getHeight());
  114. int lastWidth = 0;
  115. for (int i = 0; i < images.length; i++) {
  116. if (lastWidth > 0) {
  117. g.translate(lastWidth, 0);
  118. }
  119. if (images[i] != null) {
  120. g.drawImage(images[i], 0, 0, null);
  121. lastWidth = images[i].getWidth();
  122. } else {
  123. lastWidth = 20; //Maybe add a special placeholder image instead later
  124. }
  125. }
  126. g.dispose();
  127. return cmp;
  128. }
  129. /**
  130. * Builds a combined image that places two images next to each other for
  131. * manual, visual comparison.
  132. * @param ref the reference image
  133. * @param gen the actual image
  134. * @return the combined image
  135. */
  136. public static BufferedImage buildCompareImage(BufferedImage ref,
  137. BufferedImage gen) {
  138. return buildCompareImage(new BufferedImage[] {ref, gen});
  139. }
  140. /**
  141. * Loads an image from a URL
  142. * @param url the URL to the image
  143. * @return the bitmap as BufferedImage
  144. * TODO This method doesn't close the InputStream opened by the URL.
  145. */
  146. public static BufferedImage getImage(URL url) {
  147. ImageTagRegistry reg = ImageTagRegistry.getRegistry();
  148. Filter filt = reg.readURL(new ParsedURL(url));
  149. if (filt == null) {
  150. return null;
  151. }
  152. RenderedImage red = filt.createDefaultRendering();
  153. if (red == null) {
  154. return null;
  155. }
  156. BufferedImage img = new BufferedImage(red.getWidth(),
  157. red.getHeight(),
  158. BufferedImage.TYPE_INT_ARGB);
  159. red.copyData(img.getRaster());
  160. return img;
  161. }
  162. /**
  163. * Loads an image from a URL
  164. * @param bitmapFile the bitmap file
  165. * @return the bitmap as BufferedImage
  166. */
  167. public static BufferedImage getImage(File bitmapFile) {
  168. try {
  169. InputStream in = new java.io.FileInputStream(bitmapFile);
  170. try {
  171. in = new java.io.BufferedInputStream(in);
  172. ImageTagRegistry reg = ImageTagRegistry.getRegistry();
  173. Filter filt = reg.readStream(in);
  174. if (filt == null) {
  175. return null;
  176. }
  177. RenderedImage red = filt.createDefaultRendering();
  178. if (red == null) {
  179. return null;
  180. }
  181. BufferedImage img = new BufferedImage(red.getWidth(),
  182. red.getHeight(),
  183. BufferedImage.TYPE_INT_ARGB);
  184. red.copyData(img.getRaster());
  185. return img;
  186. } finally {
  187. IOUtils.closeQuietly(in);
  188. }
  189. } catch (IOException e) {
  190. return null;
  191. }
  192. }
  193. }