Notes開発者のためのXPagesデザインレシピ

簡単でCoolなXPagesアプリケーションを作るための情報を発信していきます

コーディング

画像リサイズ機能をJavaエージェントにしよう

はじめに

前回作成したXPages用画像リサイズ機能をJavaエージェントに書き換えて、Notesクライアントから使えるようにしたいと思います。SSJSをJavaに書き換える注意点としては、Javaのメソッド、記述方法に準拠して、なるべく短く、簡潔に書き換えることです。XPagesからインポートしていたJavaクラスはそのまま使えます。


エージェントを作成する

まず、Javaエージェントを作成します。
注意点は、実行権限です。サーバー上に作成した縮小画像ファイルを削除する必要がありますので、「フルアドミニストレータ権限」でエージェントが実行されるように設定します。

1.「コード>エージェント」を選択し、[新規エージェント]ボタンで「ResizeImage」を作成する。

名前

ResizeImage

コメント

 

タイプ

Java

2.プロパティの基本タブで、エージェントの実行タイミングを設定する。

基本

実行時

イベント

   

文書の作成後または変更後

3.プロパティのセキュリティタブで、エージェントのセキュリティレベルを設定する

セキュリティ

実行時のセキュリティレベル

3.フルアドミニストレータ権限で制限された操作を許可する


エージェントの全体構成

作成する関数は下記の4つです。

 ①

メイン関数    

UnprocessedDocumentsで取得した文書をループし、処理後updateProcessedDocで処理済みマークをつける

リサイズ必要性判定関数

1MB以上ならリサイズが必要とし、trueを返す

画像ファイル判定関数

ファイル名の拡張子を取得し、画像ファイルの場合、trueを返す

リサイズ関数

リサイズ必要性判定関数、イメージファイル判定関数でリサイズ処理の必要性を判定後、サーバーローカルにリサイズ画像を保存、リッチテキストに再添付


メイン関数を作成する

メイン関数では、getUnprocessedDocuments()を使って、処理対象文書を取得し、リサイズ処理を行った文書は保存処理を行い、処理済みであることを示すためにupdateProcessedDoc(doc)を実行します。

【メイン関数】※import文、AgentBase部分省略

    public void NotesMain() {
      try {
          Session session = getSession();
          AgentContext agentContext = session.getAgentContext();
          // 未処理の文書を取得
          DocumentCollection dc = agentContext.getUnprocessedDocuments();
          System.out.println("リサイズエージェント実行 - 対象文書数:" + dc.getCount());
          
          // 未処理文書をループで処理
          Document doc = dc.getFirstDocument();
          while (doc != null) {
              boolean result = resizeImage(doc);                                    //リサイズ
              if(result){                                                           //リサイズした場合保存
                  doc.save();
              }
              agentContext.updateProcessedDoc(doc);                             //処理済みマーク
              doc = dc.getNextDocument(doc);
          }
          
      } catch(Exception e) {
          e.printStackTrace();
      }
    }


画像ファイル判定、リサイズ必要性判定関数を作成する

画像ファイル判定関数では、引数で渡されたファイル名から拡張子を抽出し、画像ファイルの拡張子であれば、trueを返します。

【画像ファイル判定関数】

    /*
     * 画像ファイル判定(拡張子が画像の場合、true)
     */
    private boolean isImageFile(String fileName) {
        // 画像ファイルの拡張子リストを作成
        String[] imageExtensions = { ".jpg", ".jpeg", ".png", ".gif", ".bmp" };
        
        // ファイル名から拡張子を抽出する
        int dotIndex = fileName.lastIndexOf(".");
        String fileExtension = "";
        if(dotIndex >= 0){
            fileExtension = fileName.substring(dotIndex).toLowerCase();
        }
        // 拡張子が画像ファイルの拡張子リストに含まれているかを確認する
        return Arrays.asList(imageExtensions).contains(fileExtension);
    }

リサイズ必要性判定関数は、引数で渡されたファイルサイズ(byte)が1MBを超えていた場合、trueを返します。

【リサイズ必要性判定関数】

    /*
     * リサイズ対象判定(1MB以上のファイルサイズでtrue)
     */
    private boolean isResize(long fileSize) {
        long TARGET_SIZE = 1048576;             //1MB
        return fileSize >= TARGET_SIZE;
    }  


画像リサイズ関数を作成する

画像リサイズ関数では、引数で渡された文書から対象のリッチテキストフィールドを取得し、ファイルごとに拡張子とファイルサイズからリサイズ対象か?を判定し、画像ファイルをリサイズ後、再添付します。

