Search in sources :

Example 1 with BitmapInfo

use of com.koushikdutta.ion.bitmap.BitmapInfo in project ion by koush.

the class ImageViewFutureImpl method transform.

@Override
protected void transform(IonDrawable result) throws Exception {
    // need to make sure that the IonDrawable calling this future
    // is still needed. It may have changed if the user manually
    // called setDrawable on the ImageView, etc.
    final ImageView imageView = imageViewRef.get();
    // check the imageview and the activity context
    if (null != imageViewRef.isAlive() || imageView == null) {
        cancelSilently();
        return;
    }
    if (imageView.getDrawable() != result) {
        // imageview is now waiting for something else now... cancel
        cancelSilently();
        return;
    }
    // retrigger the intrinsic dimension check on the drawable
    BitmapInfo info = result.getBitmapInfo();
    if (info != null && info.exception == null) {
        applyScaleMode(imageView, scaleMode);
    }
    IonBitmapRequestBuilder.doAnimation(imageView, inAnimation, inAnimationResource);
    imageView.setImageDrawable(null);
    imageView.setImageDrawable(result);
    setComplete(imageView);
}
Also used : ImageView(android.widget.ImageView) BitmapInfo(com.koushikdutta.ion.bitmap.BitmapInfo)

Example 2 with BitmapInfo

use of com.koushikdutta.ion.bitmap.BitmapInfo in project ion by koush.

the class IonDrawable method draw.

@Override
public void draw(Canvas canvas) {
    if (info == null) {
        // draw stuff
        super.draw(canvas);
        // see if we can fetch a bitmap
        if (bitmapFetcher != null) {
            if (bitmapFetcher.sampleWidth == 0 && bitmapFetcher.sampleHeight == 0) {
                if (canvas.getWidth() != 1)
                    bitmapFetcher.sampleWidth = canvas.getWidth();
                if (canvas.getHeight() != 1)
                    bitmapFetcher.sampleHeight = canvas.getHeight();
                // now that we have final dimensions, reattempt to find the image in the cache
                bitmapFetcher.recomputeDecodeKey();
                BitmapInfo found = ion.bitmapCache.get(bitmapFetcher.bitmapKey);
                if (found != null) {
                    // won't be needing THIS anymore
                    bitmapFetcher = null;
                    // found what we're looking for, but can't draw at this very moment,
                    // since we need to trigger a new measure.
                    callback.onCompleted(null, found);
                    return;
                }
            }
            // no image found fetch it.
            callback.register(ion, bitmapFetcher.bitmapKey);
            // already in progress
            if (BitmapFetcher.shouldDeferImageView(ion)) {
                bitmapFetcher.defer();
            } else {
                bitmapFetcher.execute();
            }
            // won't be needing THIS anymore
            bitmapFetcher = null;
        }
        // well, can't do anything else here.
        return;
    }
    if (info.decoder != null) {
        drawDeepZoom(canvas);
        return;
    }
    if (info.drawTime == 0)
        info.drawTime = SystemClock.uptimeMillis();
    long destAlpha = this.alpha;
    if (fadeIn) {
        destAlpha = ((SystemClock.uptimeMillis() - info.drawTime) << 8) / FADE_DURATION;
        destAlpha = Math.min(destAlpha, this.alpha);
    }
    // remove plaeholder if not visible
    if (destAlpha == this.alpha) {
        if (placeholder != null) {
            placeholder = null;
            setDrawableByLayerId(0, NULL_PLACEHOLDER);
        }
    } else {
        // invalidate to fade in
        if (placeholder != null)
            invalidateSelf();
    }
    if (info.gifDecoder != null) {
        super.draw(canvas);
        GifFrame frame = gifDecoder.getCurrentFrame();
        if (frame != null) {
            paint.setAlpha((int) destAlpha);
            canvas.drawBitmap(frame.image, null, getBounds(), paint);
            paint.setAlpha(this.alpha);
            invalidateSelf();
        }
        return;
    }
    if (info.bitmap != null) {
        if (bitmapDrawable != null)
            bitmapDrawable.setAlpha((int) destAlpha);
    } else {
        if (error != null)
            error.setAlpha((int) destAlpha);
    }
    super.draw(canvas);
    if (true)
        return;
    // stolen from picasso
    canvas.save();
    canvas.rotate(45);
    paint.setColor(Color.WHITE);
    canvas.drawRect(0, -10, 7.5f, 10, paint);
    int sourceColor;
    if (servedFrom == ResponseServedFrom.LOADED_FROM_CACHE)
        sourceColor = Color.CYAN;
    else if (servedFrom == ResponseServedFrom.LOADED_FROM_CONDITIONAL_CACHE)
        sourceColor = Color.YELLOW;
    else if (servedFrom == ResponseServedFrom.LOADED_FROM_MEMORY)
        sourceColor = Color.GREEN;
    else
        sourceColor = Color.RED;
    paint.setColor(sourceColor);
    canvas.drawRect(0, -9, 6.5f, 9, paint);
    canvas.restore();
}
Also used : GifFrame(com.koushikdutta.ion.gif.GifFrame) BitmapInfo(com.koushikdutta.ion.bitmap.BitmapInfo) Paint(android.graphics.Paint)

