画像処理部分をAndroidではBufferedImageが使えないので、Bitmap に変更する。
chatgptに「次のコードAndroid向けに書き換えて」 ImageInfoReader.java
/** 指定した順番の画像情報を取得 * @throws RarException */ public BufferedImage getImage(int idx) throws IOException, RarException { return this.getImage(this.imageFileNames.get(idx)); } /** ファイル名から画像を取得 * 拡張子変更等は外側で修正しておく * ファイルシステムまたはZipファイルから指定されたファイル名の画像を取得 * @param srcImageFileName ファイル名 Zipならエントリ名 * ※先頭からシークされるので遅い? * @throws RarException */ public BufferedImage getImage(String srcImageFileName) throws IOException, RarException { if (this.isFile) { File file = new File(this.srcParentPath+srcImageFileName); if (!file.exists()) { //拡張子修正 srcImageFileName = this.correctExt(srcImageFileName); file = new File(this.srcParentPath+srcImageFileName); if (!file.exists()) return null; } try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file), 8192)) { return ImageUtils.readImage(srcImageFileName.substring(srcImageFileName.lastIndexOf('.') + 1).toLowerCase(), bis); } } else { if (this.srcFile.getName().endsWith(".rar")) { InputStream is = null; Archive archive = new Archive(srcFile); try { FileHeader fileHeader = archive.nextFileHeader(); while (fileHeader != null) { if (!fileHeader.isDirectory()) { String entryName = fileHeader.getFileName(); entryName = entryName.replace('\\', '/'); if (srcImageFileName.equals(entryName)) { is = archive.getInputStream(fileHeader); return ImageUtils.readImage(srcImageFileName.substring(srcImageFileName.lastIndexOf('.')+1).toLowerCase(), is); } } fileHeader = archive.nextFileHeader(); } } finally { if (is != null) is.close(); archive.close(); } } else { try (ZipFile zf = ZipFile.builder().setFile(this.srcFile).setUseUnicodeExtraFields(true).get()) { ZipArchiveEntry entry = zf.getEntry(srcImageFileName); if (entry == null) { srcImageFileName = this.correctExt(srcImageFileName); entry = zf.getEntry(srcImageFileName); if (entry == null) return null; } try (InputStream is = zf.getInputStream(entry)) { return ImageUtils.readImage(srcImageFileName.substring(srcImageFileName.lastIndexOf('.')+1).toLowerCase(), is); } } catch (Exception e) { e.printStackTrace(); } } } return null; }
Android向けにリファクタリングする際、以下の点を考慮する必要があります。
BufferedImage の代替: Androidでは BufferedImage は使えないため、Bitmap に変更。 FileInputStream の扱い: Androidでは FileInputStream を BitmapFactory.decodeStream() で処理する。 Rar/Zipの処理: junrar や android-zip4j などのライブラリを使用することを検討。 ストリーム管理: try-with-resources を活用し、リソースリークを防ぐ。 以下がAndroid向けに書き換えたコードです。
import android.graphics.Bitmap; import android.graphics.BitmapFactory; import java.io.*; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import com.github.junrar.Archive; import com.github.junrar.rarfile.FileHeader; public class ImageLoader { private String srcParentPath; private File srcFile; private boolean isFile; /** 指定した順番の画像情報を取得 */ public Bitmap getImage(int idx) throws IOException { return this.getImage(this.imageFileNames.get(idx)); } /** ファイル名から画像を取得 */ public Bitmap getImage(String srcImageFileName) throws IOException { if (this.isFile) { File file = new File(this.srcParentPath + srcImageFileName); if (!file.exists()) { // 拡張子修正 srcImageFileName = this.correctExt(srcImageFileName); file = new File(this.srcParentPath + srcImageFileName); if (!file.exists()) return null; } try (FileInputStream fis = new FileInputStream(file)) { return BitmapFactory.decodeStream(fis); } } else { if (this.srcFile.getName().endsWith(".rar")) { return getImageFromRar(srcImageFileName); } else { return getImageFromZip(srcImageFileName); } } } /** RARファイル内の画像を取得 */ private Bitmap getImageFromRar(String srcImageFileName) throws IOException { try (Archive archive = new Archive(new FileInputStream(srcFile))) { FileHeader fileHeader = archive.nextFileHeader(); while (fileHeader != null) { if (!fileHeader.isDirectory()) { String entryName = fileHeader.getFileName().replace('\\', '/'); if (srcImageFileName.equals(entryName)) { try (InputStream is = archive.getInputStream(fileHeader)) { return BitmapFactory.decodeStream(is); } } } fileHeader = archive.nextFileHeader(); } } return null; } /** ZIPファイル内の画像を取得 */ private Bitmap getImageFromZip(String srcImageFileName) throws IOException { try (ZipFile zipFile = new ZipFile(this.srcFile)) { ZipEntry entry = zipFile.getEntry(srcImageFileName); if (entry == null) { srcImageFileName = this.correctExt(srcImageFileName); entry = zipFile.getEntry(srcImageFileName); if (entry == null) return null; } try (InputStream is = zipFile.getInputStream(entry)) { return BitmapFactory.decodeStream(is); } } } /** 拡張子を補正するメソッド (実装例) */ private String correctExt(String fileName) { // 例: .jpeg を .jpg に変更など return fileName.replace(".jpeg", ".jpg").replace(".JPG", ".jpg"); } }
変更点・ポイント
BufferedImage を Bitmap に変更
BitmapFactory.decodeStream() を使用して InputStream から Bitmap を取得。
FileInputStream の適切な処理
try-with-resources を使用し、InputStream を適切に閉じる。
junrar を使ってRARファイルを処理
Archive クラスを使用して .rar のエントリを検索し、該当する InputStream から Bitmap を取得。
ZipFile を使ってZIPファイルを処理
ZipFile で ZipEntry を検索し、InputStream を取得して BitmapFactory.decodeStream() で画像をデコード。
このコードをAndroidアプリに組み込めば、RARやZIP内の画像も簡単に取得できます! 🎯
ログ表示をどうするか
次のコードAndroid向けに書き換えて
package io.github.kyukyunyorituryo.aozoraepub3.util; import javax.swing.JTextArea; /** ログ出力Wrapperクラス */ public class LogAppender { static JTextArea jTextArea = null; static public void setTextArea(JTextArea _jTextArea) { jTextArea = _jTextArea; } static public void println(String log) { LogAppender.append(log); LogAppender.append("\n"); } static public void println() { LogAppender.append("\n"); } static public void append(String log) { if (jTextArea != null) { jTextArea.append(log); jTextArea.setCaretPosition(jTextArea.getDocument().getLength()); } System.out.print(log); } static public void printStaclTrace(Exception e) { for (StackTraceElement ste : e.getStackTrace()) { LogAppender.append(ste.toString()); LogAppender.append("\n"); } } static public void msg(int lineNum, String msg, String desc) { LogAppender.append(msg); LogAppender.append(" ("+(lineNum+1)+")"); if (desc != null) { LogAppender.append(" : "); LogAppender.append(desc); } LogAppender.append("\n"); } static public void error(String msg) { LogAppender.append("[ERROR] "); LogAppender.append(msg); LogAppender.append("\n"); } static public void error(int lineNum, String msg, String desc) { LogAppender.append("[ERROR] "); LogAppender.msg(lineNum, msg, desc); } static public void error(int lineNum, String msg) { LogAppender.append("[ERROR] "); LogAppender.msg(lineNum, msg, null); } static public void warn(int lineNum, String msg, String desc) { LogAppender.append("[WARN] "); LogAppender.msg(lineNum, msg, desc); } static public void warn(int lineNum, String msg) { LogAppender.append("[WARN] "); LogAppender.msg(lineNum, msg, null); } static public void info(int lineNum, String msg, String desc) { LogAppender.append("[INFO] "); LogAppender.msg(lineNum, msg, desc); } static public void info(int lineNum, String msg) { LogAppender.append("[INFO] "); LogAppender.msg(lineNum, msg, null); } }
Android向けにリファクタリングしたコードは以下のようになります。JTextAreaの代わりにTextViewを使用し、スレッドの制約を考慮してHandlerを用いてUIを更新します。
修正点: JTextArea → TextView(Android UI向け) System.out.print(log); → Log.d("LogAppender", log);(AndroidのLogクラスを使用) TextViewの更新をメインスレッドで行うためにHandlerを追加
package io.github.kyukyunyorituryo.aozoraepub3.util; import android.os.Handler; import android.os.Looper; import android.util.Log; import android.widget.TextView; /** ログ出力Wrapperクラス */ public class LogAppender { private static TextView textView = null; private static final Handler handler = new Handler(Looper.getMainLooper()); public static void setTextView(TextView _textView) { textView = _textView; } public static void println(String log) { append(log); append("\n"); } public static void println() { append("\n"); } public static void append(String log) { Log.d("LogAppender", log); // Androidのログ出力 if (textView != null) { handler.post(() -> { textView.append(log); textView.append("\n"); }); } } public static void printStackTrace(Exception e) { for (StackTraceElement ste : e.getStackTrace()) { append(ste.toString()); append("\n"); } } public static void msg(int lineNum, String msg, String desc) { append(msg + " (" + (lineNum + 1) + ")"); if (desc != null) { append(" : " + desc); } append("\n"); } public static void error(String msg) { append("[ERROR] " + msg + "\n"); } public static void error(int lineNum, String msg, String desc) { append("[ERROR] "); msg(lineNum, msg, desc); } public static void error(int lineNum, String msg) { append("[ERROR] "); msg(lineNum, msg, null); } public static void warn(int lineNum, String msg, String desc) { append("[WARN] "); msg(lineNum, msg, desc); } public static void warn(int lineNum, String msg) { append("[WARN] "); msg(lineNum, msg, null); } public static void info(int lineNum, String msg, String desc) { append("[INFO] "); msg(lineNum, msg, desc); } public static void info(int lineNum, String msg) { append("[INFO] "); msg(lineNum, msg, null); } } > ポイント > Androidのログ機能 > System.out.print(log); の代わりに Log.d("LogAppender", log); を使用しました。 > > UI更新の考慮 > TextView の更新はメインスレッドで行う必要があるため、Handlerを利用しています。 > > 例外のリネーム > printStaclTrace というスペルミスを printStackTrace に修正しました。 > > これで、Androidアプリ内で簡単にログを出力・表示できるようになります。 テンプレート部分の書き換え [https://99nyorituryo.hatenablog.com/entry/2024/10/25/000604:embed:cite] [blog:g:11696248318754550880:banner]