【画像リサイズ関数】

    /*
     * 文書に保存された画像ファイルをリサイズし、再添付する
     *  引数    :doc-現在の文書
     *  戻り値  :false-画像圧縮せず終了
     */    
    private boolean resizeImage(Document doc) throws NotesException {
        // リッチテキストフィールドを取得(添付ファイルを消すとリッチテキストフィールド自体が消えるので、nullの場合は処理を終了)
        RichTextItem richTextField = (RichTextItem)doc.getFirstItem("ImageBody");
        if (richTextField == null) {
            return false;
        }
        
        // リッチテキストフィールドからファイルオブジェクトを取得
        Vector files = richTextField.getEmbeddedObjects();
        if (files.isEmpty()) {
            return false;
        } else {
            boolean resizeFlg = false;                  //リサイズ実行フラグ
            Enumeration file = files.elements();
            while (file.hasMoreElements()) {
                EmbeddedObject eobj = (EmbeddedObject)file.nextElement();
                String fileName = eobj.getName();
              
                // 画像ファイル判定(画像以外は何もしない)
                if (!isImageFile(fileName)) {
                    continue;
                }
                // ファイルサイズ判定(小さすぎるファイルは何もしない)
                if (!isResize(eobj.getFileSize())) {
                    continue;
                }
                // リッチテキストからファイルを取得
                java.io.InputStream fileData = eobj.getInputStream();
                // 縮小率(元画像の30%のサイズに縮小する)
                int scalePercent = 30;
                // ファイルオブジェクトがnullでない場合、処理を行う
                if (fileData != null) {
                    try{
                        // オリジナル画像を読み込む
                        java.awt.Image originalImage = javax.imageio.ImageIO.read(fileData);
    
                        // 縮小後の画像の幅と高さを計算
                        int newWidth = originalImage.getWidth(null) * scalePercent / 100;
                        int newHeight = originalImage.getHeight(null) * scalePercent / 100;
    
                        // 縮小後の画像を作成
                        java.awt.Image scaledImage = originalImage.getScaledInstance(newWidth, newHeight, java.awt.Image.SCALE_SMOOTH);
                        BufferedImage resizedImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
                        Graphics2D g = resizedImage.createGraphics();
                        g.drawImage(scaledImage, 0, 0, null);
                        g.dispose();
    
                        // ファイルを保存するためのOutputStreamを作成
                        String tmpFolder = "c:\\tmp\\";
                        FileOutputStream outputStream = new FileOutputStream(tmpFolder + fileName);
    
                        // JPEG形式で保存
                        javax.imageio.ImageIO.write(resizedImage, "jpg", outputStream);
    
                        // ストリームをクローズ
                        outputStream.close();
                        fileData.close();
    
                        // 既存の添付ファイルを削除
                        eobj.remove();
    
                        // リサイズした画像をアップロード
                        richTextField.embedObject(lotus.domino.EmbeddedObject.EMBED_ATTACHMENT, "", tmpFolder + fileName, "");
    
                        // リサイズした画像を削除
                        java.io.File deleteFile = new java.io.File(tmpFolder + fileName);
                        if (deleteFile.exists()) {
                            deleteFile.delete();
                        }
                        // for debug
                        System.out.println("resize done:" + fileName);
                        resizeFlg = true;
                        
                    }catch(IOException e){
                        e.printStackTrace();
                    }
                }                 
            }
            return resizeFlg;
        }           
        
    }


エージェント全体

こちらがimportを含むJavaエージェントの全貌になります。
デバッグ用のprint文は検証後、削除して下さい。

import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Vector;
import lotus.domino.*;

public class JavaAgent extends AgentBase {
    public void NotesMain() {
      try {
          Session session = getSession();
          AgentContext agentContext = session.getAgentContext();
          // 未処理の文書を取得
          DocumentCollection dc = agentContext.getUnprocessedDocuments();
          System.out.println("リサイズエージェント実行 - 対象文書数:" + dc.getCount());
          
          // 未処理文書をループで処理
          Document doc = dc.getFirstDocument();
          while (doc != null) {
              boolean result = resizeImage(doc);                                    //リサイズ
              if(result){                                                           //リサイズした場合保存
                  doc.save();
              }
              agentContext.updateProcessedDoc(doc);                             //処理済みマーク
              doc = dc.getNextDocument(doc);
          }
          
      } catch(Exception e) {
          e.printStackTrace();
      }
    }
    
