「ピクセル密度」ってナニよ?

 さて。
 端末でアプリを実行すると、「画像表示(View)が拡大されてしまう」不具合について。
 (参照:「画面サイズ設定」ってナニよ?)
 原因は、画面サイズだと思ったんだけど、そうではなかったみたい。
 振り出しに戻る…。
 でも、ヒントはあった。
 それが「ピクセル密度」

「ピクセル密度」ってナニよ?

 ピクセル密度は、「1dotを何pixelで表すか?」というもの。
 何の役に立つのかというと、「表示されるものは、どの環境でも、同じ大きさで表示される」。
 17インチモニターでも、15インチモニターでも、そこに表示されるものは、同じ大きさになるってワケ。

 じゃ、なんで、画像が拡大表示しまうのか?
 それは画面と画像のピクセル密度が合っていないから。
 画像のピクセル密度が、画面の密度より低いため、拡大表示されてしまうんだ。
 PhotoShopやGIMPなんかで、印刷解像度を低くした時と似てる。
 「ピクセル密度 = 印刷解像度」みたいに捉えるとわかりやすいかもね。
 Androidでの表示は、WYSWYGの仕組みに近いんだ。

ピクセル密度を調べる

 ピクセル密度は、下記の方法で調べられる。
 実行すると、ログにピクセル密度が書き出されるよ。

	DisplayMetrics metrics = getResources().getDisplayMetrics();

	Log.d( "TEST", "density=" + metrics.density );

 DisplayMetrics では、画面に関する他の情報も取得できる。

	DisplayMetrics metrics = getResources().getDisplayMetrics();
	
	Log.d( "TEST", "density=" + metrics.density );
	Log.d( "TEST", "densityDpi=" + metrics.densityDpi );
	Log.d( "TEST", "scaledDensity=" + metrics.scaledDensity );
	Log.d( "TEST", "widthPixels=" + metrics.widthPixels );
	Log.d( "TEST", "heightPixels=" + metrics.heightPixels );
	Log.d( "TEST", "xDpi=" + metrics.xdpi );
	Log.d( "TEST", "yDpi=" + metrics.ydpi );

 ちなみに。
 「画面サイズ設定ってナニよ?」で画面サイズを調べた時、画面サイズは 533×400 だった。
 それぞれに、ピクセル密度:1.5 をかけると、800×600 になる。
 ちょうど、normalScreens での値とlargeScreens での値になるね。

