/* * Copyright 2016 Hippo Seven * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.hippo.drawable; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.drawable.Animatable; import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; import com.hippo.yorozuya.MathUtils; import java.util.ArrayList; import java.util.List; public class ImageDrawable extends Drawable implements ImageWrapper.Callback, Animatable { private static final int TILE_SIZE = 512; private ImageWrapper mImageWrapper; private Paint mPaint; private List<Tile> mTileList; private static class Tile { Bitmap bitmap; int w; int h; int x; int y; } private static final BitmapPool sBitmapPool = new BitmapPool(); public ImageDrawable(@NonNull ImageWrapper imageWrapper) { mImageWrapper = imageWrapper; mPaint = new Paint(Paint.FILTER_BITMAP_FLAG); mTileList = createTileArray(); // Render first frame render(); // Add callback imageWrapper.addCallback(this); } private List<Tile> createTileArray() { int width = mImageWrapper.getWidth(); int height = mImageWrapper.getHeight(); int capacity = MathUtils.clamp(MathUtils.ceilDivide(width, TILE_SIZE) * MathUtils.ceilDivide(height, TILE_SIZE), 0, 100); List<Tile> tiles = new ArrayList<>(capacity); for (int x = 0; x < width; x += TILE_SIZE) { int w = Math.min(TILE_SIZE, width - x); for (int y = 0; y < height; y += TILE_SIZE) { int h = Math.min(TILE_SIZE, height - y); Tile tile = new Tile(); tile.x = x; tile.y = y; tile.w = w; tile.h = h; tile.bitmap = sBitmapPool.get(w, h); tiles.add(tile); } } return tiles; } private void render() { ImageWrapper imageWrapper = mImageWrapper; if (imageWrapper.isRecycled()) { return; } List<Tile> tiles = mTileList; for (int i = 0, length = tiles.size(); i < length; i++) { Tile tile = tiles.get(i); if (tile.bitmap != null) { imageWrapper.render(tile.x, tile.y, tile.bitmap, 0, 0, tile.w, tile.h, false, 0); } } } @Override public int getIntrinsicWidth() { return mImageWrapper.getWidth(); } @Override public int getIntrinsicHeight() { return mImageWrapper.getHeight(); } @Override public void draw(Canvas canvas) { List<Tile> tiles = mTileList; for (int i = 0, length = tiles.size(); i < length; i++) { Tile tile = tiles.get(i); if (tile.bitmap != null) { canvas.drawBitmap(tile.bitmap, tile.x, tile.y, mPaint); } } } @Override public void setAlpha(int alpha) { mPaint.setAlpha(alpha); } @Override public void setColorFilter(ColorFilter colorFilter) { mPaint.setColorFilter(colorFilter); } @Override public int getOpacity() { return PixelFormat.TRANSLUCENT; } public void recycle() { mImageWrapper.removeCallback(this); // Free tile's bitmap List<Tile> tiles = mTileList; for (int i = 0, length = tiles.size(); i < length; i++) { Tile tile = tiles.get(i); sBitmapPool.put(tile.bitmap); tile.bitmap = null; } } @Override public void renderImage(ImageWrapper who) { render(); } @Override public void invalidateImage(ImageWrapper who) { invalidateSelf(); } @Override public void start() { mImageWrapper.start(); } @Override public void stop() { mImageWrapper.stop(); } @Override public boolean isRunning() { return mImageWrapper.isRunning(); } }