Example 3 with BitmapInfo

use of com.koushikdutta.ion.bitmap.BitmapInfo in project ion by koush.

the class IonDrawable method drawDeepZoom.

private void drawDeepZoom(Canvas canvas) {
    // zoom 0: entire image fits in a TILE_DIMxTILE_DIM square
    // draw base bitmap for empty tiles
    // figure out zoom level
    // figure out which tiles need rendering
    // draw stuff that needs drawing
    // missing tile? fetch it
    // use parent level tiles for tiles that do not exist
    // TODO: crossfading?
    Rect clip = canvas.getClipBounds();
    Rect bounds = getBounds();
    float zoom = (float) canvas.getWidth() / (float) clip.width();
    float zoomWidth = zoom * bounds.width();
    float zoomHeight = zoom * bounds.height();
    double wlevel = Math.log(zoomWidth / TILE_DIM) / LOG_2;
    double hlevel = Math.log(zoomHeight / TILE_DIM) / LOG_2;
    double maxLevel = Math.max(wlevel, hlevel);
    int visibleLeft = Math.max(0, clip.left);
    int visibleRight = Math.min(bounds.width(), clip.right);
    int visibleTop = Math.max(0, clip.top);
    int visibleBottom = Math.min(bounds.height(), clip.bottom);
    int level = (int) Math.floor(maxLevel);
    level = Math.min(this.maxLevel, level);
    level = Math.max(level, 0);
    int levelTiles = 1 << level;
    int textureTileDim = textureDim / levelTiles;
    // System.out.println("textureTileDim: " + textureTileDim);
    // System.out.println(info.key + " visible: " + new Rect(visibleLeft, visibleTop, visibleRight, visibleBottom));
    final boolean DEBUG_ZOOM = false;
    if (info.bitmap != null) {
        canvas.drawBitmap(info.bitmap, null, getBounds(), paint);
        if (DEBUG_ZOOM) {
            paint.setColor(Color.RED);
            paint.setAlpha(0x80);
            canvas.drawRect(getBounds(), paint);
            paint.setAlpha(0xFF);
        }
    } else {
        paint.setColor(Color.BLACK);
        canvas.drawRect(getBounds(), paint);
    }
    int sampleSize = 1;
    while (textureTileDim / sampleSize > TILE_DIM) sampleSize <<= 1;
    for (int y = 0; y < levelTiles; y++) {
        int top = textureTileDim * y;
        int bottom = textureTileDim * (y + 1);
        bottom = Math.min(bottom, bounds.bottom);
        // TODO: start at visible pos
        if (bottom < visibleTop)
            continue;
        if (top > visibleBottom)
            break;
        for (int x = 0; x < levelTiles; x++) {
            int left = textureTileDim * x;
            int right = textureTileDim * (x + 1);
            right = Math.min(right, bounds.right);
            // TODO: start at visible pos
            if (right < visibleLeft)
                continue;
            if (left > visibleRight)
                break;
            Rect texRect = new Rect(left, top, right, bottom);
            // find, render/fetch
            // System.out.println("rendering: " + texRect + " for: " + bounds);
            String tileKey = FileCache.toKeyString(info.key, ",", level, ",", x, ",", y);
            BitmapInfo tile = ion.bitmapCache.get(tileKey);
            if (tile != null && tile.bitmap != null) {
                // render it
                // System.out.println("bitmap is: " + tile.bitmaps[0].getWidth() + "x" + tile.bitmaps[0].getHeight());
                canvas.drawBitmap(tile.bitmap, null, texRect, paint);
                continue;
            }
            // TODO: cancellation of unnecessary regions when fast pan/zooming
            if (ion.bitmapsPending.tag(tileKey) == null) {
                // fetch it
                // System.out.println(info.key + ": fetching region: " + texRect + " sample size: " + sampleSize);
                LoadBitmapRegion region = new LoadBitmapRegion(ion, tileKey, info.decoder, texRect, sampleSize);
            }
            ion.bitmapsPending.add(tileKey, tileCallback);
            int parentLeft = 0;
            int parentTop = 0;
            int parentUp = 1;
            int parentLevel = level - parentUp;
            if (x % 2 == 1)
                parentLeft++;
            if (y % 2 == 1)
                parentTop++;
            int parentX = x >> 1;
            int parentY = y >> 1;
            while (parentLevel >= 0) {
                tileKey = FileCache.toKeyString(info.key, ",", parentLevel, ",", parentX, ",", parentY);
                tile = ion.bitmapCache.get(tileKey);
                if (tile != null && tile.bitmap != null)
                    break;
                if (parentX % 2 == 1) {
                    parentLeft += 1 << parentUp;
                }
                if (parentY % 2 == 1) {
                    parentTop += 1 << parentUp;
                }
                parentLevel--;
                parentUp++;
                parentX >>= 1;
                parentY >>= 1;
            }
            // well, i give up
            if (tile == null || tile.bitmap == null)
                continue;
            int subLevelTiles = 1 << parentLevel;
            int subtileDim = textureDim / subLevelTiles;
            int subSampleSize = 1;
            while (subtileDim / subSampleSize > TILE_DIM) subSampleSize <<= 1;
            int subTextureDim = subtileDim / subSampleSize;
            // System.out.println(String.format("falling back for %s,%s,%s to %s,%s,%s: %s,%s (%s to %s)", x, y, level, parentX, parentY, parentLevel, parentLeft, parentTop, subTextureDim, subTextureDim >> parentUp));
            subTextureDim >>= parentUp;
            int sourceLeft = subTextureDim * parentLeft;
            int sourceTop = subTextureDim * parentTop;
            Rect sourceRect = new Rect(sourceLeft, sourceTop, sourceLeft + subTextureDim, sourceTop + subTextureDim);
            canvas.drawBitmap(tile.bitmap, sourceRect, texRect, paint);
            if (DEBUG_ZOOM) {
                paint.setColor(Color.RED);
                paint.setAlpha(0x80);
                canvas.drawRect(texRect, paint);
                paint.setAlpha(0xFF);
            }
        }
    }
}
Also used : Rect(android.graphics.Rect) Paint(android.graphics.Paint) BitmapInfo(com.koushikdutta.ion.bitmap.BitmapInfo)

