#author("2021-06-23T17:24:32+09:00","","")
[[SoftwareEngineering/ProgramLanguage/Java]]
#author("2021-06-23T17:39:21+09:00","","")
[[Java]]

* Selenium [#u6e8d3b3]
#contents

* ページ全体のスクリーンショットを取得する [#dd142f35]
** ソースコード [#y165c340]

*** Screenshot.java [#g008b76f]

#highlightjs(java)
 package org.codereign.selenium.util;
 
 import java.awt.Graphics;
 import java.awt.image.BufferedImage;
 import java.io.File;
 import java.io.IOException;
 import java.math.BigDecimal;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.ArrayList;
 import java.util.List;
 
 import javax.imageio.ImageIO;
 
 import org.codereign.selenium.web.ScrollBar;
 import org.openqa.selenium.OutputType;
 import org.openqa.selenium.TakesScreenshot;
 import org.openqa.selenium.WebDriver;
 
 public class Screenshot {
 
     private static final String CURRENT_DIRECTORY_PATH = System.getProperty("user.dir");
     private Path defaultSaveDirectory;
 
     public Screenshot() {
         this(Paths.get(CURRENT_DIRECTORY_PATH, "画面のハードコピー"));
     }
 
     public Screenshot(final String defaultSaveDirectory) {
         this(Paths.get(defaultSaveDirectory));
     }
 
     public Screenshot(Path defaultSaveDirectory) {
         this.defaultSaveDirectory = defaultSaveDirectory;
     }
 
     public File printScreen(WebDriver driver) throws IOException {
         final String fileName = "screenshot_"
                 + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd_HHmmssSSS")) + ".png";
 
         return printScreen(driver, fileName);
     }
 
     public File printScreen(WebDriver driver, final String fileName) throws IOException {
         // ---------------------------------------------------------
         // 事前準備
         // ---------------------------------------------------------
         TakesScreenshot takesScreenshot = (TakesScreenshot) driver;
         ScrollBar scrollbar = new ScrollBar(driver);
 
         // ---------------------------------------------------------
         // スクロールバーのスクロールボックスの位置を初期化する
         // ---------------------------------------------------------
         scrollbar.resetPageOffset();
 
         // ---------------------------------------------------------
         // 垂直方向にスクロールしながら画像を取得する
         // ---------------------------------------------------------
         List<BufferedImage> images = new ArrayList<BufferedImage>();
         int diff = 0;
 
         BigDecimal previousScrollY = BigDecimal.valueOf(-1);
         BigDecimal currentScrollY = scrollbar.getPageYOffset();
 
         while (previousScrollY.compareTo(currentScrollY) < 0) {
             File screenFile = takesScreenshot.getScreenshotAs(OutputType.FILE);
             BufferedImage scrapImage = ImageIO.read(screenFile);
             images.add(scrapImage);
 
             diff = currentScrollY.intValue() - previousScrollY.intValue();
 
             previousScrollY = currentScrollY;
             currentScrollY = scrollbar.moveScrollY(scrapImage.getHeight());
         }
 
         // ---------------------------------------------------------
         // 取得した画像をすべて結合する
         // ....結合後の画像の高さを算出する
         // ---------------------------------------------------------
         int totalHeight = 0;
         for (BufferedImage scrapImage : images) {
             totalHeight += scrapImage.getHeight();
         }
 
         // ---------------------------------------------------------
         // ....複数枚の場合、最後の 2 枚を重ね合わせる必要があるため
         // ....その結合後の画像の高さを調整する
         // ---------------------------------------------------------
         if (1 < images.size()) {
             BufferedImage lastImage = images.get(images.size() - 1);
             totalHeight -= (lastImage.getHeight() - diff);
         }
 
         // ---------------------------------------------------------
         // ....複数の画像を 1 枚の画像に結合する
         // ---------------------------------------------------------
         BufferedImage entireImage = unionImage(images, totalHeight);
 
         // ---------------------------------------------------------
         // 画像を保存する
         // ---------------------------------------------------------
         return saveImage(entireImage, fileName);
     }
 
     /**
      * 複数の画像を 1 枚の画像に結合します。
      * @param images
      * @param totalHeight
      * @return
      */
     protected BufferedImage unionImage(List<BufferedImage> images, final int totalHeight) {
         // ---------------------------------------------------------
         // 最初の 1 枚を取得する
         // ---------------------------------------------------------
         BufferedImage firstImage = images.get(0);
 
         // ---------------------------------------------------------
         // 結合用画像の描画領域を取得する
         // ---------------------------------------------------------
         BufferedImage entireImage = new BufferedImage(firstImage.getWidth(), totalHeight, BufferedImage.TYPE_INT_ARGB);
         Graphics graphics = entireImage.getGraphics();
 
         // ---------------------------------------------------------
         // 最初の 1 枚を結合用画像の描画領域に描画する
         // ---------------------------------------------------------
         graphics.drawImage(firstImage, 0, 0, null);
         int highWaterMark = firstImage.getHeight();
 
         // ---------------------------------------------------------
         // 2 枚目以降(最後の 1 枚を除く)を結合用画像の描画領域に描画する
         // ---------------------------------------------------------
         for (int index = 1; index < images.size() - 1; index++) {
             BufferedImage scrapImage = images.get(index);
 
             graphics.drawImage(scrapImage, 0, highWaterMark, null);
             highWaterMark += scrapImage.getHeight();
         }
 
         // ---------------------------------------------------------
         // 最後の 1 枚を結合用画像の描画領域に描画する
         // ....最後の 1 枚は今まで描画した領域と重なる箇所があることに注意
         // ---------------------------------------------------------
         if (1 < images.size()) {
             BufferedImage lastImage = images.get(images.size() - 1);
             graphics.drawImage(lastImage, 0, totalHeight - lastImage.getHeight(), null);
         }
 
         // ---------------------------------------------------------
         // 結合用画像を返却する
         // ---------------------------------------------------------
         return entireImage;
     }
 
     /**
      * 画像を保存します。
      * @param bufferedImage
      * @param fileName
      * @return
      * @throws IOException
      */
     protected File saveImage(BufferedImage bufferedImage, final String fileName) throws IOException {
         if (Files.notExists(defaultSaveDirectory)) {
             Files.createDirectories(defaultSaveDirectory);
         }
 
         File file = new File(defaultSaveDirectory.toString(), fileName);
         ImageIO.write(bufferedImage, "png", file);
 
         System.out.println("スクリーンショットを保存しました。[" + file.getAbsolutePath() + "]");
 
         return file;
     }
 
 }

*** ScrollBar.java [#k8522f2b]

#highlightjs(java)
 package org.codereign.selenium.web;
 
 import java.math.BigDecimal;
 import java.text.MessageFormat;
 
 import org.openqa.selenium.JavascriptExecutor;
 import org.openqa.selenium.WebDriver;
 
 public class ScrollBar {
 
     private final JavascriptExecutor executor;
     private final MessageFormat scrollTo = new MessageFormat("scrollTo({0}, {1});");
     private final MessageFormat scrollBy = new MessageFormat("scrollBy({0}, {1});");
     private final MessageFormat pageYOffset = new MessageFormat("return String(window.pageYOffset);");
 
     /**
      * 指定された {@code JavascriptExecutor} を持つ、新しい {@code ScrollBar} オブジェクトを構築します。
      * @param driver selenium web driver
      */
     public ScrollBar(WebDriver driver) {
         this.executor = (JavascriptExecutor) driver;
     }
 
     /**
      * 指定された {@code JavascriptExecutor} を持つ、新しい {@code ScrollBar} オブジェクトを構築します。
      * @param driver selenium javascript executor
      */
     public ScrollBar(JavascriptExecutor executor) {
         this.executor = executor;
     }
 
     /**
      * スクロールバーのスクロールボックスの位置を初期化します。<br>
      * 垂直スクロールバーのスクロールボックスは一番上<br>
      * 水平スクロールバーのスクロールボックスは左端<br>
      */
     public void resetPageOffset() {
         final Object arguments = new Object[] { 0, 0 };
         executor.executeScript(scrollTo.format(arguments));
     }
 
     /**
      * 垂直スクロールバーのスクロールボックスの位置を初期化します。
      * @return 垂直スクロールバーのスクロールボックスの位置
      */
     public BigDecimal getPageYOffset() {
         final Object arguments = new Object[] {};
         final String statement = pageYOffset.format(arguments);
 
         String pageYOffset = (String) executor.executeScript(statement);
         return stringToBigDecimal(pageYOffset);
     }
 
     /**
      * 垂直スクロールバーのスクロールボックスの位置を移動します。
      * @param y 現在の垂直スクロールバーのスクロールボックスの位置からの移動量
      * @return 移動後の垂直スクロールバーのスクロールボックスの位置
      */
     public BigDecimal moveScrollY(int y) {
         final Object arguments = new Object[] { 0, y };
 
         executor.executeScript(scrollBy.format(arguments));
         return getPageYOffset();
     }
 
     /**
      * 文字列を {@code BigDecimal} 型に変換して返却します。
      * 変換できない場合は、[@code null} を返却します。
      * @param value 変換する文字列
      * @return [{@code BigDecimal} 型の値
      */
     private BigDecimal stringToBigDecimal(final String value) {
 
         try {
             return new BigDecimal(value);
         } catch (NumberFormatException e) {
             return null;
         }
     }
 
 }

トップ   差分 履歴 リロード   一覧 検索 最終更新   ヘルプ   最終更新のRSS