一般的に、コンピュータにおいてビットマップとは、ある領域からビットへのマッピングのことです。ビット配列やビットマップインデックスとも呼ばれます。画像やディスプレイのピクセルの値を表すバイナリデータの配列を表します。
アンドロイドでは、このようなバイナリデータは、android.graphics
パッケージで定義されているBitmap
という定義済みのデータ型で保持することができます。そのリファレンスは ここにあります。
このチュートリアルでは、アンドロイドでのビットマップの使い方の例を紹介します。
例 1: Kotlin Android ビットマップの例
この例は、kotlinで書かれたアプリでビットマップを使用する初心者向けの方法です。
ここでは、作成されたデモを紹介します。
Step 1: Dependencies
サードパーティの依存関係は必要ありません。
ステップ 2: レイアウト設計
まず、xmlのレイアウトを設計します。画像のビットマップを使用しているので、そのビットマップをレンダリングするイメージビューが必要になります。そこで、イメージビューと、ビットマップを操作するためのいくつかのボタンを追加します。
activity_main.xml (英語)
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ImageView
android:id="@+id/mainActivity_imageView_testBitmap"
android:layout_width="270sp"
android:layout_height="270sp"
android:src="@drawable/image"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.496"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.06"
tools:ignore="ContentDescription" />
<Button
android:id="@+id/mainActivity_button_gray"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="23dp"
android:text="@string/gray"
app:layout_constraintBottom_toBottomOf="@+id/mainActivity_button_bright"
app:layout_constraintEnd_toStartOf="@+id/mainActivity_button_bright"
app:layout_constraintHorizontal_bias="0.49"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/mainActivity_button_bright" />
<Button
android:id="@+id/mainActivity_button_bright"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="@string/bright"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.503"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/mainActivity_imageView_testBitmap" />
<Button
android:id="@+id/mainActivity_button_dark"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/dark"
app:layout_constraintBottom_toBottomOf="@+id/mainActivity_button_bright"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.513"
app:layout_constraintStart_toEndOf="@+id/mainActivity_button_bright"
app:layout_constraintTop_toTopOf="@+id/mainActivity_button_bright" />
<Button
android:id="@+id/mainActivity_button_gama"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/gama"
app:layout_constraintBottom_toBottomOf="@+id/mainActivity_button_green"
app:layout_constraintEnd_toEndOf="@+id/mainActivity_button_gray"
app:layout_constraintStart_toStartOf="@+id/mainActivity_button_gray"
app:layout_constraintTop_toTopOf="@+id/mainActivity_button_green" />
<Button
android:id="@+id/mainActivity_button_green"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/green"
app:layout_constraintEnd_toEndOf="@+id/mainActivity_button_bright"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="@+id/mainActivity_button_bright"
app:layout_constraintTop_toBottomOf="@+id/mainActivity_button_bright" />
<Button
android:id="@+id/mainActivity_button_blue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/blue"
app:layout_constraintBottom_toBottomOf="@+id/mainActivity_button_green"
app:layout_constraintEnd_toEndOf="@+id/mainActivity_button_dark"
app:layout_constraintStart_toStartOf="@+id/mainActivity_button_dark"
app:layout_constraintTop_toTopOf="@+id/mainActivity_button_green" />
<Button
android:id="@+id/mainActivity_button_drawText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="@string/draw_text"
android:textAllCaps="false"
app:layout_constraintEnd_toEndOf="@+id/mainActivity_button_green"
app:layout_constraintHorizontal_bias="0.611"
app:layout_constraintStart_toStartOf="@+id/mainActivity_button_green"
app:layout_constraintTop_toBottomOf="@+id/mainActivity_button_green" />
<Button
android:id="@+id/mainActivity_button_drawLine"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:text="@string/draw_line"
android:textAllCaps="false"
app:layout_constraintBottom_toBottomOf="@+id/mainActivity_button_drawText"
app:layout_constraintEnd_toEndOf="@+id/mainActivity_button_gama"
app:layout_constraintStart_toStartOf="@+id/mainActivity_button_gama"
app:layout_constraintTop_toTopOf="@+id/mainActivity_button_drawText" />
<Button
android:id="@+id/mainActivity_button_drawCircle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="draw Circle"
android:textAllCaps="false"
app:layout_constraintBottom_toBottomOf="@+id/mainActivity_button_drawText"
app:layout_constraintEnd_toEndOf="@+id/mainActivity_button_blue"
app:layout_constraintStart_toStartOf="@+id/mainActivity_button_blue"
app:layout_constraintTop_toTopOf="@+id/mainActivity_button_drawText" />
<Button
android:id="@+id/mainActivity_button_drawRectangle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginTop="12dp"
android:text="draw Rectangle"
android:textAllCaps="false"
app:layout_constraintEnd_toEndOf="@+id/mainActivity_button_drawText"
app:layout_constraintHorizontal_bias="0.433"
app:layout_constraintStart_toStartOf="@+id/mainActivity_button_drawText"
app:layout_constraintTop_toBottomOf="@+id/mainActivity_button_drawText" />
<Button
android:id="@+id/mainActivity_button_drawShadow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="draw Shadow"
android:textAllCaps="false"
app:layout_constraintBottom_toBottomOf="@+id/mainActivity_button_drawRectangle"
app:layout_constraintEnd_toEndOf="@+id/mainActivity_button_drawLine"
app:layout_constraintStart_toStartOf="@+id/mainActivity_button_drawLine"
app:layout_constraintTop_toTopOf="@+id/mainActivity_button_drawRectangle" />
<Button
android:id="@+id/mainActivity_button_addPadding"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="padding"
android:textAllCaps="false"
app:layout_constraintBottom_toBottomOf="@+id/mainActivity_button_drawRectangle"
app:layout_constraintEnd_toEndOf="@+id/mainActivity_button_drawCircle"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="@+id/mainActivity_button_drawCircle"
app:layout_constraintTop_toTopOf="@+id/mainActivity_button_drawRectangle"
app:layout_constraintVertical_bias="0.0" />
<Button
android:id="@+id/mainActivity_button_borderedCircularBitmap"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="borderedCircularBitmap"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@+id/mainActivity_button_bright"
app:layout_constraintHorizontal_bias="0.509"
app:layout_constraintStart_toStartOf="@+id/mainActivity_button_bright"
app:layout_constraintTop_toBottomOf="@+id/mainActivity_button_drawRectangle"
app:layout_constraintVertical_bias="0.37" />
</androidx.constraintlayout.widget.ConstraintLayout>
Step 2: コードを書く
ここでは、ビットマップに対して実行可能な操作をいくつか紹介します。
ビットマップに線を引くには!
ビットマップに線を引くための拡張関数です。
private fun Bitmap.drawLine(x: Float = 0f, y: Float = 555f): Bitmap? {
val bitmap = copy(config, true)
val canvas = Canvas(bitmap)
Paint().apply {
color = Color.RED
strokeWidth = 10f
// draw line on canvas
canvas.drawLine(
x, // The x-coordinate of the start point of the line
x, // The y-coordinate of the start point of the line
y, // stopX
y, // stopY
this // paint
)
}
return bitmap
}
ビットマップに円の線を描画する方法)
ビットマップに円を描くための拡張機能です。
private fun Bitmap.drawCircle(
radius: Float = 100f,
color: Int = Color.YELLOW
): Bitmap? {
val bitmap = copy(config, true)
val canvas = Canvas(bitmap)
Paint().apply {
this.color = color
// draw circle on left bottom of bitmap
canvas.drawCircle(
width / 2f, // The x-coordinate of the start point of the line
height / 2f, // The y-coordinate of the start point of the line
(width + height) / 4f, // stopX
this // paint
)
}
return bitmap
}
ビットマップに矩形を描画する方法 (How to draw a rectange on a bitmap)
ビットマップ上に矩形を描画する拡張関数です。
private fun Bitmap.drawRectangle(): Bitmap? {
val bitmap = copy(config, true)
val canvas = Canvas(bitmap)
Paint().apply {
color = Color.RED
isAntiAlias = true
// draw rectangle on canvas
canvas.drawRect(
20f, // left side of the rectangle to be drawn
20f, // top side
width / 3 - 20f, // right side
height - 20f, // bottom side
this
)
}
return bitmap
}
ビットマップに影を描画する方法)
ビットマップ上に影を描画する拡張関数です。
private fun Bitmap.drawShadow(): Bitmap? {
val bitmap = Bitmap.createBitmap(
width + 10,
height + 10,
Bitmap.Config.ARGB_8888
)
val canvas = Canvas(bitmap)
val paint = Paint().apply {
isAntiAlias = true
// draw shadow right and bottom side of bitmap
/*
This draws a shadow layer below the main layer,
with the specified offset and color, and blur radius.
*/
setShadowLayer(
10f, // radius
6f, // dx
6f, // dy
Color.BLACK // color
)
}
canvas.drawBitmap(this, 0f, 0f, paint)
return bitmap
}
ビットマップにテキストを描画する方法)
ビットマップにテキストを描画するための拡張機能を紹介します。
private fun Bitmap.drawText(
text: String = "Red Lily",
textSize: Float = 60f,
color: Int = Color.RED
): Bitmap? {
val bitmap = copy(config, true)
val canvas = Canvas(bitmap)
Paint().apply {
flags = Paint.ANTI_ALIAS_FLAG
this.color = color
this.textSize = textSize
typeface = Typeface.SERIF
setShadowLayer(1f, 0f, 1f, Color.WHITE)
canvas.drawText(text, width / 4f , height - 20f, this)
}
return bitmap
}
詳細は以下のコードをご覧ください。
MainActivity.ktを参照してください。
class MainActivity : AppCompatActivity() {
lateinit var bmp: Bitmap
lateinit var operation: Bitmap
lateinit var mCanvas: Canvas
@SuppressLint("UseCompatLoadingForDrawables")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
bmp = mainActivity_imageView_testBitmap.drawable.toBitmap()
operation = Bitmap.createBitmap(bmp.width, bmp.height, bmp.config)
setOnClick()
}
private fun setOnClick() {
mainActivity_button_drawText.setOnClickListener {
mainActivity_imageView_testBitmap.setImageBitmap(bmp.drawText())
}
mainActivity_button_drawLine.setOnClickListener {
mainActivity_imageView_testBitmap.setImageBitmap(bmp.drawLine())
}
mainActivity_button_drawCircle.setOnClickListener {
mainActivity_imageView_testBitmap.setImageBitmap(bmp.drawCircle())
}
mainActivity_button_drawRectangle.setOnClickListener {
mainActivity_imageView_testBitmap.setImageBitmap(bmp.drawRectangle())
}
mainActivity_button_drawShadow.setOnClickListener {
mainActivity_imageView_testBitmap.setImageBitmap(bmp.drawShadow())
}
mainActivity_button_addPadding.setOnClickListener {
mainActivity_imageView_testBitmap.setImageBitmap(bmp.addPadding())
}
mainActivity_button_borderedCircularBitmap.setOnClickListener {
mainActivity_imageView_testBitmap.setImageBitmap(bmp.borderedCircularBitmap())
}
mainActivity_button_blue.setOnClickListener { gray() }
mainActivity_button_bright.setOnClickListener { bright() }
mainActivity_button_dark.setOnClickListener { dark() }
mainActivity_button_gama.setOnClickListener { gama() }
mainActivity_button_green.setOnClickListener { green() }
mainActivity_button_blue.setOnClickListener { blue() }
}
// utility bitmap
// extension function to draw line on bitmap
private fun Bitmap.drawLine(x: Float = 0f, y: Float = 555f): Bitmap? {
val bitmap = copy(config, true)
val canvas = Canvas(bitmap)
Paint().apply {
color = Color.RED
strokeWidth = 10f
// draw line on canvas
canvas.drawLine(
x, // The x-coordinate of the start point of the line
x, // The y-coordinate of the start point of the line
y, // stopX
y, // stopY
this // paint
)
}
return bitmap
}
// extension function to draw circle on bitmap
private fun Bitmap.drawCircle(
radius: Float = 100f,
color: Int = Color.YELLOW
): Bitmap? {
val bitmap = copy(config, true)
val canvas = Canvas(bitmap)
Paint().apply {
this.color = color
// draw circle on left bottom of bitmap
canvas.drawCircle(
width / 2f, // The x-coordinate of the start point of the line
height / 2f, // The y-coordinate of the start point of the line
(width + height) / 4f, // stopX
this // paint
)
}
return bitmap
}
// extension function to draw rectangle on bitmap
private fun Bitmap.drawRectangle(): Bitmap? {
val bitmap = copy(config, true)
val canvas = Canvas(bitmap)
Paint().apply {
color = Color.RED
isAntiAlias = true
// draw rectangle on canvas
canvas.drawRect(
20f, // left side of the rectangle to be drawn
20f, // top side
width / 3 - 20f, // right side
height - 20f, // bottom side
this
)
}
return bitmap
}
// extension function to draw shadow on bitmap
private fun Bitmap.drawShadow(): Bitmap? {
val bitmap = Bitmap.createBitmap(
width + 10,
height + 10,
Bitmap.Config.ARGB_8888
)
val canvas = Canvas(bitmap)
val paint = Paint().apply {
isAntiAlias = true
// draw shadow right and bottom side of bitmap
/*
This draws a shadow layer below the main layer,
with the specified offset and color, and blur radius.
*/
setShadowLayer(
10f, // radius
6f, // dx
6f, // dy
Color.BLACK // color
)
}
canvas.drawBitmap(this, 0f, 0f, paint)
return bitmap
}
// extension function to draw text on bitmap
private fun Bitmap.drawText(
text: String = "Red Lily",
textSize: Float = 60f,
color: Int = Color.RED
): Bitmap? {
val bitmap = copy(config, true)
val canvas = Canvas(bitmap)
Paint().apply {
flags = Paint.ANTI_ALIAS_FLAG
this.color = color
this.textSize = textSize
typeface = Typeface.SERIF
setShadowLayer(1f, 0f, 1f, Color.WHITE)
canvas.drawText(text, width / 4f , height - 20f, this)
}
return bitmap
}
// extension function to add padding to bitmap
private fun Bitmap.addPadding(
color: Int = Color.GRAY,
left: Int = 0,
top: Int = 0,
right: Int = 0,
bottom: Int = 0
): Bitmap? {
val bitmap = Bitmap.createBitmap(
width + left + right, // width in pixels
height + top + bottom, // height in pixels
Bitmap.Config.ARGB_8888
)
val canvas = Canvas(bitmap)
// draw solid color on full canvas area
canvas.drawColor(color)
// clear color from bitmap drawing area
// this is very important for transparent bitmap borders
// this will keep bitmap transparency
Paint().apply {
xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR)
canvas.drawRect(
Rect(left, top, bitmap.width - right, bitmap.height - bottom),
this
)
}
// finally, draw bitmap on canvas
Paint().apply {
canvas.drawBitmap(
this@addPadding, // bitmap
0f + left, // left
0f + top, // top
this // paint
)
}
return bitmap
}
// extension function to add border to bitmap
private fun Bitmap.addBorder(
color: Int = Color.DKGRAY,
borderWidth: Int = 10
): Bitmap? {
val bitmap = Bitmap.createBitmap(
width + borderWidth * 2, // width in pixels
height + borderWidth * 2, // height in pixels
Bitmap.Config.ARGB_8888
)
val canvas = Canvas(bitmap)
// draw solid color on full canvas area
canvas.drawColor(color)
// clear color from bitmap drawing area
// this is very important for transparent bitmap border
// this will keep bitmap transparency
Paint().apply {
xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR)
canvas.drawRect(
Rect(
borderWidth, // left
borderWidth, // top
bitmap.width - borderWidth, // right
bitmap.height - borderWidth // bottom
),
this
)
}
// finally, draw bitmap on canvas
Paint().apply {
canvas.drawBitmap(
this@addBorder, // bitmap
0f + borderWidth, // left
0f + borderWidth, // top
this // paint
)
}
return bitmap
}
// extension function to get bitmap from assets
private fun Context.assetsToBitmap(fileName: String): Bitmap? {
return try {
val stream = assets.open(fileName)
BitmapFactory.decodeStream(stream)
} catch (e: IOException) {
e.printStackTrace()
null
}
}
// extension function to crop circular area from bitmap
private fun Bitmap.cropCircularArea(): Bitmap? {
val bitmap = Bitmap.createBitmap(
width, // width in pixels
height, // height in pixels
Bitmap.Config.ARGB_8888
)
val canvas = Canvas(bitmap)
// create a circular path
val path = Path()
val radius = min(width / 2f, height / 2f)
path.apply {
addCircle(
width / 2f,
height / 2f,
radius,
Path.Direction.CCW
)
}
// draw circular bitmap on canvas
canvas.clipPath(path)
canvas.drawBitmap(this, 0f, 0f, null)
val diameter = (radius * 2).toInt()
val x = (width - diameter) / 2
val y = (height - diameter) / 2
// return cropped circular bitmap
return Bitmap.createBitmap(
bitmap, // source bitmap
x, // x coordinate of the first pixel in source
y, // y coordinate of the first pixel in source
diameter, // width
diameter // height
)
}
// extension function to create circular bitmap with border
private fun Bitmap.borderedCircularBitmap(
borderColor: Int = Color.LTGRAY,
borderWidth: Int = 10
): Bitmap? {
val bitmap = Bitmap.createBitmap(
width, // width in pixels
height, // height in pixels
Bitmap.Config.ARGB_8888
)
// canvas to draw circular bitmap
val canvas = Canvas(bitmap)
// get the maximum radius
val radius = min(width / 2f, height / 2f)
// create a path to draw circular bitmap border
val borderPath = Path().apply {
addCircle(
width / 2f,
height / 2f,
radius,
Path.Direction.CCW
)
}
// draw border on circular bitmap
canvas.clipPath(borderPath)
canvas.drawColor(borderColor)
// create a path for circular bitmap
val bitmapPath = Path().apply {
addCircle(
width / 2f,
height / 2f,
radius - borderWidth,
Path.Direction.CCW
)
}
canvas.clipPath(bitmapPath)
val paint = Paint().apply {
xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR)
isAntiAlias = true
}
// clear the circular bitmap drawing area
// it will keep bitmap transparency
canvas.drawBitmap(this, 0f, 0f, paint)
// now draw the circular bitmap
canvas.drawBitmap(this, 0f, 0f, null)
val diameter = (radius * 2).toInt()
val x = (width - diameter) / 2
val y = (height - diameter) / 2
// return cropped circular bitmap with border
return Bitmap.createBitmap(
bitmap, // source bitmap
x, // x coordinate of the first pixel in source
y, // y coordinate of the first pixel in source
diameter, // width
diameter // height
)
}
// extension function to create rounded corners bitmap
private fun Bitmap.toRoundedCorners(
cornerRadius: Float = 25F
): Bitmap? {
val bitmap = Bitmap.createBitmap(
width, // width in pixels
height, // height in pixels
Bitmap.Config.ARGB_8888
)
val canvas = Canvas(bitmap)
// path to draw rounded corners bitmap
val path = Path().apply {
addRoundRect(
RectF(0f, 0f, width.toFloat(), height.toFloat()),
cornerRadius,
cornerRadius,
Path.Direction.CCW
)
}
canvas.clipPath(path)
// draw the rounded corners bitmap on canvas
canvas.drawBitmap(this, 0f, 0f, null)
return bitmap
}
// extension function to crop bitmap to square
private fun Bitmap.toSquare(): Bitmap? {
// get the small side of bitmap
val side = min(width, height)
// calculate the x and y offset
val xOffset = (width - side) / 2
val yOffset = (height - side) / 2
// create a square bitmap
// a square is closed, two dimensional shape with 4 equal sides
return Bitmap.createBitmap(
this, // source bitmap
xOffset, // x coordinate of the first pixel in source
yOffset, // y coordinate of the first pixel in source
side, // width
side // height
)
}
// extension function to crop bitmap rectangle area
private fun Bitmap.cropRectangle(
xOffset: Int = 0,
yOffset: Int = 0,
newWidth: Int = this.width,
newHeight: Int = this.height
): Bitmap? {
return try {
Bitmap.createBitmap(
this, // source bitmap
xOffset, // x coordinate of the first pixel in source
yOffset, // y coordinate of the first pixel in source
newWidth, // width in pixels
newHeight // height in pixels
)
} catch (e: IllegalArgumentException) {
null
}
}
// extension function to crop bitmap center
// it return square bitmap when no parameters pass
private fun Bitmap.cropCenter(
newWidth: Int = min(width, height),
newHeight: Int = min(width, height)
): Bitmap? {
// calculate x and y offset
val xOffset = (width - newWidth) / 2
val yOffset = (height - newHeight) / 2
return try {
Bitmap.createBitmap(
this, // source bitmap
xOffset, // x coordinate of the first pixel in source
yOffset, // y coordinate of the first pixel in source
newWidth, // new width
newHeight // new height
)
} catch (e: IllegalArgumentException) {
null
}
}
// extension function to remove bitmap transparency
private fun Bitmap.removeTransparency(backgroundColor: Int = Color.WHITE): Bitmap? {
val bitmap = copy(config, true)
var alpha: Int
var red: Int
var green: Int
var blue: Int
var pixel: Int
// scan through all pixels
for (x in 0 until width) {
for (y in 0 until height) {
pixel = getPixel(x, y)
alpha = Color.alpha(pixel)
red = Color.red(pixel)
green = Color.green(pixel)
blue = Color.blue(pixel)
if (alpha == 0) {
// if pixel is full transparent then
// replace it by solid background color
bitmap.setPixel(x, y, backgroundColor)
} else {
// if pixel is partially transparent then
// set pixel full opaque
val color = Color.argb(
255,
red,
green,
blue
)
bitmap.setPixel(x, y, color)
}
}
}
return bitmap
}
// extension function to mask bitmap
private fun Bitmap.mask(mask: Bitmap): Bitmap? {
val bitmap = Bitmap.createBitmap(
mask.width, mask.height, Bitmap.Config.ARGB_8888
)
// paint to mask
val paint = Paint().apply {
isAntiAlias = true
xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_IN)
}
Canvas(bitmap).apply {
// draw source bitmap on canvas
drawBitmap(this@mask, 0f, 0f, null)
// mask bitmap
drawBitmap(mask, 0f, 0f, paint)
}
return bitmap
}
// filter bitmap
private fun gray() {
operation = Bitmap.createBitmap(bmp.width, bmp.height, bmp.config)
val red = 0.33
val green = 0.59
val blue = 0.11
for (i in 0 until bmp.width) {
for (j in 0 until bmp.height) {
val p = bmp.getPixel(i, j)
var r: Int = Color.red(p)
var g: Int = Color.green(p)
var b: Int = Color.blue(p)
r *= red.toInt()
g *= green.toInt()
b *= blue.toInt()
operation.setPixel(i, j, Color.argb(Color.alpha(p), r, g, b))
}
}
mainActivity_imageView_testBitmap.setImageBitmap(operation)
}
private fun bright() {
operation = Bitmap.createBitmap(bmp.width, bmp.height, bmp.config)
for (i in 0 until bmp.width) {
for (j in 0 until bmp.height) {
val p = bmp.getPixel(i, j)
var r = Color.red(p)
var g = Color.green(p)
var b = Color.blue(p)
var alpha = Color.alpha(p)
r += 100
g += 100
b += 100
alpha += 100
operation.setPixel(i, j, Color.argb(alpha, r, g, b))
}
}
mainActivity_imageView_testBitmap.setImageBitmap(operation)
}
private fun dark() {
operation = Bitmap.createBitmap(bmp.width, bmp.height, bmp.config)
for (i in 0 until bmp.width) {
for (j in 0 until bmp.height) {
val p = bmp.getPixel(i, j)
var r = Color.red(p)
var g = Color.green(p)
var b = Color.blue(p)
var alpha = Color.alpha(p)
r -= 50
g -= 50
b -= 50
alpha -= 50
operation.setPixel(i, j, Color.argb(Color.alpha(p), r, g, b))
}
}
mainActivity_imageView_testBitmap.setImageBitmap(operation)
}
private fun gama() {
operation = Bitmap.createBitmap(bmp.width, bmp.height, bmp.config)
for (i in 0 until bmp.width) {
for (j in 0 until bmp.height) {
val p = bmp.getPixel(i, j)
var r = Color.red(p)
var g = Color.green(p)
var b = Color.blue(p)
var alpha = Color.alpha(p)
r += 150
g = 0
b = 0
alpha = 0
operation.setPixel(i, j, Color.argb(Color.alpha(p), r, g, b))
}
}
mainActivity_imageView_testBitmap.setImageBitmap(operation)
}
private fun green() {
operation = Bitmap.createBitmap(bmp.width, bmp.height, bmp.config)
for (i in 0 until bmp.width) {
for (j in 0 until bmp.height) {
val p = bmp.getPixel(i, j)
var r = Color.red(p)
var g = Color.green(p)
var b = Color.blue(p)
var alpha = Color.alpha(p)
r = 0
g += 150
b = 0
alpha = 0
operation.setPixel(i, j, Color.argb(Color.alpha(p), r, g, b))
}
}
mainActivity_imageView_testBitmap.setImageBitmap(operation)
}
private fun blue() {
operation = Bitmap.createBitmap(bmp.width, bmp.height, bmp.config)
for (i in 0 until bmp.width) {
for (j in 0 until bmp.height) {
val p = bmp.getPixel(i, j)
var r = Color.red(p)
var g = Color.green(p)
var b = Color.blue(p)
var alpha = Color.alpha(p)
r = 0
g = 0
b = b + 150
alpha = 0
operation.setPixel(i, j, Color.argb(Color.alpha(p), r, g, b))
}
}
mainActivity_imageView_testBitmap.setImageBitmap(operation)
}
}
実行
最後にプロジェクトを実行します。
リファレンス
ダウンロードは以下のリンクから行ってください。
1. | コードのダウンロード | 2. |
2. | コード作者をフォロー |
その他の簡単な例
Android Bitmap Tutorial and Examples.
いくつかの簡単な例を紹介します。
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.util.Base64;
import android.util.Log;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
public class ImageUtils {
private static final String TAG = "ImageUtils";
public static byte[] bitmap2Bytes(Bitmap bitmap, int quality, Bitmap.CompressFormat format){
if (bitmap == null){
return null;
}else {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
bitmap.compress(format,quality,outputStream);
try {
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
return outputStream.toByteArray();
}
}
public static String bitmap2Base64(Bitmap bitmap, int quality, Bitmap.CompressFormat format){
byte[] bytes = bitmap2Bytes(bitmap,quality,format);
return Base64.encodeToString(bytes,Base64.DEFAULT)
.replace("n","")
.replace("r","")
.replace("t","");
}
public static Bitmap scaleBitmap(Bitmap srcBitmap, int maxWidth, int maxHeight){
int width = srcBitmap.getWidth();
int height = srcBitmap.getHeight();
Log.d(TAG, "scaleBitmap: nwidth = " + width + "nheight = " + height);
int desiredWidth = Math.min(width,maxWidth);
int desiredHeight = Math.min(height,maxHeight);
float scaleWidth = ((float) desiredWidth / width);
float scaleHeight = ((float) desiredHeight / height);
float scaled = Math.min(scaleHeight,scaleWidth);
Matrix matrix = new Matrix();
matrix.postScale(scaled,scaled);
return Bitmap.createBitmap(srcBitmap,0,0,width,height,matrix,true);
}
public static Bitmap convert2Gray(Bitmap bitmap) {
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int[] pixs = new int[width * height];
bitmap.getPixels(pixs, 0, width, 0, 0, width, height);
int alpha = 0xFF << 24;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
int color = pixs[width * i + j];
int red = (color & 0x00FF0000) >> 16;
int green = (color & 0x0000FF00) >> 8;
int blue = (color & 0x000000FF);
color = (red + green + blue) / 3;
color = alpha | (color << 16) | (color << 8)| color;
pixs[width * i + j] = color;
}
}
Bitmap result = Bitmap.createBitmap(width,height, Bitmap.Config.RGB_565);
result.setPixels(pixs,0,width,0,0,width,height);
return result;
}
}
1. ウェブからのビットマップのダウンロード
HttpURLConnectionクラスを使って、インターネットからビットマップをダウンロードする方法を見てみましょう。
private Bitmap downloadUrl(String myurl) throws IOException {
try {
URL url = new URL(myurl);
HttpURLConnection connection = (HttpURLConnection) url
.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
Bitmap myBitmap = BitmapFactory.decodeStream(input);
return myBitmap;
} catch (IOException e) {
return null;
}
}
AsyncTaskを使った完全な例を示します。
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class HttpImageGetTask extends AsyncTask<String, Void, Bitmap> {
private OnImageDownloadCompleted listener;
public HttpImageGetTask(OnImageDownloadCompleted listener) {
this.listener = listener;
}
@Override
protected Bitmap doInBackground(String... urls) {
try {
return downloadUrl(urls[0]);
} catch (IOException e) {
return null;
}
}
@Override
protected void onPostExecute(Bitmap result) {
listener.onBitmapCompleted(result);
}
private Bitmap downloadUrl(String myurl) throws IOException {
try {
URL url = new URL(myurl);
HttpURLConnection connection = (HttpURLConnection) url
.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
Bitmap myBitmap = BitmapFactory.decodeStream(input);
return myBitmap;
} catch (IOException e) {
return null;
}
}
}
2. 文字列のMD5を取得する方法
これは、以下のいくつかの例で使用するヘルパー・メソッドです。
public static String getMD5(String content) {
try {
MessageDigest digest = MessageDigest.getInstance("MD5");
digest.update(content.getBytes());
return getHashString(digest);
} catch (Exception e) {
}
return null;
}
3. ファイルシステムからImageViewにビットマップをロードする方法
ファイルシステムからビットマップをロードすることもできます。ただし、URLではなく、イメージのパスを渡す必要があります。
public static Bitmap getBitmap2(String imagePath) {
if (!(imagePath.length() > 5)) {
return null;
}
File cache_file = new File(new File(
Environment.getExternalStorageDirectory(), "xxxx"),
"cachebitmap");
cache_file = new File(cache_file, getMD5(imagePath));
if (cache_file.exists()) {
return BitmapFactory.decodeFile(getBitmapCache(imagePath));
} else {
try {
URL url = new URL(imagePath);
HttpURLConnection conn = (HttpURLConnection) url
.openConnection();
conn.setConnectTimeout(5000);
if (conn.getResponseCode() == 200) {
InputStream inStream = conn.getInputStream();
File file = new File(new File(
Environment.getExternalStorageDirectory(), "xxxx"),
"cachebitmap");
if (!file.exists()) {
file.mkdirs();
}
file = new File(file, getMD5(imagePath));
FileOutputStream out = new FileOutputStream(file);
byte buff[] = new byte[1024];
int len = 0;
while ((len = inStream.read(buff)) != -1) {
out.write(buff, 0, len);
}
out.close();
inStream.close();
return BitmapFactory.decodeFile(getBitmapCache(imagePath));
}
} catch (Exception e) {
}
}
return null;
}
4.ビットマップキャッシュの取得方法
public static String getBitmapCache(String url) {
File file = new File(new File(
Environment.getExternalStorageDirectory(), "xxxx"),
"cachebitmap");
file = new File(file, getMD5(url));
if (file.exists()) {
return file.getAbsolutePath();
}
return null;
}
5. Glideを使ってImageViewにビットマップをロードする方法
public static void displayImageBitmap(String url,ImageView imageView) {
Glide.with(MainApp.getContext())
.load(url)
.asBitmap()
.thumbnail(0.2f)
.placeholder(R.drawable.pictures_no)
.diskCacheStrategy(DiskCacheStrategy.SOURCE)
.into(imageView);
}
6. MessageDigestのハッシュ文字列を取得する方法
private static String getHashString(MessageDigest digest) {
StringBuilder builder = new StringBuilder();
for (byte b : digest.digest()) {
builder.append(Integer.toHexString((b >> 4) & 0xf));
builder.append(Integer.toHexString(b & 0xf));
}
return builder.toString().toLowerCase();
}
7. ビットマップをローカルファイルに保存する方法
ビットマップを保存したいFileオブジェクトを渡します。ビットマップは、メソッドのパラメータとしても渡されます。
public static String saveBitmapToLocal(File file , Bitmap bitmap) {
try {
if(!file.exists()) {
file.createNewFile();
}
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(file));
bitmap.compress(Bitmap.CompressFormat.PNG, 100, bufferedOutputStream);
bufferedOutputStream.close();
LogUtil.d(TAG, "photo image from data, path:" + file.getAbsolutePath());
return file.getAbsolutePath();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
8. 画像からサムネイルを抽出する方法
次に、ビットマップを返します。画像へのパスは、サムネイルの寸法と、画像をトリミングするかどうかと一緒に渡されます。
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static Bitmap extractThumbNail(final String path, final int width, final int height, final boolean crop) {
Assert.assertTrue(path != null && !path.equals("") && height > 0 && width > 0);
BitmapFactory.Options options = new BitmapFactory.Options();
try {
options.inJustDecodeBounds = true;
Bitmap tmp = BitmapFactory.decodeFile(path);
if (tmp != null) {
tmp.recycle();
tmp = null;
}
LogUtil.d(TAG, "extractThumbNail: round=" + width + "x" + height + ", crop=" + crop);
final double beY = options.outHeight * 1.0 / height;
final double beX = options.outWidth * 1.0 / width;
LogUtil.d(TAG, "extractThumbNail: extract beX = " + beX + ", beY = " + beY);
options.inSampleSize = (int) (crop ? (beY > beX ? beX : beY) : (beY < beX ? beX : beY));
if (options.inSampleSize <= 1) {
options.inSampleSize = 1;
}
// NOTE: out of memory error
while (options.outHeight * options.outWidth / options.inSampleSize > MAX_DECODE_PICTURE_SIZE) {
options.inSampleSize++;
}
int newHeight = height;
int newWidth = width;
if (crop) {
if (beY > beX) {
newHeight = (int) (newWidth * 1.0 * options.outHeight / options.outWidth);
} else {
newWidth = (int) (newHeight * 1.0 * options.outWidth / options.outHeight);
}
} else {
if (beY < beX) {
newHeight = (int) (newWidth * 1.0 * options.outHeight / options.outWidth);
} else {
newWidth = (int) (newHeight * 1.0 * options.outWidth / options.outHeight);
}
}
options.inJustDecodeBounds = false;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
options.inMutable = true;
}
LogUtil.i(TAG, "bitmap required size=" + newWidth + "x" + newHeight + ", orig=" + options.outWidth + "x" + options.outHeight + ", sample=" + options.inSampleSize);
Bitmap bm = BitmapFactory.decodeFile(path);
setInNativeAlloc(options);
if (bm == null) {
Log.e(TAG, "bitmap decode failed");
return null;
}
LogUtil.i(TAG, "bitmap decoded size=" + bm.getWidth() + "x" + bm.getHeight());
final Bitmap scale = Bitmap.createScaledBitmap(bm, newWidth, newHeight, true);
if (scale != null) {
bm.recycle();
bm = scale;
}
if (crop) {
final Bitmap cropped = Bitmap.createBitmap(bm, (bm.getWidth() - width) >> 1, (bm.getHeight() - height) >> 1, width, height);
if (cropped == null) {
return bm;
}
bm.recycle();
bm = cropped;
LogUtil.i(TAG, "bitmap croped size=" + bm.getWidth() + "x" + bm.getHeight());
}
return bm;
} catch (final OutOfMemoryError e) {
LogUtil.e(TAG, "decode bitmap failed: " + e.getMessage());
options = null;
}
return null;
}
9. ストリームをビットマップにデコードする方法
public static Bitmap decodeStream(InputStream stream , float dip) {
BitmapFactory.Options options = new BitmapFactory.Options();
if(dip != 0.0F) {
options.inDensity = (int)(160.0F * dip);
}
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
setInNativeAlloc(options);
try {
Bitmap bitmap = BitmapFactory.decodeStream(stream, null,options);
return bitmap;
} catch (OutOfMemoryError e) {
options.inPreferredConfig = Bitmap.Config.RGB_565;
setInNativeAlloc(options);
try {
Bitmap bitmap = BitmapFactory.decodeStream(stream, null,options);
return bitmap;
} catch (OutOfMemoryError e2) {
}
}
return null;
}
10. 新しいビットマップを作るには
public static Bitmap newBitmap(int width, int height,Bitmap.Config config) {
try {
Bitmap bitmap = Bitmap.createBitmap(width, height,config);
return bitmap;
} catch (Throwable localThrowable) {
LogUtil.e(TAG, localThrowable.getMessage());
}
return null;
}
11. ビットマップを配列に変換する方法
パラメータとしてビットマップを渡すと、それを圧縮してバイト配列に変換します。
public static byte[] bmpToByteArray(final Bitmap bmp, final boolean needRecycle) {
ByteArrayOutputStream output = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.PNG, 100, output);
if (needRecycle) {
bmp.recycle();
}
byte[] result = output.toByteArray();
try {
output.close();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
12. ファイル名からビットマップを読み込む方法
さらに簡単な例として、ファイル名からビットマップを読み込み、それを返す方法を紹介します。
public static Bitmap loadFromFile(String filename) {
try {
File f = new File(filename);
if (!f.exists()) {
return null;
}
Bitmap tmp = BitmapFactory.decodeFile(filename);
// tmp = setExifInfo(filename, tmp);
return tmp;
} catch (Exception e) {
return null;
}
}
13. 画像を圧縮する方法
画像を圧縮して、ビットマップとして返します。基本的には、ビットマップを渡すと、それを圧縮して返してくれます。
public Bitmap compressImage(Bitmap image) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
int options = 100;
while (baos.toByteArray().length / 1024 > 128) {
baos.reset();
image.compress(Bitmap.CompressFormat.JPEG,options, baos);/
options -= 10;
}
ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);
// bitmap.
return bitmap;
}
14. パスからビットマップを読み込む方法
画像のパスを渡すだけで、BitmapFactory
のdecodeFile
メソッドを使ってファイルをデコードします。
public static Bitmap loadBitmap(String imgpath) {
return BitmapFactory.decodeFile(imgpath);
}
15. ビットマップを拡大縮小するには
ビットマップの幅と高さを渡すと、それをスケールします。
private static Bitmap scaleBitmap(Bitmap bitmap, float ww, float hh) {
double scaleWidth = 1;
double scaleHeight = 1;
int widthOri = bitmap.getWidth();
int heightOri = bitmap.getHeight();
if (widthOri > heightOri && widthOri > ww) {
scaleWidth = 1.0 / (double) (widthOri / ww);
scaleHeight = scaleWidth;
} else if (widthOri < heightOri && heightOri > hh) {
scaleHeight = 1.0 / (double) (heightOri / hh);
scaleWidth = scaleHeight;
}
Matrix matrix = new Matrix();
matrix.postScale((float) scaleWidth, (float) scaleHeight);
Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0,
bitmap.getWidth(), bitmap.getHeight(), matrix, true);
16. スクリーンショットをキャプチャして、バイトとして返す方法
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.View;
public class ScreenShotUtil {
public static Bitmap capture(View view, float width, float height, boolean scroll, Bitmap.Config config) {
if (!view.isDrawingCacheEnabled()) {
view.setDrawingCacheEnabled(true);
}
if(width==0){
width= MainApp.getInstance().getScreenWidth();
}
if(height==0){
height= MainApp.getInstance().getScreenHeight();
}
Bitmap bitmap = Bitmap.createBitmap((int) width, (int) height, config);
bitmap.eraseColor(Color.WHITE);
Canvas canvas = new Canvas(bitmap);
int left = view.getLeft();
int top = view.getTop();
if (scroll) {
left = view.getScrollX();
top = view.getScrollY();
}
int status = canvas.save();
canvas.translate(-left, -top);
float scale = width / view.getWidth();
canvas.scale(scale, scale, left, top);
view.draw(canvas);
canvas.restoreToCount(status);
Paint alphaPaint = new Paint();
alphaPaint.setColor(Color.TRANSPARENT);
canvas.drawRect(0f, 0f, 1f, height, alphaPaint);
canvas.drawRect(width - 1f, 0f, width, height, alphaPaint);
canvas.drawRect(0f, 0f, width, 1f, alphaPaint);
canvas.drawRect(0f, height - 1f, width, height, alphaPaint);
canvas.setBitmap(null);
return bitmap;
}
}
17. ビットマップをBase64文字列に変換する方法
public static String convertBitmapToString(Bitmap bitmap) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();// outputstream
bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] b = baos.toByteArray();
return Base64.encodeToString(b, Base64.DEFAULT);
}
18. 文字列をビットマップに変換する方法
public static Bitmap convertStringToBitmap(String st) {
// OutputStream out;
Bitmap bitmap = null;
try
{
// out = new FileOutputStream("/sdcard/aa.jpg");
byte[] bitmapArray;
bitmapArray = Base64.decode(st, Base64.DEFAULT);
bitmap = BitmapFactory.decodeByteArray(bitmapArray, 0, bitmapArray.length);
// bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
return bitmap;
}
catch (Exception e)
{
return null;
}
19. 指定されたビューからビットマップを作成する方法。
ビットマップを作成してほしいビューを指定します。
public static Bitmap createBitmapFromView(View view) {
final Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(bitmap);
view.layout(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
view.draw(canvas);
return bitmap;
}