質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

Q&A

解決済

2回答

3777閲覧

android studio: ImageViewで画像をぼやけさせずに拡大する方法

REIK727

総合スコア23

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

1グッド

1クリップ

投稿2019/01/16 06:03

編集2019/01/18 15:06

前提・実現したいこと

現在android studioでポケモン図鑑を作ろうとしています。
ImageViewに画像を載せるとき、自動的に画像がImageViewの大きさに合わせて拡縮されますよね?そこで、ゲームで使われるドット絵のように縦横の画素数が極めて少ない画像を画面いっぱいに表示しようとするとぼやけてしまいます。これをぼやけないようにしたいです。

発生している問題・エラーメッセージ

イメージ説明

該当のソースコード

MainActivity

Kotlin

1package com.example.myapplication 2 3import android.graphics.Bitmap 4import android.graphics.BitmapFactory 5import android.support.v7.app.AppCompatActivity 6import android.os.Bundle 7import android.os.Environment 8import android.widget.ImageView 9import com.bumptech.glide.Glide 10import kotlin.math.min 11 12class MainActivity : AppCompatActivity() { 13 14 override fun onCreate(savedInstanceState: Bundle?) { 15 super.onCreate(savedInstanceState) 16 setContentView(R.layout.activity_main) 17 val view = findViewById<ImageView>(R.id.imageView) 18 19 //pngの場合 20 view.setImageBitmap( 21 BitmapFactory.decodeFile( 22 Environment.getExternalStorageDirectory().path + "/MyApp/pikachu_static.png" 23 ) 24 ) 25 26 //gifの場合 27 Glide 28 .with(this) 29 .load( 30 Environment.getExternalStorageDirectory().path + "/MyApp/pikachu_dynamic.gif" 31 ) 32 .into(view) 33 } 34}

activity_main

XML

1<?xml version="1.0" encoding="utf-8"?> 2<android.support.constraint.ConstraintLayout 3 xmlns:android="http://schemas.android.com/apk/res/android" 4 xmlns:tools="http://schemas.android.com/tools" 5 xmlns:app="http://schemas.android.com/apk/res-auto" 6 android:layout_width="match_parent" 7 android:layout_height="match_parent" 8 tools:context=".MainActivity"> 9 10 <ImageView 11 android:layout_width="0dp" 12 android:layout_height="0dp" 13 tools:srcCompat="@tools:sample/avatars" 14 android:id="@+id/imageView" 15 app:layout_constraintStart_toStartOf="parent" 16 app:layout_constraintEnd_toEndOf="parent" 17 app:layout_constraintTop_toTopOf="parent" 18 app:layout_constraintBottom_toBottomOf="parent" 19 android:layout_marginTop="24dp" 20 android:layout_marginStart="24dp" 21 android:layout_marginEnd="24dp" 22 android:layout_marginBottom="24dp"/> 23</android.support.constraint.ConstraintLayout>

試したこと

  1. Vector Drawableにする

→ベクタ画像にしたことでぼやけは完全になくなったが、gifには使えない。

  1. あらかじめ縦横の画素数を何倍かに増やしておく

→ファイルサイズが大きくなるうえ、何倍に拡大すれば目立たなくなる程度のぼやけになるのかも決定できない。あまりスマートでないのでやりたくない。

  1. Bitmap.createScaledBitmap()を使って動的に拡大したものを表示する

→静止画はきれいに表示できる。しかしGlideを使ってgifを表示するときは使えない。

Main Activity

kotin

1package com.example.myapplication 2 3import android.graphics.Bitmap 4import android.graphics.BitmapFactory 5import android.os.Bundle 6import android.os.Environment 7import android.support.v7.app.AppCompatActivity 8import android.view.ViewTreeObserver 9import android.widget.ImageView 10import kotlin.math.min 11 12class MainActivity : AppCompatActivity() { 13 14 override fun onCreate(savedInstanceState: Bundle?) { 15 super.onCreate(savedInstanceState) 16 setContentView(R.layout.activity_main) 17 val view = findViewById<ImageView>(R.id.imageView) 18 19 view.viewTreeObserver.addOnGlobalLayoutListener( 20 object : ViewTreeObserver.OnGlobalLayoutListener { 21 override fun onGlobalLayout() { 22 //getResizedBitmap()はviewの幅と高さが決定してからでないと使えないためここで画像をセットする 23 view.setImageBitmap( 24 getResizedBitmap( 25 BitmapFactory.decodeFile( 26 Environment.getExternalStorageDirectory().path + "/MyApp/pikachu_static.png" 27 ), 28 view 29 ) 30 ) 31 //幅と高さだけ取得できれば用済みなのでリスナを削除 32 view.viewTreeObserver.removeOnGlobalLayoutListener(this) 33 } 34 } 35 ) 36 } 37 38 //originalをviewに入る最大の大きさに拡大する。このときcreateScaledBitmap()のfilterにfalseを指定するとぼやけないっぽい。 39 fun getResizedBitmap(original: Bitmap, view: ImageView): Bitmap { 40 val magnification = min(view.width / original.width, view.height / original.height) 41 return Bitmap.createScaledBitmap( 42 original, original.width * magnification, original.height * magnification, false 43 ) 44 } 45}

activity_main

さっきと一緒

イメージ説明

補足情報(FW/ツールのバージョンなど)

android studioのバージョンは3.3、使用した実機及びエミュレータのOSは8.0、APIレベルは26です。
上にのせたサンプルコードで使っている画像はこの二つです。

pikachu_static
イメージ説明
pikachu_dynamic
イメージ説明

kakajika👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kakajika

2019/01/18 14:07

自動的にImageViewの大きさに合わせて画像が拡縮されるということはないと思います。画像ファイルはどのディレクトリに入れていますか?
REIK727

2019/01/18 15:14 編集

画像ファイルは、掲載したソースコードの方ではリソースから読み込んでいましたが実際に作ったアプリの方ではストレージから読み込んでいます(掲載しているほうのソースコードもそれに合わせ一部修正しました)。 また画像の拡縮に関してですが、ImageViewは掲載したXMLに書かれているように「上下左右24dpのマージンを確保しつつ画面いっぱいに広げる」といったものになっています。先ほどこのマージンを大きくすることでImageViewが小さくなるようにし、画像がどのように表示されるのか確かめてみたのですがやはり画像の方もImageView同様小さくなっていました。なので「自動的にImageViewの大きさに合わせて画像が拡縮される」ということに間違いはなさそうなのですが...
kakajika

2019/01/19 01:13

画像がImageViewのサイズよりも小さく描画されることを期待しているということでしょうか?それならばImageViewのScaleTypeを調整することによりそのような挙動になるはずです。 あくまでImageViewのサイズに合わせつつ描画時にボケないようにする方法については、回答に書きますね。
guest

回答2

0

ベストアンサー

以下の3点をおさえてもらえば、お望みの挙動になると思います。

1. リソースファイルから読み込む際の拡縮について

Androidではdrawableフォルダに入れた画像ファイルを読み込む際に、フォルダのdpiと端末のdpiを比較して自動的に画像を拡縮した状態で読み込まれます。この機能は、 drawable-nodpi フォルダに画像ファイルを入れるようにすることで無効にできます。BitmapFactory.OptionsのinScaledをfalseにすることでも同じ挙動を実現できますが、読み込み方が限定されてしまうので前者の方法のほうが便利です。
編集後のご質問のようにストレージから画像ファイルを読み込むのであれば関係ないので、これはスルーしてください。

2. ImageViewの描画時の補間について

ImageViewのサイズよりも小さい画像をセットして描画する場合、デフォルトで PaintのFILTER_BITMAP_FLAG が有効になっているのでBilinear補間が効いた状態で描画されます。おそらく今回問題とされているのはこれが一番の原因でしょう。これを無効にするには、ImageViewを継承したクラスで描画処理をオーバーライドすれば可能です。

kotlin

1class NoFilterImageView(...) : AppCompatImageView(...) { 2 // 特定のフラグを無効にするためのDrawFilter 3 private val drawFilter = PaintFlagsDrawFilter(Paint.FILTER_BITMAP_FLAG, 0) 4 5 override fun onDraw(canvas: Canvas) { 6 val originalDrawFilter = canvas.drawFilter 7 canvas.drawFilter = drawFilter // drawFilterを変更 8 super.onDraw(canvas) 9 canvas.drawFilter = originalDrawFilter // drawFilterを元に戻す 10 } 11}

3. Glideの読み込み時の拡縮について

Glideで画像を読み込む場合にも、デフォルトではGlide内部でImageViewのサイズに合わせて画像を拡縮する変形が行われます。RequestOptions#dontTransform を指定することでこれを無効にできます。

kotlin

1Glide.with(...) 2 .setDefaultRequestOptions(RequestOptions().dontTransform()) 3 .load(...) 4 .into(imageView)

投稿2019/01/19 01:41

編集2019/01/19 01:43
kakajika

総合スコア3131

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

REIK727

2019/01/19 07:33

今試してみました。すごいです、png, gif共に完全に希望通りの挙動になりました。本当にありがとうございました。
guest

0

これは直接の回答になっていないのですが・・・もしかしたら今後役にたつかと思い回答させてもらいます。

androidには解像度というのがあり、それは機種によって1(mdpi):1.5(hdpi):2(xhdpi):3(xxhdpi):4(xxxhdpi)というふうに分かれています。(数字はmdpiを1としたときの解像度の倍率)。

それで例えば、xxhdpiの機種でxhdpiの画像のみしか用意しないなどすると、画像がぼやけやすく、動きものろくなってしまいます。(実際に私がはまったことがあります・・・)

これを解決するにはBatch drawable importerというプラグインを使います。導入のしかたまでは記しませんが、それでいくらかぼやけなくなるかもしれません。
でも、これはドット絵を引き延ばす対策にはなっていないので、他のかたの回答をまつことをおすすめします。

投稿2019/01/18 07:10

hood

総合スコア351

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

REIK727

2019/01/18 08:58

回答ありがとうございます。ご紹介いただいたBatch drawable importerを使ってみましたが、画像をインポートした時点ですでにぼやけたものになっており、ご指摘の通りドット絵には向かないようです。 あまり回答がつかないことからやはり一般的な解決法はないようなので、とりあえず現在は静止画についてはcreateScaledBitmap()でぼやけないように拡大、gifについてはデコーダを自力で作れないか検討しています。ご協力ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問