Example 4 with BitmapInfo

use of com.koushikdutta.ion.bitmap.BitmapInfo in project ion by koush.

the class FileLoader method loadBitmap.

@Override
public Future<BitmapInfo> loadBitmap(final Context context, final Ion ion, final String key, final String uri, final int resizeWidth, final int resizeHeight, final boolean animateGif) {
    if (uri == null || !uri.startsWith("file:/"))
        return null;
    final SimpleFuture<BitmapInfo> ret = new SimpleFuture<BitmapInfo>();
    // Log.d("FileLoader", "Loading file bitmap " + uri + " " + resizeWidth + "," + resizeHeight);
    Ion.getBitmapLoadExecutorService().execute(new Runnable() {

        @Override
        public void run() {
            if (ret.isCancelled()) {
                // Log.d("FileLoader", "Bitmap load cancelled (no longer needed)");
                return;
            }
            try {
                File file = new File(URI.create(uri));
                BitmapFactory.Options options = ion.getBitmapCache().prepareBitmapOptions(file, resizeWidth, resizeHeight);
                Point size = new Point(options.outWidth, options.outHeight);
                BitmapInfo info;
                if (animateGif && TextUtils.equals("image/gif", options.outMimeType)) {
                    FileInputStream fin = new FileInputStream(file);
                    try {
                        info = loadGif(key, size, fin, options);
                    } finally {
                        StreamUtility.closeQuietly(fin);
                    }
                } else {
                    Bitmap bitmap = IonBitmapCache.loadBitmap(file, options);
                    if (bitmap == null)
                        throw new Exception("Bitmap failed to load");
                    info = new BitmapInfo(key, options.outMimeType, bitmap, size);
                }
                info.servedFrom = ResponseServedFrom.LOADED_FROM_CACHE;
                ret.setComplete(info);
            } catch (OutOfMemoryError e) {
                ret.setComplete(new Exception(e), null);
            } catch (Exception e) {
                ret.setComplete(e);
            }
        }
    });
    return ret;
}
Also used : Bitmap(android.graphics.Bitmap) Point(android.graphics.Point) File(java.io.File) BitmapInfo(com.koushikdutta.ion.bitmap.BitmapInfo) FileInputStream(java.io.FileInputStream) SimpleFuture(com.koushikdutta.async.future.SimpleFuture)

