ImageUtils { public static BufferedImage verticalMerge(List<BufferedImage> images) { int totalHeight = 0; int totalWidth = -1; for (BufferedImage image : images) { totalHeight += image.getHeight(); if (totalWidth < 0) { totalWidth = image.getWidth(); } } LOG.trace("(VerticalMerge) new image[{}, {}]", totalWidth, totalHeight); BufferedImage screenshot = new BufferedImage(totalWidth, totalHeight, BufferedImage.TYPE_INT_RGB); Graphics graphics = screenshot.getGraphics(); int nextTop = 0; for (BufferedImage image : images) { graphics.drawImage(image, 0, nextTop, null); nextTop += image.getHeight(); } return screenshot; } private  ImageUtils(); static ImageComparedResult compare(BufferedImage image1, Rectangle imageArea1, BufferedImage image2,
			Rectangle imageArea2, CompareOption[] options); static boolean isContained(BufferedImage entireImage, BufferedImage partImage); static double[][] calcIntegralImage(BufferedImage source); static boolean imageEquals(BufferedImage image1, BufferedImage image2); static BufferedImage getMaskedImage(BufferedImage image, List<Rectangle> maskAreas); static BufferedImage getMarkedImage(BufferedImage image, DiffPoints diffPoints); static BufferedImage getDiffImage(BufferedImage leftImage, BufferedImage rightImage, DiffPoints diffPoints); static BufferedImage trim(BufferedImage image, int trimTop, int trimLeft, int trimBottom, int trimRight); static BufferedImage verticalMerge(List<BufferedImage> images); static BufferedImage merge(List<List<BufferedImage>> images); static int[] getRGB(BufferedImage image, int width, int height); static int[] toARGB(int pixel); static int toPixel(int[] argb); static int toPixel(int r, int g, int b); static int toPixel(int a, int r, int g, int b); static int detectBackgroundColor(BufferedImage b); static boolean getObjectRectangle(BufferedImage image, Rectangle rectangle); static double norm(int pixel1, int pixel2); static double[] countSubpixel(BufferedImage bimage); static void removeRedundantRectangles(List<Rectangle> rectangles, int xLimit, int yLimit); static void removeOverlappingRectangles(List<Rectangle> rectangles); static void reshapeRect(Rectangle rectangle, int xLimit, int yLimit); static Rectangle getTightDiffArea(Rectangle rectangle, int xLimit, int yLimit); static List<Rectangle> convertObjectGroupsToAreas(List<ObjectGroup> objectGroups); static List<ObjectGroup> convertDiffPointsToObjectGroups(DiffPoints DP, int group_distance); static BufferedImage getSubImage(BufferedImage image, Rectangle rectangle); static Offset findDominantOffset(BufferedImage expectedImage, BufferedImage actualImage, double diffThreshold); static BufferedImage getDominantImage(BufferedImage expectedImage, BufferedImage actualImage, Offset offset); static int getSizeRelationType(int expectedWidth, int expectedHeight, int actualWidth, int actualHeight);  }
@Test public void testVerticalMerge() throws Exception { List<BufferedImage> images = new ArrayList<BufferedImage>(); images.add(ImageIO.read(getClass().getResource("hifive_logo.png"))); images.add(ImageIO.read(getClass().getResource("hifive_logo.png"))); BufferedImage expected = ImageIO.read(getClass().getResource("ImageUtilsTest_vertical_merge.png")); BufferedImage actual = ImageUtils.verticalMerge(images); assertThat(ImageUtils.imageEquals(expected, actual), is(true)); }