use of android.graphics.BitmapRegionDecoder in project android_frameworks_base by crdroidandroid.
the class WallpaperManagerService method generateCrop.
/**
* Once a new wallpaper has been written via setWallpaper(...), it needs to be cropped
* for display.
*/
private void generateCrop(WallpaperData wallpaper) {
boolean success = false;
Rect cropHint = new Rect(wallpaper.cropHint);
if (DEBUG) {
Slog.v(TAG, "Generating crop for new wallpaper(s): 0x" + Integer.toHexString(wallpaper.whichPending) + " to " + wallpaper.cropFile.getName() + " crop=(" + cropHint.width() + 'x' + cropHint.height() + ") dim=(" + wallpaper.width + 'x' + wallpaper.height + ')');
}
// Analyse the source; needed in multiple cases
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(wallpaper.wallpaperFile.getAbsolutePath(), options);
if (options.outWidth <= 0 || options.outHeight <= 0) {
Slog.e(TAG, "Invalid wallpaper data");
success = false;
} else {
boolean needCrop = false;
boolean needScale = false;
// Empty crop means use the full image
if (cropHint.isEmpty()) {
cropHint.left = cropHint.top = 0;
cropHint.right = options.outWidth;
cropHint.bottom = options.outHeight;
} else {
// force the crop rect to lie within the measured bounds
cropHint.offset((cropHint.right > options.outWidth ? options.outWidth - cropHint.right : 0), (cropHint.bottom > options.outHeight ? options.outHeight - cropHint.bottom : 0));
// If the crop hint was larger than the image we just overshot. Patch things up.
if (cropHint.left < 0) {
cropHint.left = 0;
}
if (cropHint.top < 0) {
cropHint.top = 0;
}
// Don't bother cropping if what we're left with is identity
needCrop = (options.outHeight > cropHint.height() || options.outWidth > cropHint.width());
}
// scale if the crop height winds up not matching the recommended metrics
needScale = (wallpaper.height != cropHint.height());
if (DEBUG) {
Slog.v(TAG, "crop: w=" + cropHint.width() + " h=" + cropHint.height());
Slog.v(TAG, "dims: w=" + wallpaper.width + " h=" + wallpaper.height);
Slog.v(TAG, "meas: w=" + options.outWidth + " h=" + options.outHeight);
Slog.v(TAG, "crop?=" + needCrop + " scale?=" + needScale);
}
if (!needCrop && !needScale) {
// the whole thing and just copy the image file directly.
if (DEBUG) {
Slog.v(TAG, "Null crop of new wallpaper; copying");
}
success = FileUtils.copyFile(wallpaper.wallpaperFile, wallpaper.cropFile);
if (!success) {
wallpaper.cropFile.delete();
// TODO: fall back to default wallpaper in this case
}
} else {
// Fancy case: crop and scale. First, we decode and scale down if appropriate.
FileOutputStream f = null;
BufferedOutputStream bos = null;
try {
BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(wallpaper.wallpaperFile.getAbsolutePath(), false);
// This actually downsamples only by powers of two, but that's okay; we do
// a proper scaling blit later. This is to minimize transient RAM use.
// We calculate the largest power-of-two under the actual ratio rather than
// just let the decode take care of it because we also want to remap where the
// cropHint rectangle lies in the decoded [super]rect.
final BitmapFactory.Options scaler;
final int actualScale = cropHint.height() / wallpaper.height;
int scale = 1;
while (2 * scale < actualScale) {
scale *= 2;
}
if (scale > 1) {
scaler = new BitmapFactory.Options();
scaler.inSampleSize = scale;
if (DEBUG) {
Slog.v(TAG, "Downsampling cropped rect with scale " + scale);
}
} else {
scaler = null;
}
Bitmap cropped = decoder.decodeRegion(cropHint, scaler);
decoder.recycle();
if (cropped == null) {
Slog.e(TAG, "Could not decode new wallpaper");
} else {
// We've got the extracted crop; now we want to scale it properly to
// the desired rectangle. That's a height-biased operation: make it
// fit the hinted height, and accept whatever width we end up with.
cropHint.offsetTo(0, 0);
// adjust by downsampling factor
cropHint.right /= scale;
cropHint.bottom /= scale;
final float heightR = ((float) wallpaper.height) / ((float) cropHint.height());
if (DEBUG) {
Slog.v(TAG, "scale " + heightR + ", extracting " + cropHint);
}
final int destWidth = (int) (cropHint.width() * heightR);
final Bitmap finalCrop = Bitmap.createScaledBitmap(cropped, destWidth, wallpaper.height, true);
if (DEBUG) {
Slog.v(TAG, "Final extract:");
Slog.v(TAG, " dims: w=" + wallpaper.width + " h=" + wallpaper.height);
Slog.v(TAG, " out: w=" + finalCrop.getWidth() + " h=" + finalCrop.getHeight());
}
f = new FileOutputStream(wallpaper.cropFile);
bos = new BufferedOutputStream(f, 32 * 1024);
finalCrop.compress(Bitmap.CompressFormat.JPEG, 100, bos);
// don't rely on the implicit flush-at-close when noting success
bos.flush();
success = true;
}
} catch (Exception e) {
if (DEBUG) {
Slog.e(TAG, "Error decoding crop", e);
}
} finally {
IoUtils.closeQuietly(bos);
IoUtils.closeQuietly(f);
}
}
}
if (!success) {
Slog.e(TAG, "Unable to apply new wallpaper");
wallpaper.cropFile.delete();
}
if (wallpaper.cropFile.exists()) {
boolean didRestorecon = SELinux.restorecon(wallpaper.cropFile.getAbsoluteFile());
if (DEBUG) {
Slog.v(TAG, "restorecon() of crop file returned " + didRestorecon);
}
}
}
use of android.graphics.BitmapRegionDecoder in project android_frameworks_base by crdroidandroid.
the class WallpaperManager method getBuiltInDrawable.
/**
* Returns a drawable for the built-in static wallpaper of the specified type. Based on the
* parameters, the drawable can be cropped and scaled.
*
* @param outWidth The width of the returned drawable
* @param outWidth The height of the returned drawable
* @param scaleToFit If true, scale the wallpaper down rather than just cropping it
* @param horizontalAlignment A float value between 0 and 1 specifying where to crop the image;
* 0 for left-aligned, 0.5 for horizontal center-aligned, and 1 for right-aligned
* @param verticalAlignment A float value between 0 and 1 specifying where to crop the image;
* 0 for top-aligned, 0.5 for vertical center-aligned, and 1 for bottom-aligned
* @param which The {@code FLAG_*} identifier of a valid wallpaper type. Throws
* IllegalArgumentException if an invalid wallpaper is requested.
* @return A Drawable presenting the built-in default wallpaper image of the given type,
* or {@code null} if no default image of that type is defined on this device.
*/
public Drawable getBuiltInDrawable(int outWidth, int outHeight, boolean scaleToFit, float horizontalAlignment, float verticalAlignment, @SetWallpaperFlags int which) {
if (sGlobals.mService == null) {
Log.w(TAG, "WallpaperService not running");
throw new RuntimeException(new DeadSystemException());
}
if (which != FLAG_SYSTEM && which != FLAG_LOCK) {
throw new IllegalArgumentException("Must request exactly one kind of wallpaper");
}
Resources resources = mContext.getResources();
horizontalAlignment = Math.max(0, Math.min(1, horizontalAlignment));
verticalAlignment = Math.max(0, Math.min(1, verticalAlignment));
InputStream wpStream = openDefaultWallpaper(mContext, which);
if (wpStream == null) {
if (DEBUG) {
Log.w(TAG, "default wallpaper stream " + which + " is null");
}
return null;
} else {
InputStream is = new BufferedInputStream(wpStream);
if (outWidth <= 0 || outHeight <= 0) {
Bitmap fullSize = BitmapFactory.decodeStream(is, null, null);
return new BitmapDrawable(resources, fullSize);
} else {
int inWidth;
int inHeight;
// Just measure this time through...
{
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(is, null, options);
if (options.outWidth != 0 && options.outHeight != 0) {
inWidth = options.outWidth;
inHeight = options.outHeight;
} else {
Log.e(TAG, "default wallpaper dimensions are 0");
return null;
}
}
// Reopen the stream to do the full decode. We know at this point
// that openDefaultWallpaper() will return non-null.
is = new BufferedInputStream(openDefaultWallpaper(mContext, which));
RectF cropRectF;
outWidth = Math.min(inWidth, outWidth);
outHeight = Math.min(inHeight, outHeight);
if (scaleToFit) {
cropRectF = getMaxCropRect(inWidth, inHeight, outWidth, outHeight, horizontalAlignment, verticalAlignment);
} else {
float left = (inWidth - outWidth) * horizontalAlignment;
float right = left + outWidth;
float top = (inHeight - outHeight) * verticalAlignment;
float bottom = top + outHeight;
cropRectF = new RectF(left, top, right, bottom);
}
Rect roundedTrueCrop = new Rect();
cropRectF.roundOut(roundedTrueCrop);
if (roundedTrueCrop.width() <= 0 || roundedTrueCrop.height() <= 0) {
Log.w(TAG, "crop has bad values for full size image");
return null;
}
// See how much we're reducing the size of the image
int scaleDownSampleSize = Math.min(roundedTrueCrop.width() / outWidth, roundedTrueCrop.height() / outHeight);
// Attempt to open a region decoder
BitmapRegionDecoder decoder = null;
try {
decoder = BitmapRegionDecoder.newInstance(is, true);
} catch (IOException e) {
Log.w(TAG, "cannot open region decoder for default wallpaper");
}
Bitmap crop = null;
if (decoder != null) {
// Do region decoding to get crop bitmap
BitmapFactory.Options options = new BitmapFactory.Options();
if (scaleDownSampleSize > 1) {
options.inSampleSize = scaleDownSampleSize;
}
crop = decoder.decodeRegion(roundedTrueCrop, options);
decoder.recycle();
}
if (crop == null) {
// BitmapRegionDecoder has failed, try to crop in-memory. We know at
// this point that openDefaultWallpaper() will return non-null.
is = new BufferedInputStream(openDefaultWallpaper(mContext, which));
Bitmap fullSize = null;
BitmapFactory.Options options = new BitmapFactory.Options();
if (scaleDownSampleSize > 1) {
options.inSampleSize = scaleDownSampleSize;
}
fullSize = BitmapFactory.decodeStream(is, null, options);
if (fullSize != null) {
crop = Bitmap.createBitmap(fullSize, roundedTrueCrop.left, roundedTrueCrop.top, roundedTrueCrop.width(), roundedTrueCrop.height());
}
}
if (crop == null) {
Log.w(TAG, "cannot decode default wallpaper");
return null;
}
// Scale down if necessary
if (outWidth > 0 && outHeight > 0 && (crop.getWidth() != outWidth || crop.getHeight() != outHeight)) {
Matrix m = new Matrix();
RectF cropRect = new RectF(0, 0, crop.getWidth(), crop.getHeight());
RectF returnRect = new RectF(0, 0, outWidth, outHeight);
m.setRectToRect(cropRect, returnRect, Matrix.ScaleToFit.FILL);
Bitmap tmp = Bitmap.createBitmap((int) returnRect.width(), (int) returnRect.height(), Bitmap.Config.ARGB_8888);
if (tmp != null) {
Canvas c = new Canvas(tmp);
Paint p = new Paint();
p.setFilterBitmap(true);
c.drawBitmap(crop, m, p);
crop = tmp;
}
}
return new BitmapDrawable(resources, crop);
}
}
}
Aggregations