Example 5 with BitmapInfo

use of com.koushikdutta.ion.bitmap.BitmapInfo in project ion by koush.

the class ResourceLoader method loadBitmap.

@Override
public Future<BitmapInfo> loadBitmap(final Context context, final Ion ion, final String key, final String uri, final int resizeWidth, final int resizeHeight, final boolean animateGif) {
    if (uri == null || !uri.startsWith("android.resource:/"))
        return null;
    final SimpleFuture<BitmapInfo> ret = new SimpleFuture<BitmapInfo>();
    // Log.d("FileLoader", "Loading file bitmap " + uri + " " + resizeWidth + "," + resizeHeight);
    Ion.getBitmapLoadExecutorService().execute(new Runnable() {

        @Override
        public void run() {
            try {
                Resource res = lookupResource(context, uri);
                BitmapFactory.Options options = ion.getBitmapCache().prepareBitmapOptions(res.res, res.id, resizeWidth, resizeHeight);
                Point size = new Point(options.outWidth, options.outHeight);
                BitmapInfo info;
                if (animateGif && TextUtils.equals("image/gif", options.outMimeType)) {
                    InputStream in = res.res.openRawResource(res.id);
                    try {
                        info = loadGif(key, size, in, options);
                    } finally {
                        StreamUtility.closeQuietly(in);
                    }
                } else {
                    Bitmap bitmap = IonBitmapCache.loadBitmap(res.res, res.id, options);
                    if (bitmap == null)
                        throw new Exception("Bitmap failed to load");
                    info = new BitmapInfo(key, options.outMimeType, bitmap, size);
                }
                info.servedFrom = ResponseServedFrom.LOADED_FROM_CACHE;
                ret.setComplete(info);
            } catch (OutOfMemoryError e) {
                ret.setComplete(new Exception(e), null);
            } catch (Exception e) {
                ret.setComplete(e);
            }
        }
    });
    return ret;
}
Also used : Bitmap(android.graphics.Bitmap) InputStream(java.io.InputStream) Point(android.graphics.Point) BitmapInfo(com.koushikdutta.ion.bitmap.BitmapInfo) SimpleFuture(com.koushikdutta.async.future.SimpleFuture)

Aggregations

BitmapInfo (com.koushikdutta.ion.bitmap.BitmapInfo)19 Bitmap (android.graphics.Bitmap)8 Point (android.graphics.Point)8 SimpleFuture (com.koushikdutta.async.future.SimpleFuture)5 File (java.io.File)5 GifFrame (com.koushikdutta.ion.gif.GifFrame)4 ImageView (android.widget.ImageView)3 GifDecoder (com.koushikdutta.ion.gif.GifDecoder)3 Paint (android.graphics.Paint)2 Rect (android.graphics.Rect)2 FileInputStream (java.io.FileInputStream)2 InputStream (java.io.InputStream)2 CancellationException (java.util.concurrent.CancellationException)2 Intent (android.content.Intent)1 PackageManager (android.content.pm.PackageManager)1 BitmapRegionDecoder (android.graphics.BitmapRegionDecoder)1 Transition (android.transition.Transition)1 View (android.view.View)1 ByteBufferList (com.koushikdutta.async.ByteBufferList)1 FutureCallback (com.koushikdutta.async.future.FutureCallback)1