はじめに
このブログ記事は下記三部作の前編です。検索エンジンでたどり着いた方は他の関連記事も御覧下さい。
- ChatGPTとペアプログラミングで画像リサイズ機能を作ろう(実装検討編)←ココ
- ChatGPTとペアプログラミングで画像リサイズ機能を作ろう(実装編)
- ChatGPTとペアプログラミングで画像リサイズ機能を作ろう(課題解決編)
実装の背景
Notesクライアントにはリッチテキストフィールドに添付した画像をリサイズする機能はありません。それはXPagesでも同様です。
また、デジカメやスマホの画素数向上で画像ファイルは5MBくらいが当たり前になりました。
画像ファイルを複数添付するとすぐに10MB、20MBの文書ができ、文書を開く際にも「Notesは遅い」と言われてしまいます。(Notesだから遅いんじゃないっつーの!)
機種 |
カメラ画素数(広角) |
画像の画素数(px) |
およそのファイルサイズ |
|
Xperia10 V |
1200万画素 |
4000×2256 |
3~6MB |
|
iPhone12 Pro |
1200万画素 |
4032×3024 |
2~5MB |
XPagesのSSJSを使って、画像ファイルをリサイズし、リッチテキストフィールドの画像を小さくする機能を検討してみましょう。
ざっくりした仕様を決める
実装検討の前にざっくりした仕様を考えてみます。
- リッチテキストフィールドに添付された画像をリサイズし、差し替える
- 元画像は残さない
- 画像は拡張子で判定し、Wordファイルなど他形式のファイルが添付された場合は、リサイズ処理しない
- リサイズ対象の画像は1MB以上とする
- 処理が複数回実行された場合も、1MB以上の場合のみ実行する(小さくなりすぎないようにする)
- 保存する画像のファイル形式はJPEGとする
- スマホで撮影した写真を想定しているため
- リサイズは文書保存時に実行する
- 用途、利用シーンによっては、定期実行エージェントによる処理を検討する
- 用途、利用シーンによっては、定期実行エージェントによる処理を検討する
リサイズの事例がないか?ググってみる
仕様が決まったので、ググってみます。 「XPages image resize」でググってみると、小野さんのブログにフロントエンド(ClientSideJavaScript)で、縮小した画像をcanvasに描画し、canvasの画像をリッチテキストフィールドにアップロードする方法がありました。(アップロードにはOpenNTFのコンポーネント使用)
https://ameblo.jp/mak1005/entry-12217023161.html
メリットとデメリットをまとめると下記のようになります。
- メリット
フロントエンドで圧縮するので、通信量が削減できる
サーバーのCPUパワーを使わなくても良い - デメリット
OpenNTFのコンポーネントを組み込む必要があり「誰でも簡単に」とは言えない
NTFやNSFをコピーしただけで使えるようにしたいのでバックエンドでリサイズする方法を検討します。
ChatGPTに聞いてみる①:リッチテキストに添付された画像をローカルに保存できる?
無料版のChatGPTに聞いてみます(GPT-3.5)。
単純に聞くのではなく、SSJSでリッチテキストから画像を取得するところまで自分で書いて、続きを具体的に聞いてみます。
何やらJavaで書いてくれたようです。
XPagesのSSJSで動かしたいので書き換えて貰います。
SSJSに書き換えてくれました。importPackageを使ってJavaパッケージを読み込んでいるようです。
XPages上に実装し、動作を確認してみます。ChatGPTは毎回動作するコードを書いてくれるわけではないですが、今回は動作するようです。
ChatGPTに聞いてみる②:リサイズしてからローカルに保存できる?
リッチテキストフィールドの画像をローカルにダウンロードできたので、次はリサイズしてから保存してくれるように依頼します。
Javaパッケージでリサイズしてくれました。
もちろん、回答が正しいとは限らないので、実際に実装して動作を確認します。今回もうまく動作しました。
これで後は作成した画像をリッチテキストにアップロードすれば実装できそうです。
参考:リッチテキストフィールドの添付ファイルをリサイズして、ローカルに保存するSSJS
importPackage(java.io);
importPackage(com.ibm.xsp.http);
importPackage(java.awt);
importPackage(java.awt.image);
importPackage(javax.imageio);
// リッチテキストフィールドを取得
var richTextField = document1.getDocument().getFirstItem("ImageBody");
// リッチテキストフィールドからファイルオブジェクトを取得
var fileData = richTextField.getEmbeddedObject("fileName.jpg"); // fileName.jpgは対象のファイル名
// ファイルを保存するディレクトリとファイル名を指定
var saveDirectory = "C:/path/to/your/directory"; // 保存したいディレクトリのパスを指定
var fileName = "fileName.jpg"; // 保存するファイルの名前を指定
// 縮小後の幅と高さを指定
var newWidth = 800;
var newHeight = 600;
try {
// IUploadedFileからInputStreamを取得
var inputStream = fileData.getInputStream();
// オリジナル画像を読み込む
var originalImage = ImageIO.read(inputStream);
// 縮小後の画像を作成
var scaledImage = originalImage.getScaledInstance(newWidth, newHeight, Image.SCALE_SMOOTH);
var resizedImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
var g = resizedImage.createGraphics();
g.drawImage(scaledImage, 0, 0, null);
g.dispose();
// ファイルを保存するためのOutputStreamを作成
var outputStream = new FileOutputStream(saveDirectory + "/" + fileName);
// JPEG形式で保存
ImageIO.write(resizedImage, "jpeg", outputStream);
// ストリームをクローズ
outputStream.close();
inputStream.close();
// ファイルの保存が成功した場合の処理を記述(オプション)
} catch (e) {
// 例外処理:ファイルの保存に失敗した場合のエラーハンドリング
print(e);
}
ChatGPTに聞いてみる③:ローカルファイルを削除できる?
リサイズして、リッチテキストに再アップロードはできそうですが、このままではサーバーのテンポラリフォルダに画像が残ってしまいます。
SSJSでファイルは削除できないか?聞いてみます。
Javaクラスを使って、SSJSから作成したJavaクラスを呼び出すコードを提案してくれました。
importPakage(java.io)で直接Javaパッケージを呼び出せば良いのでは?と思って聞いてみます。
Javaクラスを作らない方法に書き換えてくれました。
実際に実装してみます。
保存できないんかい!?
「delete」はJavaScriptの予約語なので、メソッド名に使えません。(ChatGPTが最初の回答でJavaクラスを作れ!と言った意味がここで判明)
仕方がないので正直に相談します。
何と言うことでしょう!
メソッド名を””で囲んで文字列として渡せば実行できるよと教えてくれました。
var isDeleted = fileToDelete[“delete”]();
こんな書き方できるんですね。
いにしえの魔法みたいです。
毎回、動作確認します。
保存でき、動作も確認できました! これで技術的な課題はクリアです。
まとめ
ChatGPTは、誰でも同じ結果を出せる銀の弾丸ではありません。
メッチャ頭の良い友人と同じく、こちらの質問レベルに応じた回答をしてくれます。
本当の友人のように先回りして忖度してくれたり、真意を聞いたりはしてくれません。
しかし、自分がペアプログラミングするための先生としてディスカッションしながらコーディングしていくと、自分をレベルアップさせつつ、今までできなかったことが出来る可能性があります。
明日はこの知見を使って実際にXPages上に実装していきます。