Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Init color array when decode for bitmap #6147

Merged
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
c563119
Init color array when decodeStream to create Bitmap
utzcoz Jan 8, 2021
71aff26
Move color array initialization to a single method
utzcoz Jan 8, 2021
93c46cf
Init color array when decodeByteArray to create Bitmap
utzcoz Jan 8, 2021
b38a53f
Add color array test for BitmapFactory.decodeResourceStream
utzcoz Jan 9, 2021
c5c60d6
Rename getPngImageColor to getPngImageColorFromStream
utzcoz Jan 9, 2021
c3c3bb2
Init color arrary when decodeResource to create Bitmap
utzcoz Jan 9, 2021
5fc7b4d
Init color arrary when decodeFile to create Bitmap
utzcoz Jan 9, 2021
a1af698
Fix BitmapTest.testExtractAlpha with correct assert statement
utzcoz Jan 9, 2021
32eba2b
Fix logger info of initializating color
utzcoz Jan 16, 2021
383143a
Compress bitmap to file with color array
utzcoz Jan 16, 2021
ad062fb
Add test to check sameAs after decodeStream
utzcoz Jan 27, 2021
5662015
Bring back jpg format support for ImageWriter
utzcoz Feb 15, 2021
fd8cac0
Use google common io Resources.toByteArray to read byte array
utzcoz Feb 25, 2021
2cb2539
Add null check for ImageUtil.getBufferedImageType
utzcoz Feb 25, 2021
e4f6ea6
Keep alpha value to alpha channel bit for Bitmap.extractAlpha
utzcoz Feb 26, 2021
b8898ec
Add test for webp non-100% quality compress
utzcoz Feb 26, 2021
10df7ee
Resue InputStream to get all image info for ShadowBitmapFactory.decod…
utzcoz Mar 3, 2021
6e14e8f
Add image/ before image format to get mimeType directly
utzcoz Mar 7, 2021
957fa0e
Remove unused config and exception for ShadowBitmapFactoryTest
utzcoz Mar 7, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,32 +1,46 @@
package org.robolectric.shadows;

import static android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH;
import static com.google.common.io.Resources.toByteArray;
import static com.google.common.truth.Truth.assertThat;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertEquals;
import static org.robolectric.Shadows.shadowOf;

import android.app.Application;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.Point;
import android.net.Uri;
import android.os.Build;
import android.provider.MediaStore;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.R;
import org.robolectric.annotation.Config;

