/*
* Copyright 2015 Daniel Dittmar
*
* 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 dan.dit.whatsthat.image;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.util.LruCache;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import dan.dit.whatsthat.util.image.BitmapUtil;
import dan.dit.whatsthat.util.image.Dimension;
import dan.dit.whatsthat.util.mosaic.data.BitmapSource;
import dan.dit.whatsthat.util.mosaic.data.MosaicTile;
/**
* Provides a source for the mosaic library. This is a cache of bitmaps
* for images identified by their hash. Should be closed as soon as it is no longer needed since
* this can and will take up lots of memory.
* Created by daniel on 01.07.15.
*/
public class ImageBitmapSource implements BitmapSource<String> {
private final Map<String, Image> mImages;
private Resources mRes;
private LruCache<String, List<Bitmap>> mBitmapCache;
private Dimension mDimension = new Dimension(0, 0);
public ImageBitmapSource(Resources res, Map<String, Image> images) {
mRes = res;
mImages = images;
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
final int cacheSize = maxMemory / 10;
mBitmapCache = new LruCache<String, List<Bitmap>>(cacheSize) {
@Override
protected int sizeOf(String key, List<Bitmap> bitmaps) {
// The cache size will be measured in kilobytes rather than
// number of items.
int size = 0;
for (Bitmap bitmap : bitmaps) {
size += bitmap.getByteCount() / 1024;
}
return size;
}
};
}
@Override
public Bitmap getBitmap(MosaicTile<String> forTile, int requiredWidth, int requiredHeight) {
String hash = forTile.getSource();
List<Bitmap> cachedForImage = mBitmapCache.get(hash);
if (cachedForImage != null) {
Bitmap bigger = null;
for (Bitmap bitmap : cachedForImage) {
if (bitmap.getWidth() == requiredWidth &&
bitmap.getHeight() == requiredHeight) {
return bitmap; // found exact match, yeah!
} else if (bitmap.getWidth() >= requiredWidth && bitmap.getHeight() >= requiredHeight ) {
//Log.d("HomeStuff", "Found bigger bitmap: " + bitmap.getWidth() + "x" + bitmap.getHeight() + " instead of " + requiredWidth + "x" + requiredHeight);
bigger = bitmap;
}
}
if (bigger != null) {
Bitmap result = BitmapUtil.resize(bigger, requiredWidth, requiredHeight);
if (result != null) {
cachedForImage.add(result);
mBitmapCache.put(hash, cachedForImage);
return result;
}
}
}
// found no exact match, no bigger image or could not resize it, so load a new one
Image image = mImages.get(hash);
if (image != null) {
mDimension.set(requiredWidth, requiredHeight);
Bitmap result = image.loadBitmap(mRes, mDimension, true);
if (result != null) {
if (cachedForImage == null) {
cachedForImage = new LinkedList<>();
}
cachedForImage.add(result);
mBitmapCache.put(hash, cachedForImage);
return result;
}
}
return null;
}
}