我看到好多博客都是这样计算的,可是这样算对吗?有没有哥们试验过这种方法正确性?我以为看博客要对博主表示怀疑,论证别人写的是否正确。更多详细能够看个人GitHub:https://github.com/yangchong211php
加载一张本地资源图片,那么它占用的内存 = width height nTargetDensity/inDensity nTargetDensity/inDensity 一个像素所占的内存。android
@Nullable public static Bitmap decodeResourceStream(@Nullable Resources res, @Nullable TypedValue value, @Nullable InputStream is, @Nullable Rect pad, @Nullable Options opts) { validate(opts); if (opts == null) { opts = new Options(); } if (opts.inDensity == 0 && value != null) { final int density = value.density; if (density == TypedValue.DENSITY_DEFAULT) { opts.inDensity = DisplayMetrics.DENSITY_DEFAULT; } else if (density != TypedValue.DENSITY_NONE) { opts.inDensity = density; } } if (opts.inTargetDensity == 0 && res != null) { opts.inTargetDensity = res.getDisplayMetrics().densityDpi; } return decodeStream(is, pad, opts); }
质量压缩方法:在保持像素的前提下改变图片的位深及透明度等,来达到压缩图片的目的,这样适合去传递二进制的图片数据,好比分享图片,要传入二进制数据过去,限制500kb以内。git
/** * 第一种:质量压缩法 * @param image 目标原图 * @param maxSize 最大的图片大小 * @return bitmap,注意能够测试如下压缩先后bitmap的大小值 */ public static Bitmap compressImage(Bitmap image , long maxSize) { int byteCount = image.getByteCount(); Log.i("yc压缩图片","压缩前大小"+byteCount); ByteArrayOutputStream baos = new ByteArrayOutputStream(); // 把ByteArrayInputStream数据生成图片 Bitmap bitmap = null; // 质量压缩方法,options的值是0-100,这里100表示原来图片的质量,不压缩,把压缩后的数据存放到baos中 image.compress(Bitmap.CompressFormat.JPEG, 100, baos); int options = 90; // 循环判断若是压缩后图片是否大于maxSize,大于继续压缩 while (baos.toByteArray().length > maxSize) { // 重置baos即清空baos baos.reset(); // 这里压缩options%,把压缩后的数据存放到baos中 image.compress(Bitmap.CompressFormat.JPEG, options, baos); // 每次都减小10,当为1的时候中止,options<10的时候,递减1 if(options == 1){ break; }else if (options <= 10) { options -= 1; } else { options -= 10; } } byte[] bytes = baos.toByteArray(); if (bytes.length != 0) { // 把压缩后的数据baos存放到bytes中 bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); int byteCount1 = bitmap.getByteCount(); Log.i("yc压缩图片","压缩后大小"+byteCount1); } return bitmap; }
/**github
/**面试
什么是采样率压缩?算法
/** * 第二种:按采样大小压缩 * * @param src 源图片 * @param sampleSize 采样率大小 * @param recycle 是否回收 * @return 按采样率压缩后的图片 */ public static Bitmap compressBySampleSize(final Bitmap src, final int sampleSize, final boolean recycle) { if (src == null || src.getWidth() == 0 || src.getHeight() == 0) { return null; } Log.i("yc压缩图片","压缩前大小"+src.getByteCount()); BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = sampleSize; ByteArrayOutputStream baos = new ByteArrayOutputStream(); src.compress(Bitmap.CompressFormat.JPEG, 100, baos); byte[] bytes = baos.toByteArray(); if (recycle && !src.isRecycled()) { src.recycle(); } Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options); Log.i("yc压缩图片","压缩后大小"+bitmap.getByteCount()); return bitmap; }
/**segmentfault
/**api
Android中使用Matrix对图像进行缩放、旋转、平移、斜切等变换的。 缓存
setTranslate(float dx,float dy):控制Matrix进行位移。 setSkew(float kx,float ky):控制Matrix进行倾斜,kx、ky为X、Y方向上的比例。 setSkew(float kx,float ky,float px,float py):控制Matrix以px、py为轴心进行倾斜,kx、ky为X、Y方向上的倾斜比例。 setRotate(float degrees):控制Matrix进行depress角度的旋转,轴心为(0,0)。 setRotate(float degrees,float px,float py):控制Matrix进行depress角度的旋转,轴心为(px,py)。 setScale(float sx,float sy):设置Matrix进行缩放,sx、sy为X、Y方向上的缩放比例。 setScale(float sx,float sy,float px,float py):设置Matrix以(px,py)为轴心进行缩放,sx、sy为X、Y方向上的缩放比例。
/** * 第三种:按缩放压缩 * * @param src 源图片 * @param newWidth 新宽度 * @param newHeight 新高度 * @param recycle 是否回收 * @return 缩放压缩后的图片 */ public static Bitmap compressByScale(final Bitmap src, final int newWidth, final int newHeight, final boolean recycle) { return scale(src, newWidth, newHeight, recycle); }
public static Bitmap compressByScale(final Bitmap src, final float scaleWidth, final float scaleHeight, final boolean recycle) {
return scale(src, scaleWidth, scaleHeight, recycle);
}markdown
/**
if (bitmap != null && !bitmap.isRecycled()) { bitmap.recycle(); bitmap = null; }
public void recycle() { if (!mRecycled && mNativePtr != 0) { if (nativeRecycle(mNativePtr)) { // return value indicates whether native pixel object was actually recycled. // false indicates that it is still in use at the native level and these // objects should not be collected now. They will be collected later when the // Bitmap itself is collected. mNinePatchChunk = null; } mRecycled = true; } }
Bitmap复用的实验,代码以下所示,而后看打印的日志信息
getByteCount()获取到的是当前图片应当所占内存大小,getAllocationByteCount()获取到的是被复用Bitmap真实占用内存大小。虽然bitmapReuse的内存只有4346880,可是由于是复用的bitmap的内存,于是其真实占用的内存大小是被复用的bitmap的内存大小(1228800)。这也是getAllocationByteCount()可能比getByteCount()大的缘由。
@RequiresApi(api = Build.VERSION_CODES.KITKAT) private void initBitmap() { BitmapFactory.Options options = new BitmapFactory.Options(); // 图片复用,这个属性必须设置; options.inMutable = true; // 手动设置缩放比例,使其取整数,方便计算、观察数据; options.inDensity = 320; options.inTargetDensity = 320; Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bg_autumn_tree_min, options); // 对象内存地址; Log.i("ycBitmap", "bitmap = " + bitmap); Log.i("ycBitmap", "ByteCount = " + bitmap.getByteCount() + ":::bitmap:AllocationByteCount = " + bitmap.getAllocationByteCount()); // 使用inBitmap属性,这个属性必须设置; options.inBitmap = bitmap; options.inDensity = 320; // 设置缩放宽高为原始宽高一半; options.inTargetDensity = 160; options.inMutable = true; Bitmap bitmapReuse = BitmapFactory.decodeResource(getResources(), R.drawable.bg_kites_min, options); // 复用对象的内存地址; Log.i("ycBitmap", "bitmapReuse = " + bitmapReuse); Log.i("ycBitmap", "bitmap:ByteCount = " + bitmap.getByteCount() + ":::bitmap:AllocationByteCount = " + bitmap.getAllocationByteCount()); Log.i("ycBitmap", "bitmapReuse:ByteCount = " + bitmapReuse.getByteCount() + ":::bitmapReuse:AllocationByteCount = " + bitmapReuse.getAllocationByteCount()); //11-26 18:24:07.971 15470-15470/com.yc.cn.ycbanner I/ycBitmap: bitmap = android.graphics.Bitmap@9739bff //11-26 18:24:07.972 15470-15470/com.yc.cn.ycbanner I/ycBitmap: bitmap:ByteCount = 4346880:::bitmap:AllocationByteCount = 4346880 //11-26 18:24:07.994 15470-15470/com.yc.cn.ycbanner I/ycBitmap: bitmapReuse = android.graphics.Bitmap@9739bff //11-26 18:24:07.994 15470-15470/com.yc.cn.ycbanner I/ycBitmap: bitmap:ByteCount = 1228800:::bitmap:AllocationByteCount = 4346880 //11-26 18:24:07.994 15470-15470/com.yc.cn.ycbanner I/ycBitmap: bitmapReuse:ByteCount = 1228800:::bitmapReuse:AllocationByteCount = 4346880 }
public final int getAllocationByteCount() { if (mRecycled) { Log.w(TAG, "Called getAllocationByteCount() on a recycle()'d bitmap! " + "This is undefined behavior!"); return 0; } return nativeGetAllocationByteCount(mNativePtr); }