@RunWith(AndroidJUnit4.class)
public class ShadowBitmapFactoryTest {
private static final int TEST_JPEG_WIDTH = 50;
private static final int TEST_JPEG_HEIGHT = 50;

private Application context;

Expand Down Expand Up @@ -67,6 +81,27 @@ public void decodeResource_shouldPassABitmapConfig() {
assertThat(bitmap.getConfig()).isEqualTo(Bitmap.Config.ALPHA_8);
}

@Test
public void decodeResource_sameAs() throws IOException {
Resources resources = context.getResources();
Bitmap bitmap = BitmapFactory.decodeResource(resources, R.drawable.an_image);
File tmp = Files.createTempFile("BitmapTest", null).toFile();
try (FileOutputStream stream = new FileOutputStream(tmp)) {
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
}
FileInputStream fileInputStream = new FileInputStream(tmp);
Bitmap bitmap2 = BitmapFactory.decodeStream(fileInputStream);
assertThat(bitmap.sameAs(bitmap2)).isTrue();
}

@Test
public void decodeResource_shouldGetCorrectColorFromPngImage() {
Resources resources = context.getResources();
BitmapFactory.Options opts = new BitmapFactory.Options();
Bitmap bitmap = BitmapFactory.decodeResource(resources, R.drawable.an_image, opts);
assertThat(bitmap.getPixel(0, 0) != 0).isTrue();
}

@Test
public void decodeFile_shouldSetDescriptionAndCreatedFrom() {
Bitmap bitmap = BitmapFactory.decodeFile("/some/file.jpg");
Expand Down Expand Up @@ -150,6 +185,15 @@ public void decodeResourceStream_canTakeOptions() throws Exception {
assertEquals(true, shadowOf(bitmap).getDescription().contains("inSampleSize=100"));
}

@Test
public void decodeResourceStream_shouldGetCorrectColorFromPngImage() throws Exception {
assertEquals(Color.BLACK, getPngImageColorFromResourceStream("res/drawable/pure_black.png"));
assertEquals(Color.BLUE, getPngImageColorFromResourceStream("res/drawable/pure_blue.png"));
assertEquals(Color.GREEN, getPngImageColorFromResourceStream("res/drawable/pure_green.png"));
assertEquals(Color.RED, getPngImageColorFromResourceStream("res/drawable/pure_red.png"));
assertEquals(Color.WHITE, getPngImageColorFromResourceStream("res/drawable/pure_white.png"));
}

@Test
public void decodeFile_shouldGetWidthAndHeightFromHints() {
ShadowBitmapFactory.provideWidthAndHeightHints("/some/file.jpg", 123, 456);
Expand Down Expand Up @@ -223,6 +267,15 @@ public void decodeByteArray_shouldIncludeOffsets() {
assertEquals("Bitmap for " + data + " bytes 1..13", shadowOf(bitmap).getDescription());
}

@Test
public void decodeByteArray_shouldGetCorrectColorFromPngImage() throws Exception {
assertEquals(Color.BLACK, getPngImageColorFromByteArray("res/drawable/pure_black.png"));
assertEquals(Color.BLUE, getPngImageColorFromByteArray("res/drawable/pure_blue.png"));
assertEquals(Color.GREEN, getPngImageColorFromByteArray("res/drawable/pure_green.png"));
assertEquals(Color.RED, getPngImageColorFromByteArray("res/drawable/pure_red.png"));
assertEquals(Color.WHITE, getPngImageColorFromByteArray("res/drawable/pure_white.png"));
}

@Test
public void decodeStream_shouldGetWidthAndHeightFromHints() throws Exception {
ShadowBitmapFactory.provideWidthAndHeightHints(Uri.parse("content:/path"), 123, 456);
Expand Down Expand Up @@ -278,6 +331,26 @@ public void decodeStream_shouldGetCorrectMimeTypeFromGifImage() throws Exception
assertEquals("image/gif", opts.outMimeType);
}

@Test
public void decodeStream_shouldGetCorrectColorFromPngImage() throws Exception {
assertEquals(Color.BLACK, getPngImageColorFromStream("res/drawable/pure_black.png"));
assertEquals(Color.BLUE, getPngImageColorFromStream("res/drawable/pure_blue.png"));
assertEquals(Color.GREEN, getPngImageColorFromStream("res/drawable/pure_green.png"));
assertEquals(Color.RED, getPngImageColorFromStream("res/drawable/pure_red.png"));
assertEquals(Color.WHITE, getPngImageColorFromStream("res/drawable/pure_white.png"));
}

@Test
public void decodeStream_shouldSameAsCompressedBefore() throws Exception {
Bitmap bitmap = Bitmap.createBitmap(/* width= */ 10, /* height= */ 10, Bitmap.Config.ARGB_8888);
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, /* quality= */ 100, outStream);
byte[] outBytes = outStream.toByteArray();
ByteArrayInputStream inStream = new ByteArrayInputStream(outBytes);
Bitmap newBitmap = BitmapFactory.decodeStream(inStream);
assertThat(bitmap.sameAs(newBitmap)).isTrue();
}

@Test
public void decodeWithDifferentSampleSize() {
String name = "test";
Expand Down Expand Up @@ -325,28 +398,73 @@ public void createShouldSetSizeToHardcodedValueAsLastPriority() {
assertThat(bitmap.getHeight()).isEqualTo(100);
}

@Test
public void decodeFile_shouldGetCorrectColorFromPngImage() {
int color = Color.RED;
String pathName =
getClass().getClassLoader().getResource("res/drawable/pure_red.png").getPath();
Bitmap bitmap = BitmapFactory.decodeFile(pathName);
assertEquals(color, bitmap.getPixel(0, 0));
bitmap.recycle();
}

@Test
public void decodeFile_shouldHaveCorrectWidthAndHeight() throws IOException {
Bitmap bitmap = Bitmap.createBitmap(500, 600, Bitmap.Config.ARGB_8888);
assertThat(bitmap.getWidth()).isEqualTo(500);
assertThat(bitmap.getHeight()).isEqualTo(600);
Bitmap bitmap = getBitmapFromResourceStream("res/drawable/test_jpeg.jpg");
assertThat(bitmap.getWidth()).isEqualTo(TEST_JPEG_WIDTH);
assertThat(bitmap.getHeight()).isEqualTo(TEST_JPEG_HEIGHT);
File tmpFile = File.createTempFile("ShadowBitmapFactoryTest", ".jpg");
tmpFile.deleteOnExit();
try (FileOutputStream fileOutputStream = new FileOutputStream(tmpFile)) {
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, fileOutputStream);
}
bitmap.recycle();
Bitmap loadedBitmap = BitmapFactory.decodeFile(tmpFile.getAbsolutePath());
assertThat(loadedBitmap.getWidth()).isEqualTo(500);
assertThat(loadedBitmap.getHeight()).isEqualTo(600);
assertThat(loadedBitmap.getWidth()).isEqualTo(TEST_JPEG_WIDTH);
assertThat(loadedBitmap.getHeight()).isEqualTo(TEST_JPEG_HEIGHT);
loadedBitmap.recycle();
}

@Test
public void decodeFile_shouldGetCorrectColorFromCompressedPngFile()
throws IOException, URISyntaxException {
decodeFile_shouldGetCorrectColorFromCompressedFile(
Bitmap.CompressFormat.PNG,
getBitmapByteArrayFromResourceStream("res/drawable/an_image.png"));
}

@Test
@Config(minSdk = ICE_CREAM_SANDWICH)
utzcoz marked this conversation as resolved.
Show resolved Hide resolved
public void decodeFile_shouldGetCorrectColorFromCompressedWebpFile()
throws IOException, URISyntaxException {
decodeFile_shouldGetCorrectColorFromCompressedFile(
Bitmap.CompressFormat.WEBP,
getBitmapByteArrayFromResourceStream("res/drawable/test_webp.webp"));
}

@Test
@Config(minSdk = Build.VERSION_CODES.R)
public void decodeFile_shouldGetCorrectColorFromCompressedWebpLossyFile()
throws IOException, URISyntaxException {
decodeFile_shouldGetCorrectColorFromCompressedFile(
Bitmap.CompressFormat.WEBP_LOSSY,
getBitmapByteArrayFromResourceStream("res/drawable/test_webp_lossy.webp"));
}

@Test
@Config(minSdk = Build.VERSION_CODES.R)
public void decodeFile_shouldGetCorrectColorFromCompressedWebpLosslessFile()
throws IOException, URISyntaxException {
decodeFile_shouldGetCorrectColorFromCompressedFile(
Bitmap.CompressFormat.WEBP_LOSSLESS,
getBitmapByteArrayFromResourceStream("res/drawable/test_webp_lossless.webp"));
}

@Test
public void decodeFileDescriptor_shouldHaveCorrectWidthAndHeight() throws IOException {
Bitmap bitmap = Bitmap.createBitmap(500, 600, Bitmap.Config.ARGB_8888);
assertEquals(500, bitmap.getWidth());
assertEquals(600, bitmap.getHeight());
Bitmap bitmap = getBitmapFromResourceStream("res/drawable/test_jpeg.jpg");
assertThat(bitmap.getWidth()).isEqualTo(TEST_JPEG_WIDTH);
assertThat(bitmap.getHeight()).isEqualTo(TEST_JPEG_HEIGHT);

File tmpFile = File.createTempFile("ShadowBitmapFactoryTest", ".jpg");
tmpFile.deleteOnExit();
Expand All @@ -356,9 +474,64 @@ public void decodeFileDescriptor_shouldHaveCorrectWidthAndHeight() throws IOExce
bitmap.recycle();
try (FileInputStream fileInputStream = new FileInputStream(tmpFile)) {
Bitmap loadedBitmap = BitmapFactory.decodeFileDescriptor(fileInputStream.getFD());
assertEquals(500, loadedBitmap.getWidth());
assertEquals(600, loadedBitmap.getHeight());
assertThat(loadedBitmap.getWidth()).isEqualTo(TEST_JPEG_WIDTH);
assertThat(loadedBitmap.getHeight()).isEqualTo(TEST_JPEG_HEIGHT);
loadedBitmap.recycle();
}
}

private void decodeFile_shouldGetCorrectColorFromCompressedFile(
Bitmap.CompressFormat format, byte[] bitmapData) throws IOException {
Bitmap oldBitmap = BitmapFactory.decodeByteArray(bitmapData, 0, bitmapData.length);
Path tempFile = Files.createTempFile("bitmap", null);
FileOutputStream fileOutputStream = new FileOutputStream(tempFile.toFile());
// lossless compression
oldBitmap.compress(format, 100, fileOutputStream);
fileOutputStream.close();
Bitmap newBitmap = BitmapFactory.decodeFile(tempFile.toAbsolutePath().toString());

ByteBuffer oldBuffer = ByteBuffer.allocate(oldBitmap.getHeight() * oldBitmap.getRowBytes());
oldBitmap.copyPixelsToBuffer(oldBuffer);

ByteBuffer newBuffer = ByteBuffer.allocate(newBitmap.getHeight() * newBitmap.getRowBytes());
newBitmap.copyPixelsToBuffer(newBuffer);
assertThat(oldBuffer.array()).isEqualTo(newBuffer.array());
}

private int getPngImageColorFromStream(String pngImagePath) throws IOException {
InputStream inputStream =
new BufferedInputStream(getClass().getClassLoader().getResourceAsStream(pngImagePath));
inputStream.mark(inputStream.available());
BitmapFactory.Options opts = new BitmapFactory.Options();
Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, opts);
return bitmap.getPixel(0, 0);
}

private int getPngImageColorFromByteArray(String pngImagePath) throws IOException {
InputStream inputStream =
new BufferedInputStream(getClass().getClassLoader().getResourceAsStream(pngImagePath));
inputStream.mark(inputStream.available());
byte[] array = new byte[inputStream.available()];
inputStream.read(array);
Bitmap bitmap = BitmapFactory.decodeByteArray(array, 0, array.length);
return bitmap.getPixel(0, 0);
}

private int getPngImageColorFromResourceStream(String pngImagePath) throws IOException {
Bitmap bitmap = getBitmapFromResourceStream(pngImagePath);
return bitmap.getPixel(0, 0);
}

private Bitmap getBitmapFromResourceStream(String imagePath) throws IOException {
InputStream inputStream =
new BufferedInputStream(getClass().getClassLoader().getResourceAsStream(imagePath));
inputStream.mark(inputStream.available());
BitmapFactory.Options opts = new BitmapFactory.Options();
Resources resources = context.getResources();
return BitmapFactory.decodeResourceStream(resources, null, inputStream, null, opts);
}

private byte[] getBitmapByteArrayFromResourceStream(String imagePath) throws IOException {
return toByteArray(com.google.common.io.Resources.getResource(imagePath));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import android.os.Parcel;
import android.util.DisplayMetrics;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.nio.LongBuffer;
Expand Down Expand Up @@ -471,6 +472,15 @@ public void shouldCopyPixelsToBufferAndReconstruct() {
assertThat(Arrays.equals(pixelsOriginal, pixelsReconstructed)).isTrue();
}

@Test
public void compress_shouldLessThanBeforeForWebp() {
Bitmap bitmap = Bitmap.createBitmap(400, 200, Bitmap.Config.ARGB_8888);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.WEBP, 75, stream);
byte[] compressedImageByteArray = stream.toByteArray();
assertThat(compressedImageByteArray.length).isLessThan(bitmap.getByteCount());
}

@Config(sdk = Build.VERSION_CODES.O)
@Test
public void getBytesPerPixel_O() {
Expand Down Expand Up @@ -637,7 +647,7 @@ public void sameAs_bitmapsSamePixels() {

@Test
public void extractAlpha() {
int[] pixels = new int[] {0xFF000000, 0x00000000, 0x88999999, 0x12345678};
int[] pixels = new int[] {0xFF123456, 0x00123456, 0x88999999, 0x12345678};
Bitmap bitmap = Bitmap.createBitmap(/* width= */ 2, /* height= */ 2, Bitmap.Config.ARGB_8888);
bitmap.setPixels(
pixels,
Expand All @@ -650,15 +660,15 @@ public void extractAlpha() {

Bitmap alpha = bitmap.extractAlpha();

assertThat(alpha.getPixel(0, 0)).isEqualTo(0xFF);
assertThat(alpha.getPixel(1, 0)).isEqualTo(0x00);
assertThat(alpha.getPixel(0, 1)).isEqualTo(0x88);
assertThat(alpha.getPixel(1, 1)).isEqualTo(0x12);
assertThat(alpha.getPixel(0, 0)).isEqualTo(0xFF000000);
assertThat(alpha.getPixel(1, 0)).isEqualTo(0x00000000);
assertThat(alpha.getPixel(0, 1)).isEqualTo(0x88000000);
assertThat(alpha.getPixel(1, 1)).isEqualTo(0x12000000);
}

@Test
public void extractAlpha_withArgs() {
int[] pixels = new int[] {0xFF000000, 0x00000000, 0x88999999, 0x12345678};
int[] pixels = new int[] {0xFF123456, 0x00123456, 0x88999999, 0x12345678};
Bitmap bitmap = Bitmap.createBitmap(/* width= */ 2, /* height= */ 2, Bitmap.Config.ARGB_8888);
bitmap.setPixels(
pixels,
Expand All @@ -671,10 +681,10 @@ public void extractAlpha_withArgs() {

Bitmap alpha = bitmap.extractAlpha(/* paint= */ null, /* offsetXY= */ new int[2]);

assertThat(alpha.getPixel(0, 0)).isEqualTo(0xFF);
assertThat(alpha.getPixel(1, 0)).isEqualTo(0x00);
assertThat(alpha.getPixel(0, 1)).isEqualTo(0x88);
assertThat(alpha.getPixel(1, 1)).isEqualTo(0x12);
assertThat(alpha.getPixel(0, 0)).isEqualTo(0xFF000000);
assertThat(alpha.getPixel(1, 0)).isEqualTo(0x00000000);
assertThat(alpha.getPixel(0, 1)).isEqualTo(0x88000000);
assertThat(alpha.getPixel(1, 1)).isEqualTo(0x12000000);
}

private static Bitmap create(String name) {
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading