ソース画像の絶対パスからサムネイル画像を作り、出力用絶対パスに保存するクラスを切り出す。
サムネイル画像の保存サイズは、正方形のサイズを指定。
元画像の縦横比をそのままスケールダウンし、指定サイズに収める。
出力のファイル拡張子(JPG/PNG)から書き出しファイル形式を決める。
入力(source.png)、出力(destination.jpg)とした時に
toThumbnailFile( new File("source.png"), new File("destination.jpg"), 100 )
入力は"PNG"だけど作られたものは"JPG"になる。
使用例:クラスをインポートした上で
File souFile = new File( 入力絶対パス );
File destFile = new File( 出力絶対パス );
boolean ret = new MyMakeThumbnail.toThumbnailFile( souFile, destFile, 100 )
元画像があれば、サムネイル画像が作成、または上書きされる。
前省略
public class MyMakeThumbnail {
int saveSize;
public boolean toThumbnailFile( File souFile, File destFile, int saveSize ) {
if (souFile == null || !souFile.exists() || !souFile.isFile()) return false;
this.saveSize = saveSize;
Bitmap bitmap = thumbnaileImage( souFile );
if ( bitmap != null ) {
try {
FileOutputStream fos = new FileOutputStream( destFile );
Bitmap.CompressFormat bcf = getCompressFormat( destFile.getName() );
if ( bcf != null ) bitmap.compress( bcf, 85, fos );
fos.close();
} catch (IOException e) {
return false;
}
}
return true;
}
private Bitmap thumbnaileImage( File souFile ) {
Bitmap scaleBitmap = null;
try {
BitmapFactory.Options op = new BitmapFactory.Options();
op.inJustDecodeBounds = true;
InputStream istream = new FileInputStream( souFile );
BitmapFactory.decodeStream( istream, null, op );
op.inSampleSize = calculateInSampleSize( op );
op.inJustDecodeBounds = false;
istream.close();
istream = new FileInputStream( souFile );
scaleBitmap = BitmapFactory.decodeStream( istream, null, op );
istream.close();
if ( scaleBitmap == null ) return null;
Matrix matrix = new Matrix();
float mag = calcMag( scaleBitmap.getWidth(), scaleBitmap.getHeight() );
matrix.postScale( mag, mag );
scaleBitmap = Bitmap.createBitmap( scaleBitmap, 0, 0, scaleBitmap.getWidth(), scaleBitmap.getHeight(), matrix, true);
} catch (OutOfMemoryError | IOException ignored) {
return null;
}
return scaleBitmap;
}
private int calculateInSampleSize(BitmapFactory.Options op) {
int height = op.outHeight;
int width = op.outWidth;
int inSamplSize = 1;
if ( height > saveSize || width > saveSize) {
int halfHeight = height / 2;
int halfWidth = width / 2;
while ( ( halfHeight / inSamplSize ) >= saveSize &&
( halfWidth / inSamplSize ) >= saveSize
) {
inSamplSize *= 2;
}
}
return inSamplSize;
}
private Bitmap.CompressFormat getCompressFormat(String name ) {
String t = name.toLowerCase();
if ( t.endsWith( ".jpg" ) ) return Bitmap.CompressFormat.JPEG;
if ( t.endsWith( ".png" ) ) return Bitmap.CompressFormat.PNG;
return null;
}
private float calcMag( int souX, int souY ) {
float magW = (float)saveSize / (float)souX;
float magH = (float)saveSize / (float)souY;
return Math.min(magW, magH);
}
}
MyAsyncTaskは次のように短くなった。MyMakeThumbnailも使いまわしできる。
public class MyAsyncTask extends AsyncTask<String,Object,Object> {
private MyMainData mMainData;
@SuppressLint("StaticFieldLeak")
private RecyclerView mRecyclerView;
private File mCacheDir;
private final int vID;
public MyAsyncTask( MyMainData data, RecyclerView rv, int id ) {
super();
mMainData = data;
mCacheDir = data.getCacheDir();
mRecyclerView = rv ;
vID = id;
}
@Override
protected Object doInBackground(String... p) {
File souFile = new File(p[0]);
if ( !souFile.exists() || !souFile.isFile() ) return false;
if ( mCacheDir == null || ( !mCacheDir.exists() && !mCacheDir.mkdirs() ) ) return false;
File cacheFile = new File( mCacheDir, souFile.getName() );
if ( cacheFile.exists() ) return false;
return new MyMakeThumbnail().toThumbnailFile(souFile, cacheFile, 128);
}
@Override
protected void onPostExecute( Object result ) {
if ( (boolean)result ) {
// RecyclerViewアダプタは不定期更新される。別スレッド稼働時は必ずチェックする。
// 同じRecyclerViewアダプタのオブジェクトならnotifyItemChanged(vID)で更新。
if (Objects.equals(mRecyclerView.getAdapter(), mMainData.getThumbnailPage().getRecyclerView().getAdapter()))
Objects.requireNonNull(mRecyclerView.getAdapter()).notifyItemChanged(vID);
}
finish();
}
private void finish() {
mCacheDir = null;
mRecyclerView = null;
mMainData = null;
}
}