画像リソースのピクセル密度設定(画像解像度設定)

 拡大表示される原因は、ピクセル密度の違いにあることがわかった。
 じゃ、画面のピクセル密度に、画像のピクセル密度を合わせればいいワケだ。
 でもソレってどうやるの…?

 印刷解像度をいじくったリソースを使用してもダメ。
 ピクセル密度は、画像リソースだけで行う設定じゃないんだ。

 ピクセル密度の設定は、Eclipseプロジェクトでも行うんだ。
 正確には、設定ではないんだけどね。(^_^;

 大抵、画像リソースは、drawable ディレクトリに置くよね?
 それと同じで、それぞれのピクセル密度のディレクトリに、最適化した画像リソースを置くんだ。

	drawable-ldpi … 120dpi( low )
	drawable-mdpi … 160dpi( medium )
	drawable-hdpi … 240dpi( high )

 たとえば、medium で533x400dot の画像の場合、drawable-hdpi に800x600dot に拡大した画像リソースを置く。
 そうすることで、動作環境がdensityDpi = 240(high)だったら、画像リソースはdrawable-hdpi から使用される。
 Android は動作環境に合わせて、それぞれから最適なピクセル密度のリソースを使用してくれるって仕組み。

 最適なリソースがない場合、Android が自動的に拡縮調整してくれる。
 ただし、基準はmedium(160dpi)。
 つまり、drawable にだけ置くと、リソースをmedium として拡縮処理をしてしまう。
 high(240dpi)の環境で表示すると、拡大表示されてしまうんだね。

 これは便利な仕組みなんだけど…ゲームなんかでは困った仕組みだよ。
 ゲームの場合、テレビのようにdpi調整はしないで欲しい…
 この場合、drawable-nodpi ディレクトリにリソースを置く。

	drawable-nodpi … dpi調整をしない

 今回、drawable ディレクトリにあったリソースを、drawable-nodpi へ移すことで、拡大表示されてしまう不具合は解消されたよ。

プログラムからピクセル密度(画像解像度)を設定する

 ピクセル密度は、リソース・ディレクトリで対応できることがわかった。
 でも、ソレってデータがリソースの時だけ。

 画像データを外部参照する時は…?

 外部参照だけじゃなく、プログラム側からピクセル密度を設定したい場合もあるよね。
 そこでピクセル密度を設定できるか、ざっと調べてみたよ。

◆Canvas

	int	 getDensity()
	void	 setDensity(int density)

http://developer.android.com/reference/android/graphics/Canvas.html

◆Bitmap

	int 	getDensity()
	void 	setDensity(int density)

	int 	getScaledHeight(int targetDensity)
	int 	getScaledWidth(int targetDensity)

http://developer.android.com/reference/android/graphics/Bitmap.html

◆BitmapDrawable

	void	 setTargetDensity(int density)
	void	 setTargetDensity(DisplayMetrics metrics)
	void	 setTargetDensity(Canvas canvas)

http://developer.android.com/reference/android/graphics/drawable/BitmapDrawable.html

 以上からすると、今回の不具合には、Viewで使ってるCanvas にピクセル密度を設定すればいいみたい。
 そこでこんな風↓にしてみたよ。

	Canvas canvas;
	Bitmap scrImg = Bitmap.createBitmap( width, height, Bitmap.Config.ARGB_8888 );
	
	scrImg.setDensity( 160 );
	Log.d("TEST", "scrImg density = " + scrImg.getDensity() );
	
	Canvas scrImg_canv = new Canvas( scrImg );
//	scrImg_canv.setDensity( 160 );
	Log.d("TEST", "Canvas density = " + scrImg_canv.getDensity() );

 Canvas に直接、設定するのではなく、元になるBitmap の密度を設定してみた。
 Bitmap の設定がCanvas に引き継がれるか、確かめたかったため。
 実行してみると、設定値はちゃんと引き継がれていた。

 表示する画像データは、drawable ディレクトリに置いた画像リソース。
 medium(160dpi) と認識されるので、setDensity で設定する値も160にしてある。

 以上で、拡大表示される不具合は解消できたよ。

 この設定は、他のことにも使えそう。
 たとえば、動的に値を変えて、拡縮操作の代わりにするとか。
 まぁ、setBounds の方が使い勝手はいいから、意味はないだろうけどね。(^_^;

Posted in Bitmap, ピクセル密度. Tags: , , , , , , , , . 「ピクセル密度」ってナニよ? はコメントを受け付けていません »

「画面サイズ設定」ってナニよ?

 エミュレータ・ベース(VBox)で作ってたアプリを、端末で実行したら拡大表示されてしまった。
 いや、拡大表示っていうのは、正確じゃない。
 画像表示は拡大されて、ボタン等は横幅が圧縮されてしまってる。
 ちょうど、”小さな画面” に押し込まれた感じ。なんだけど…。

	VBoxの画面サイズは、800x600
	端末のタブレットも、800x600

 画面サイズは同じなのに、これはどういうことなんだろ…?

画面サイズを調べる

 原因は「端末の画面サイズ」だろうと予想がつく。
 なぜなら、ボタン等の左右端は、画面端から一定の長さを保つようにしているから。
 だから小さい画面になると、左右幅が圧迫されて横幅が小さくなってしまうんだ。
 でも前述のように、端末は800×600のハズ…。
 なにはともあれ、画面サイズをまず調べてみることにした。

 画面サイズは、下記方法で取得できる。

◆Activityの場合

	WindowManager wm = (WindowManager) getSystemService( Activity.WINDOW_SERVICE );
	Display display = wm.getDefaultDisplay();
	int width = display.getWidth();
	int height = display.getHeight();

◆Viewの場合

	WindowManager wm = (WindowManager) context.getSystemService( Context.WINDOW_SERVICE );
	Display display = wm.getDefaultDisplay();
	int width = display.getWidth();
	int height = display.getHeight();

 結果は…

	width  = 533
	height = 400

 やはり、画面サイズが小さいようだ。
 とすると、アプリ側で画面サイズの設定が必要…ということなのかな?

実は必要、画面サイズ設定(解像度設定)

 調べると、AndroidManifest.xml に supports-screens が必要らしい。
 supports-screens は、アプリでサポートしている画面解像度を設定するようだ。
 たとえば、下記のような感じ。

	<manifest xmlns:android="http://schemas.android.com/apk/res/android">
		<supports-screens
			android:largeScreens="true"
			android:normalScreens="true"
			android:smallScreens="true"
			android:anyDensity="true" />
	 </manifest>

 それぞれの意味は…

	largeScreens … ラージスクリーンのサポート
	normalScreens … ノーマルスクリーンのサポート
	smallScreens … スモールスクリーンのサポート
	anyDensity … ピクセル密度を調整可能

 ということのよう。
 これらの設定がない場合、解像度設定は、SDK Version の設定(後述)に従うらしい。
 そして、SDK Version の設定もない場合、すべてfalse となるらしい。

 supports-screens もSDK Version もない…
 その場合は、SDK 1.5相当のサポートとなり、normalScreens で動作することになる。
 つまり、「端末がlargeScreens の解像度でも、normalScreens の解像度で動作」する。
 ──今回のような「小さな画面サイズ」になってしまうようだ。

 PCに例えると、「17インチ・モニター(1024×768)で、15インチ設定(800×600)」にした感じかな。
 それと、これには逆の現象もあるらしい。
 本来、画面いっぱいに表示されるアプリが、小さく表示されてしまうようなんだ。
 原因は同じで、supports-screens もSDK Version の設定もないせいで起きるみたい。

 現在、作っているアプリは、800×480での動作を対象としている。
 なので、下記を追加したことで、画面サイズの問題はひとまず解決。

	<supports-screens
		android:largeScreens="true"
		android:anyDensity="true" />

SDK Version の設定

 前記 supports-screens とは別の設定でも、画面サイズを設定できる。
 別の設定とは、minSdkVersin もしくは targetSdkVersion の設定。
 それぞれは…

	minSdkVersino … 指定SDKバージョン以上で動作
	targetSdkVersion … 指定SDKバージョンでのみ動作

 …ということらしい。
 なので正確には、画面サイズ設定ではない。
 しかしこれらの設定をすると、SDKでサポートしている設定が supports-screens に設定されるため、同様の結果がえられるんだ。

 今回、下記を追加したことでも、画面サイズの問題は解決した。

	<uses-sdk android:minSdkVersion="4" />

※. 参考資料
http://developer.android.com/guide/practices/screens_support.html

未解決がひとつ…

 さて。
 画面サイズの問題は、supports-screens もしくは、minSdkVersion で解決した。
 けれども、「画像表示が拡大されてしまう」不具合は直らなかった。
 これはピクセル密度が関係した不具合で…
 解決方法は、またページを改めて。
 →「ピクセル密度ってナニよ?」

by the way…

 ここらへんって、基本中の基本っていうか、すごく重要なことだと思うんだけど…。
 手元にある緑本には記述が見当たらない。
 なんだかなぁ…。
 入門書だからこそ、解説してほしい事項なのになぁ。

Posted in アプリ設定, 画面. Tags: , , , , , . 「画面サイズ設定」ってナニよ? はコメントを受け付けていません »