    /*
     * 文書に保存された画像ファイルをリサイズし、再添付する
     *  引数    :doc-現在の文書
     *  戻り値  :false-画像圧縮せず終了
     */    
    private boolean resizeImage(Document doc) throws NotesException {
        // リッチテキストフィールドを取得(添付ファイルを消すとリッチテキストフィールド自体が消えるので、nullの場合は処理を終了)
        RichTextItem richTextField = (RichTextItem)doc.getFirstItem("ImageBody");
        if (richTextField == null) {
            return false;
        }
        
        // リッチテキストフィールドからファイルオブジェクトを取得
        Vector files = richTextField.getEmbeddedObjects();
        if (files.isEmpty()) {
            return false;
        } else {
            boolean resizeFlg = false;                  //リサイズ実行フラグ
            Enumeration file = files.elements();
            while (file.hasMoreElements()) {
                EmbeddedObject eobj = (EmbeddedObject)file.nextElement();
                String fileName = eobj.getName();
              
                // 画像ファイル判定(画像以外は何もしない)
                if (!isImageFile(fileName)) {
                    continue;
                }
                // ファイルサイズ判定(小さすぎるファイルは何もしない)
                if (!isResize(eobj.getFileSize())) {
                    continue;
                }
                // リッチテキストからファイルを取得
                java.io.InputStream fileData = eobj.getInputStream();
                // 縮小率(元画像の30%のサイズに縮小する)
                int scalePercent = 30;
                // ファイルオブジェクトがnullでない場合、処理を行う
                if (fileData != null) {
                    try{
                        // オリジナル画像を読み込む
                        java.awt.Image originalImage = javax.imageio.ImageIO.read(fileData);
    
                        // 縮小後の画像の幅と高さを計算
                        int newWidth = originalImage.getWidth(null) * scalePercent / 100;
                        int newHeight = originalImage.getHeight(null) * scalePercent / 100;
    
                        // 縮小後の画像を作成
                        java.awt.Image scaledImage = originalImage.getScaledInstance(newWidth, newHeight, java.awt.Image.SCALE_SMOOTH);
                        BufferedImage resizedImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
                        Graphics2D g = resizedImage.createGraphics();
                        g.drawImage(scaledImage, 0, 0, null);
                        g.dispose();
    
                        // ファイルを保存するためのOutputStreamを作成
                        String tmpFolder = "c:\\tmp\\";
                        FileOutputStream outputStream = new FileOutputStream(tmpFolder + fileName);
    
                        // JPEG形式で保存
                        javax.imageio.ImageIO.write(resizedImage, "jpg", outputStream);
    
                        // ストリームをクローズ
                        outputStream.close();
                        fileData.close();
    
                        // 既存の添付ファイルを削除
                        eobj.remove();
    
                        // リサイズした画像をアップロード
                        richTextField.embedObject(lotus.domino.EmbeddedObject.EMBED_ATTACHMENT, "", tmpFolder + fileName, "");
    
                        // リサイズした画像を削除
                        java.io.File deleteFile = new java.io.File(tmpFolder + fileName);
                        if (deleteFile.exists()) {
                            deleteFile.delete();
                        }
                        // for debug
                        System.out.println("resize done:" + fileName);
                        resizeFlg = true;
                        
                    }catch(IOException e){
                        e.printStackTrace();
                    }
                }                 
            }
            return resizeFlg;
        }           
        
    }
    
    /*
     * 画像ファイル判定(拡張子が画像の場合、true)
     */
    private boolean isImageFile(String fileName) {
        // 画像ファイルの拡張子リストを作成
        String[] imageExtensions = { ".jpg", ".jpeg", ".png", ".gif", ".bmp" };
        
        // ファイル名から拡張子を抽出する
        int dotIndex = fileName.lastIndexOf(".");
        String fileExtension = "";
        if(dotIndex >= 0){
            fileExtension = fileName.substring(dotIndex).toLowerCase();
        }
        // 拡張子が画像ファイルの拡張子リストに含まれているかを確認する
        return Arrays.asList(imageExtensions).contains(fileExtension);
    }
    /*
     * リサイズ対象判定(1MB以上のファイルサイズでtrue)
     */
    private boolean isResize(long fileSize) {
        long TARGET_SIZE = 1048576;             //1MB
        return fileSize >= TARGET_SIZE;
    }  
}


まとめ

Javaエージェントで作ってしまえば、実行までに若干タイムラグが発生してもNotesクライアントアプリ、NomadWebアプリ、NomadMobileアプリ、XPagesアプリすべてで有効です。