画像処理部分を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]