private void internalCheckPixelAccess(int x, int y) { if (x < 0) { throw new IllegalArgumentException("x must be >= 0"); } if (y < 0) { throw new IllegalArgumentException("y must be >= 0"); } if (x >= getWidth()) { throw new IllegalArgumentException("x must be < bitmap.width()"); } if (y >= getHeight()) { throw new IllegalArgumentException("y must be < bitmap.height()"); } } }
/** * Note that this method will return a RuntimeException unless: - {@code pixels} has the same * length as the number of pixels of the bitmap. - {@code x = 0} - {@code y = 0} - {@code width} * and {@code height} height match the current bitmap's dimensions. */ @Implementation protected void getPixels( int[] pixels, int offset, int stride, int x, int y, int width, int height) { if (x != 0 || y != 0 || width != getWidth() || height != getHeight() || pixels.length != colors.length) { for (int y0 = 0; y0 < height; y0++) { for (int x0 = 0; x0 < width; x0++) { pixels[offset + y0 * stride + x0] = colors[(y0 + y) * getWidth() + x0 + x]; } } } else { System.arraycopy(colors, 0, pixels, 0, colors.length); } }
@Implementation protected void setPixel(int x, int y, int color) { if (isRecycled()) { throw new IllegalStateException("Can't call setPixel() on a recycled bitmap"); } else if (!isMutable()) { throw new IllegalStateException("Bitmap is immutable"); } internalCheckPixelAccess(x, y); if (colors == null) { colors = new int[getWidth() * getHeight()]; } colors[y * getWidth() + x] = color; }
@Implementation protected int getRowBytes() { return getBytesPerPixel(config) * getWidth(); }
@Implementation protected int getPixel(int x, int y) { internalCheckPixelAccess(x, y); if (colors != null) { // Note that getPixel() returns a non-premultiplied ARGB value; if // config is RGB_565, our return value will likely be more precise than // on a physical device, since it needs to map each color component from // 5 or 6 bits to 8 bits. return colors[y * getWidth() + x]; } else { return 0; } }
@Implementation protected Bitmap extractAlpha() { int[] alphaPixels = new int[colors.length]; for (int i = 0; i < alphaPixels.length; i++) { alphaPixels[i] = Color.alpha(colors[i]); } return createBitmap(alphaPixels, getWidth(), getHeight(), Bitmap.Config.ALPHA_8); }
@Implementation(minSdk = JELLY_BEAN_MR1) protected static Bitmap createBitmap( DisplayMetrics displayMetrics, int width, int height, Bitmap.Config config) { if (width <= 0 || height <= 0) { throw new IllegalArgumentException("width and height must be > 0"); } Bitmap scaledBitmap = ReflectionHelpers.callConstructor(Bitmap.class); ShadowBitmap shadowBitmap = Shadow.extract(scaledBitmap); shadowBitmap.setDescription("Bitmap (" + width + " x " + height + ")"); shadowBitmap.width = width; shadowBitmap.height = height; shadowBitmap.config = config; shadowBitmap.setMutable(true); if (displayMetrics != null) { shadowBitmap.density = displayMetrics.densityDpi; } shadowBitmap.setPixels(new int[shadowBitmap.getHeight() * shadowBitmap.getWidth()], 0, shadowBitmap.getWidth(), 0, 0, shadowBitmap.getWidth(), shadowBitmap.getHeight()); return scaledBitmap; }
@Implementation protected Bitmap copy(Bitmap.Config config, boolean isMutable) { Bitmap newBitmap = ReflectionHelpers.callConstructor(Bitmap.class); ShadowBitmap shadowBitmap = Shadow.extract(newBitmap); shadowBitmap.createdFromBitmap = realBitmap; shadowBitmap.config = config; shadowBitmap.mutable = isMutable; shadowBitmap.height = getHeight(); shadowBitmap.width = getWidth(); if (colors != null) { shadowBitmap.colors = new int[colors.length]; System.arraycopy(shadowBitmap.colors, 0, colors, 0, colors.length); } return newBitmap; }
@Implementation protected static Bitmap createScaledBitmap( Bitmap src, int dstWidth, int dstHeight, boolean filter) { if (dstWidth == src.getWidth() && dstHeight == src.getHeight() && !filter) { return src; // Return the original. } Bitmap scaledBitmap = ReflectionHelpers.callConstructor(Bitmap.class); ShadowBitmap shadowBitmap = Shadow.extract(scaledBitmap); ShadowBitmap shadowSrcBitmap = Shadow.extract(src); shadowBitmap.appendDescription(shadowSrcBitmap.getDescription()); shadowBitmap.appendDescription(" scaled to " + dstWidth + " x " + dstHeight); if (filter) { shadowBitmap.appendDescription(" with filter " + filter); } shadowBitmap.createdFromBitmap = src; shadowBitmap.createdFromFilter = filter; shadowBitmap.width = dstWidth; shadowBitmap.height = dstHeight; shadowBitmap.setPixels(new int[shadowBitmap.getHeight() * shadowBitmap.getWidth()], 0, 0, 0, 0, shadowBitmap.getWidth(), shadowBitmap.getHeight()); return scaledBitmap; }
@Test public void shouldCreateBitmapWithMatrix() { Bitmap originalBitmap = create("Original bitmap"); shadowOf(originalBitmap).setWidth(200); shadowOf(originalBitmap).setHeight(200); Matrix m = new Matrix(); m.postRotate(90); Bitmap newBitmap = Bitmap.createBitmap(originalBitmap, 0, 0, 100, 50, m, true); ShadowBitmap shadowBitmap = shadowOf(newBitmap); assertThat(shadowBitmap.getDescription()) .isEqualTo("Original bitmap at (0,0) with width 100 and height 50" + " using matrix Matrix[pre=[], set={}, post=[rotate 90.0]] with filter"); assertThat(shadowBitmap.getCreatedFromBitmap()).isEqualTo(originalBitmap); assertThat(shadowBitmap.getCreatedFromX()).isEqualTo(0); assertThat(shadowBitmap.getCreatedFromY()).isEqualTo(0); assertThat(shadowBitmap.getCreatedFromWidth()).isEqualTo(100); assertThat(shadowBitmap.getCreatedFromHeight()).isEqualTo(50); assertThat(shadowBitmap.getCreatedFromMatrix()).isEqualTo(m); assertThat(shadowBitmap.getCreatedFromFilter()).isEqualTo(true); assertThat(shadowBitmap.getWidth()).isEqualTo(50); assertThat(shadowBitmap.getHeight()).isEqualTo(100); }
@Implementation public void setPixel(int x, int y, int color) { if (isRecycled()) { throw new IllegalStateException("Can't call setPixel() on a recycled bitmap"); } else if (!isMutable()) { throw new IllegalStateException("Bitmap is immutable"); } internalCheckPixelAccess(x, y); if (colors == null) { colors = new int[getWidth() * getHeight()]; } colors[y * getWidth() + x] = color; }
@Implementation protected int getPixel(int x, int y) { internalCheckPixelAccess(x, y); if (colors != null) { // Note that getPixel() returns a non-premultiplied ARGB value; if // config is RGB_565, our return value will likely be more precise than // on a physical device, since it needs to map each color component from // 5 or 6 bits to 8 bits. return colors[y * getWidth() + x]; } else { return 0; } }
@Implementation protected void setPixel(int x, int y, int color) { if (isRecycled()) { throw new IllegalStateException("Can't call setPixel() on a recycled bitmap"); } else if (!isMutable()) { throw new IllegalStateException("Bitmap is immutable"); } internalCheckPixelAccess(x, y); if (colors == null) { colors = new int[getWidth() * getHeight()]; } colors[y * getWidth() + x] = color; }
@Implementation public int getRowBytes() { return getBytesPerPixel(config) * getWidth(); }
@Implementation protected int getRowBytes() { return getBytesPerPixel(config) * getWidth(); }
@Implementation public int getRowBytes() { return getBytesPerPixel(config) * getWidth(); }
@Implementation public int getRowBytes() { return getBytesPerPixel(config) * getWidth(); }
@Implementation public int getPixel(int x, int y) { internalCheckPixelAccess(x, y); if (colors != null) { // Note that getPixel() returns a non-premultiplied ARGB value; if // config is RGB_565, our return value will likely be more precise than // on a physical device, since it needs to map each color component from // 5 or 6 bits to 8 bits. return colors[y * getWidth() + x]; } else { return 0; } }
@Implementation public void setPixel(int x, int y, int color) { if (isRecycled()) { throw new IllegalStateException("Can't call setPixel() on a recycled bitmap"); } else if (!isMutable()) { throw new IllegalStateException("Bitmap is immutable"); } internalCheckPixelAccess(x, y); if (colors == null) { colors = new int[getWidth() * getHeight()]; } colors[y * getWidth() + x] = color; }
@Implementation protected Bitmap extractAlpha() { int[] alphaPixels = new int[colors.length]; for (int i = 0; i < alphaPixels.length; i++) { alphaPixels[i] = Color.alpha(colors[i]); } return createBitmap(alphaPixels, getWidth(), getHeight(), Bitmap.Config.ALPHA_8); }