原博客地址:http://blog.csdn.net/moubenmao_jun/article/details/20055189
===================================================================================================================================
基本思路是先把bitmap转化为byte数组,用Intent传递数组,在将数组转化为bitmap
bitmap转化为byte数组的方法:
- private byte[] Bitmap2Bytes(Bitmap bm){
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- bm.compress(Bitmap.CompressFormat.PNG, 100, baos);
- return baos.toByteArray();
- }
byte数组转化为bitmap方法:
- byte buff[]=mIntent.getByteArrayExtra("image");
- bitmap = BitmapFactory.decodeByteArray(buff, 0, buff.length);
=================================================================================================================
首先该文章是总结, 不是原创, 是通过看网上其他大神的文章和自己的一些实践总结出来的.
一.图片的存在形式
1.文件形式(即以二进制形式存在于硬盘上)
2.流的形式(即以二进制形式存在于内存中)
3.Bitmap形式
这三种形式的区别: 文件形式和流的形式对图片体积大小并没有影响,也就是说,如果你手机SD卡上的如果是100K,那么通过流的形式读到内存中,也一定是占100K的内存,注意是流的形式,不是Bitmap的形式,当图片以Bitmap的形式存在时,其占用的内存会瞬间变大, 我试过500K文件形式的图片加载到内存,以Bitmap形式存在时,占用内存将近10M,当然这个增大的倍数并不是固定的
检测图片三种形式大小的方法:
文件形式: file.length()
流的形式: 讲图片文件读到内存输入流中,看它的byte数
Bitmap: bitmap.getByteCount()
二.常见的压缩方式
1. 将图片保存到本地时进行压缩, 即将图片从Bitmap形式变为File形式时进行压缩,
特点是: File形式的图片确实被压缩了, 但是当你重新读取压缩后的file为 Bitmap是,它占用的内存并没有改变
- public static void compressBmpToFile(Bitmap bmp,File file){
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- int options = 80;
- bmp.compress(Bitmap.CompressFormat.JPEG, options, baos);
- while (baos.toByteArray().length / 1024 > 100) {
- baos.reset();
- options -= 10;
- bmp.compress(Bitmap.CompressFormat.JPEG, options, baos);
- }
- try {
- FileOutputStream fos = new FileOutputStream(file);
- fos.write(baos.toByteArray());
- fos.flush();
- fos.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
方法说明: 该方法是压缩图片的质量, 注意它不会减少图片的像素,比方说, 你的图片是300K的, 1280*700像素的, 经过该方法压缩后, File形式的图片是在100以下, 以方便上传服务器, 但是你BitmapFactory.decodeFile到内存中,变成Bitmap时,它的像素仍然是1280*700, 计算图片像素的方法是 bitmap.getWidth()和bitmap.getHeight(), 图片是由像素组成的, 每个像素又包含什么呢? 熟悉PS的人知道, 图片是有色相,明度和饱和度构成的.
该方法的官方文档也解释说, 它会让图片重新构造, 但是有可能图像的位深(即色深)和每个像素的透明度会变化,JPEG onlysupports opaque(不透明), 也就是说以jpeg格式压缩后, 原来图片中透明的元素将消失.所以这种格式很可能造成失真
既然它是改变了图片的显示质量, 达到了对File形式的图片进行压缩, 图片的像素没有改变的话, 那重新读取经过压缩
的file为Bitmap时, 它占用的内存并不会少.(不相信的可以试试)
因为: bitmap.getByteCount() 是计算它的像素所占用的内存, 请看官方解释: Returns the number of bytes used to
store this bitmap's pixels.
2.
将图片从本地读到内存时,进行压缩 ,即图片从File形式变为Bitmap形式
特点: 通过设置采样率, 减少图片的像素, 达到对内存中的Bitmap进行压缩
先看一个方法: 该方法是对内存中的Bitmap进行质量上的压缩, 由上面的理论可以得出该方法是无效的, 而且也是没有必要的,
因为你已经将它读到内存中了,再压缩多此一举, 尽管在获取系统相册图片时,某些手机会直接返回一个Bitmap,
但是这种情况下, 返回的Bitmap都是经过压缩的, 它不可能直接返回一个原声的Bitmap形式的图片, 后果可想而知
- private Bitmap compressBmpFromBmp(Bitmap image) {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- int options = 100;
- image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
- while (baos.toByteArray().length / 1024 > 100) {
- baos.reset();
- options -= 10;
- image.compress(Bitmap.CompressFormat.JPEG, options, baos);
- }
- ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
- Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);
- return bitmap;
- }
再看一个方法:
- private Bitmap compressImageFromFile(String srcPath) {
- BitmapFactory.Options newOpts = new BitmapFactory.Options();
- newOpts.inJustDecodeBounds = true;
- Bitmap bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
-
- newOpts.inJustDecodeBounds = false;
- int w = newOpts.outWidth;
- int h = newOpts.outHeight;
- float hh = 800f;
- float ww = 480f;
- int be = 1;
- if (w > h && w > ww) {
- be = (int) (newOpts.outWidth / ww);
- } else if (w < h && h > hh) {
- be = (int) (newOpts.outHeight / hh);
- }
- if (be <= 0)
- be = 1;
- newOpts.inSampleSize = be;
-
- newOpts.inPreferredConfig = Config.ARGB_8888;
- newOpts.inPurgeable = true;
- newOpts.inInputShareable = true;
-
- bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
-
-
- return bitmap;
- }
下面是网上另外三种图片压缩的方法 :
第一:我们先看下质量压缩方法:
- private Bitmap compressImage(Bitmap image) {
-
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
- int options = 90;
- while ( baos.toByteArray().length / 1024>100) {
- baos.reset();
- image.compress(Bitmap.CompressFormat.JPEG, options, baos);
- options -= 10;
- }
- ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
- Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);
- return bitmap;
- }
第二:图片按比例大小压缩方法(根据路径获取图片并压缩):
- private Bitmap getimage(String srcPath) {
- BitmapFactory.Options newOpts = new BitmapFactory.Options();
-
- newOpts.inJustDecodeBounds = true;
- Bitmap bitmap = BitmapFactory.decodeFile(srcPath,newOpts);
-
- newOpts.inJustDecodeBounds = false;
- int w = newOpts.outWidth;
- int h = newOpts.outHeight;
-
- float hh = 800f;
- float ww = 480f;
-
- int be = 1;
- if (w > h && w > ww) {
- be = (int) (newOpts.outWidth / ww);
- } else if (w < h && h > hh) {
- be = (int) (newOpts.outHeight / hh);
- }
- if (be <= 0)
- be = 1;
- newOpts.inSampleSize = be;
-
- bitmap = BitmapFactory.decodeFile(srcPath, newOpts);
- return compressImage(bitmap);
- }
第三:图片按比例大小压缩方法(根据Bitmap图片压缩):
- private Bitmap comp(Bitmap image) {
-
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- image.compress(Bitmap.CompressFormat.JPEG, 100, baos);
- if( baos.toByteArray().length / 1024>1024) {
- baos.reset();
- image.compress(Bitmap.CompressFormat.JPEG, 50, baos);
- }
- ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());
- BitmapFactory.Options newOpts = new BitmapFactory.Options();
-
- newOpts.inJustDecodeBounds = true;
- Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, newOpts);
- newOpts.inJustDecodeBounds = false;
- int w = newOpts.outWidth;
- int h = newOpts.outHeight;
-
- float hh = 800f;
- float ww = 480f;
-
- int be = 1;
- if (w > h && w > ww) {
- be = (int) (newOpts.outWidth / ww);
- } else if (w < h && h > hh) {
- be = (int) (newOpts.outHeight / hh);
- }
- if (be <= 0)
- be = 1;
- newOpts.inSampleSize = be;
-
- isBm = new ByteArrayInputStream(baos.toByteArray());
- bitmap = BitmapFactory.decodeStream(isBm, null, newOpts);
- return compressImage(bitmap);
- }
Android 设置壁纸功能 :
在Android中设置壁纸的方法有三种,分别是:
1、使用WallpaperManager的setResource(int ResourceID)方法
2、使用WallpaperManager的setBitmap(Bitmap bitmap)方法
3、重写ContextWrapper 类中提供的setWallpaper()
除此之外,我们还需要在应用程序中加入下列权限: <uses-permission android:name="android.permission.SET_WALLPAPER"/>
下面我们以此为基本方法,来实现Android中自带的壁纸应用。首先来看我的布局代码:
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="vertical"
- android:background="#000000"
- tools:context=".MainActivity" >
- <ImageSwitcher
- android:id="@+id/ImageSwitcher"
- android:layout_width="fill_parent"
- android:layout_height="370dp">
- </ImageSwitcher>
- <Gallery
- android:id="@+id/Gallery"
- android:layout_width="fill_parent"
- android:layout_height="80dp"
- android:layout_below="@+id/ImageSwitcher" />
- <Button
- android:id="@+id/BtnGo"
- android:layout_width="wrap_content"
- android:layout_height="40dp"
- android:layout_below="@+id/Gallery"
- android:layout_alignParentBottom="true"
- android:layout_centerHorizontal="true"
- android:text="@string/BtnGo" />
- </RelativeLayout>
在这里我们使用Gallery来实现一个可以供用户选择的缩略图列表,当用户选择列表中的图像时,会在ImageSwitcher控件中显示出当前图像,当点击Button时,当前图片将被设置为壁纸。其实这里的ImageSwitcher完全可以替换为ImageView,考虑到ImageSwitcher可以提供较好的动画效果,所以我们在这里选择了ImageSwitcher。同样地,我们继续使用
Android开发学习之Gallery中的那个ImageAdapter类:
- package com.android.gallery2switcher;
-
- import android.content.Context;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.BaseAdapter;
- import android.widget.ImageView;
-
- public class ImageAdapter extends BaseAdapter{
-
-
- private Context myContext;
- private int[] myImages;
-
-
- public ImageAdapter(Context c,int[] Images)
- {
-
- this.myContext=c;
- this.myImages=Images;
- }
-
-
- @Override
- public int getCount()
- {
-
- return this.myImages.length;
- }
-
-
- @Override
- public Object getItem(int position)
- {
- return position;
- }
-
-
- @Override
- public long getItemId(int position)
- {
- return position;
- }
-
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent)
- {
- ImageView image=new ImageView(this.myContext);
- image.setImageResource(this.myImages[position]);
- image.setScaleType(ImageView.ScaleType.FIT_XY);
- image.setAdjustViewBounds(true);
- return image;
- }
-
- }
现在,我们就可以开始编写程序了,后台的代码如下:
- package com.android.gallery2switcher;
-
- import java.io.IOException;
-
- import android.os.Bundle;
- import android.app.Activity;
- import android.app.WallpaperManager;
- import android.view.Menu;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.view.Window;
- import android.view.animation.AnimationUtils;
- import android.widget.AdapterView;
- import android.widget.AdapterView.OnItemSelectedListener;
- import android.widget.Button;
- import android.widget.Gallery;
- import android.widget.Gallery.LayoutParams;
- import android.widget.ImageSwitcher;
- import android.widget.ImageView;
- import android.widget.ViewSwitcher.ViewFactory;
-
- public class MainActivity extends Activity {
-
- Gallery mGallery;
- ImageSwitcher mSwitcher;
- Button BtnGo;
- int[] Resources=new int[]{R.drawable.image0,R.drawable.image1,R.drawable.image2,R.drawable.image3,
- R.drawable.image4,R.drawable.image5,R.drawable.image6,R.drawable.image7,R.drawable.image8};
- int index;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- requestWindowFeature(Window.FEATURE_NO_TITLE);
- setContentView(R.layout.activity_main);
- mGallery=(Gallery)findViewById(R.id.Gallery);
- mSwitcher=(ImageSwitcher)findViewById(R.id.ImageSwitcher);
-
- mSwitcher.setFactory(new ViewFactory()
- {
- @Override
- public View makeView()
- {
- ImageView i = new ImageView(MainActivity.this);
- i.setBackgroundColor(0xFF000000);
- i.setScaleType(ImageView.ScaleType.FIT_CENTER);
- i.setLayoutParams(new ImageSwitcher.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
- return i;
- }
- });
-
- mSwitcher.setImageResource(Resources[0]);
-
- mSwitcher.setInAnimation(AnimationUtils.loadAnimation(this,android.R.anim.fade_in));
- mSwitcher.setOutAnimation(AnimationUtils.loadAnimation(this,android.R.anim.fade_out));
- BtnGo=(Button)findViewById(R.id.BtnGo);
- BtnGo.setOnClickListener(new OnClickListener()
- {
- @Override
- public void onClick(View arg0)
- {
- SetWallPaper();
- }
- });
- ImageAdapter mAdapter=new ImageAdapter(this,Resources);
- mGallery.setAdapter(mAdapter);
- mGallery.setOnItemSelectedListener(new OnItemSelectedListener()
- {
- @Override
- public void onItemSelected(AdapterView<?> Adapter, View view,int position, long id)
- {
-
- mSwitcher.setImageResource(Resources[position]);
-
- index=position;
- }
- @Override
- public void onNothingSelected(AdapterView<?> arg0)
- {
-
- }
-
- });
-
-
- }
-
- public void SetWallPaper()
- {
- WallpaperManager mWallManager=WallpaperManager.getInstance(this);
- try
- {
- mWallManager.setResource(Resources[index]);
- }
- catch (IOException e)
- {
- e.printStackTrace();
- }
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu)
- {
- return true;
- }
-
- }
可以看到,在使用ImageSwitcher的时候,我们需要实现它的工厂接口,并且这里的makeView()方法和BaseAdapter里的getView()方法是一样的,即返回一个View视图。我们ImageSwitcher给使用了系统默认的动画效果。最终运行效果如下: