Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發實例 >> Android多媒體學習四:實現圖像的編輯和合成

Android多媒體學習四:實現圖像的編輯和合成

編輯:Android開發實例

閒話少說,全在注釋中:

 

  1. package demo.camera;  
  2. import java.io.FileNotFoundException;  
  3. import android.app.Activity;  
  4. import android.content.Intent;  
  5. import android.graphics.Bitmap;  
  6. import android.graphics.BitmapFactory;  
  7. import android.graphics.Canvas;  
  8. import android.graphics.ColorMatrix;  
  9. import android.graphics.ColorMatrixColorFilter;  
  10. import android.graphics.Matrix;  
  11. import android.graphics.Paint;  
  12. import android.graphics.PorterDuff;  
  13. import android.graphics.PorterDuffXfermode;  
  14. import android.net.Uri;  
  15. import android.os.Bundle;  
  16. import android.provider.MediaStore;  
  17. import android.util.Log;  
  18. import android.view.Menu;  
  19. import android.view.MenuItem;  
  20. import android.view.View;  
  21. import android.widget.Button;  
  22. import android.widget.ImageView;  
  23. /**  
  24.  * 在Android中我們可以對圖像進行編輯處理等操作  
  25.  * 包括放大縮小,旋轉,偏移,裁剪,以及更改亮度,飽和度等  
  26.  *   
  27.  * 1、首先,從SDCard中選擇圖片,采用Android自帶的Callery應用獲得  
  28.  * Gallery是Android自帶的圖片和視頻管理應用  
  29.  * 使用Intent來啟動Gallery應用,需要指定兩個參數,一個是Action,另一個是多媒體存放的URI  
  30.  * Action是一個通用的Action叫ACTION_PICK,來告訴Gallery,我們想檢索數據。  
  31.  * 第二個是Data,是一個URI,這裡當然是MediaStore.Images.Media.EXTERNAL_CONTENT_URI  
  32.  * 當在Gallery中選擇了一個圖片的時候,返回的Intent中的Data域就是所選圖片對應的URI  
  33.  *   
  34.  * @author Administrator  
  35.  *  
  36.  */ 
  37. public class PhotoProcess extends Activity{  
  38.     public static final int FIRST_PIC = 0;  
  39.     public static final int SECOND_PIC = 1;  
  40.     public static final int MAX_WIDTH = 240;  
  41.     public static final int MAX_HEIGHT = 180;  
  42.     private Button btnSelect,btnSelect2;  
  43.     private ImageView srcImageView, dstImageView;  
  44.       
  45.     private Bitmap srcBitmap, dstBitmap;  
  46.     private Uri imageUri;  
  47.       
  48.       
  49.     public void onCreate(Bundle savedInstanceState){  
  50.         super.onCreate(savedInstanceState);  
  51.         this.setContentView(R.layout.process);  
  52.           
  53.         this.btnSelect = (Button)this.findViewById(R.id.btn_select);  
  54.         btnSelect.setOnClickListener(clickListener);  
  55.         this.btnSelect2 = (Button)this.findViewById(R.id.btn_select2);  
  56.         btnSelect2.setOnClickListener(clickListener2);  
  57.         srcImageView = (ImageView)this.findViewById(R.id.img_src);  
  58.         dstImageView = (ImageView)this.findViewById(R.id.img_dst);  
  59.     }  
  60.       
  61.     private View.OnClickListener clickListener = new View.OnClickListener() {  
  62.           
  63.         @Override 
  64.         public void onClick(View arg0) {  
  65.             // 啟動Gallery應用  
  66.             Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);  
  67.             startActivityForResult(intent, FIRST_PIC);  
  68.         }  
  69.     };  
  70.     private View.OnClickListener clickListener2 = new View.OnClickListener() {  
  71.           
  72.         @Override 
  73.         public void onClick(View arg0) {  
  74.             // 啟動Gallery應用  
  75.             Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);  
  76.             startActivityForResult(intent, SECOND_PIC);  
  77.               
  78.         }  
  79.     };    
  80.       
  81.     public boolean onCreateOptionsMenu(Menu menu){  
  82.         //super.onCreateOptionsMenu(menu);  
  83.         //MenuInflater menuInflater = new MenuInflater(this);  
  84.         //menuInflater.inflate(R.layout.image, menu)  
  85.         menu.add(Menu.NONE,1,Menu.NONE,"復制");  
  86.         menu.add(Menu.NONE,2,Menu.NONE,"變換");  
  87.         menu.add(Menu.NONE,3,Menu.NONE,"亮度");  
  88.         menu.add(Menu.NONE,4,Menu.NONE,"合成");  
  89.         return super.onCreateOptionsMenu(menu);  
  90.     }  
  91.       
  92.     public boolean onOptionsItemSelected(MenuItem item){  
  93.         int id = item.getItemId();  
  94.         switch(id){  
  95.         case 1:  
  96.             //復制一個圖像  
  97.             if(srcBitmap != null){  
  98.                 dstBitmap = getDstImage(null);//這裡沒有變換  
  99.                 dstImageView.setImageBitmap(dstBitmap);  
  100.             }  
  101.             break;  
  102.         case 2:  
  103.             //對復制後的圖像進行變換  
  104.             if(srcBitmap != null){  
  105.                 dstBitmap = transferImage();  
  106.                 dstImageView.setImageBitmap(dstBitmap);  
  107.             }  
  108.             break;  
  109.         case 3:  
  110.             //改變圖像的色彩  
  111.             if(srcBitmap != null){  
  112.                 dstBitmap = ajustImage();  
  113.                 dstImageView.setImageBitmap(dstBitmap);  
  114.             }  
  115.             break;  
  116.         case 4:  
  117.             if(srcBitmap != null && dstBitmap != null){  
  118.                 dstBitmap = compositeImages();  
  119.                 dstImageView.setImageBitmap(dstBitmap);  
  120.             }  
  121.             break;  
  122.         }  
  123.         return true;  
  124.     }  
  125.       
  126.     /**  
  127.      * 為了創建一個圖像的副本,我們可以在創建一個新的空的Bitmap,然後在這個Bitmap上繪制一個Bitmap  
  128.      * 這個空的Bitmap應該和已存在的Bitmap具有相同的尺寸和顏色深度  
  129.      *   
  130.      * 然後我們需要一個Canvas對象,一個Canvas簡單說,就是一個畫布,存放Bitmap,在構造時,就可以傳入Bitmap對象  
  131.      * 同時,Canvas中定義了很多便捷的畫圖方法,方便我們繪制各種圖形  
  132.      * 接下來,如果我們需要處理顏色和對比度,我們需要一個Paint對象,通過Paint我們可以設置畫筆的各種特性。  
  133.      *   
  134.      * 最後,我們調用Canvas的drawBitmap就可以將原Bitmap繪制在dstBitmap上了  
  135.      *   
  136.      */ 
  137.     private Bitmap getDstImage(Matrix matrix){  
  138.           
  139.         Bitmap bmp = null;  
  140.         //下面這個Bitmap中創建的函數就可以創建一個空的Bitmap  
  141.         //返回的是一個可以改變的Bitmap對象,這樣我們後面就可以對其進行變換和顏色調整等操作了  
  142.         bmp = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), srcBitmap.getConfig());  
  143.         //創建Canvas對象,  
  144.         Canvas canvas = new Canvas(bmp);   
  145.         //創建Paint對象,這裡先不用  
  146.         Paint paint = new Paint();  
  147.         //在Canvas上繪制一個已經存在的Bitmap。這樣,dstBitmap就和srcBitmap一摸一樣了  
  148.           
  149.         if(matrix != null){  
  150.             //如果matrix存在,則采用變換  
  151.             canvas.drawBitmap(dstBitmap, matrix, paint);  
  152.         }else{  
  153.             canvas.drawBitmap(srcBitmap, 0, 0, paint);  
  154.         }  
  155.           
  156.           
  157.         return bmp;  
  158.  
  159.     }  
  160.       
  161.       
  162.     /**  
  163.      * 重載getDstImage函數,傳入定制的Paint對象  
  164.      * @param matrix  
  165.      * @param paint  
  166.      * @return  
  167.      */ 
  168.     private Bitmap getDstImage(Matrix matrix, Paint paint){  
  169.           
  170.         Bitmap bmp = null;  
  171.         //下面這個Bitmap中創建的函數就可以創建一個空的Bitmap  
  172.         //返回的是一個可以改變的Bitmap對象,這樣我們後面就可以對其進行變換和顏色調整等操作了  
  173.         bmp = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), srcBitmap.getConfig());  
  174.         //創建Canvas對象,  
  175.         Canvas canvas = new Canvas(bmp);   
  176.           
  177.         //在Canvas上繪制一個已經存在的Bitmap。這樣,dstBitmap就和srcBitmap一摸一樣了  
  178.           
  179.         if(matrix != null){  
  180.             //如果matrix存在,則采用變換  
  181.             canvas.drawBitmap(dstBitmap, matrix, paint);  
  182.         }else{  
  183.             canvas.drawBitmap(srcBitmap, 0, 0, paint);  
  184.         }  
  185.           
  186.           
  187.         return bmp;  
  188.  
  189.     }     
  190.       
  191.     /**  
  192.      * 為了放大縮小、旋轉圖像,我們要使用Matrix類。Matrix類是一個三維矩陣。  
  193.      * 在Android屏幕中,圖像的每個像素對應都是一個坐標,一個坐標由x/y/z組成  
  194.      * ------------------------  
  195.      * cosX -sinX translateX  
  196.      * sinX cosX  translateY  
  197.      * 0    0     scale  
  198.      * ------------------------  
  199.      * 第一行的值,影響著x坐標。比如 1 0 0 =>x = 1*x + 0*y + 0*z  
  200.      * 第二行的值,影響著y坐標。比如0 1 0 => y = 0*x + 1*y + 0*z  
  201.      * 第三行的值,影響著z坐標。比如 0 0 1 => z = 0*x + 0*y + 1*z  
  202.      *   
  203.      * 我們自己計算一個矩陣然後通過Matrax.setValues設置。  
  204.      * 這樣,在調用canvas的drawBitmap方法時,傳入matrix  
  205.      *   
  206.      * Matrix類並不提倡我們使用這種方式來操作變換,Matrix針對不同的變換都相應的有pre,set,post三種方法  
  207.      * 可以使用。  
  208.      * pre是矩陣前乘  
  209.      * set是直接設置  
  210.      * post是矩陣後乘  
  211.      */ 
  212.     private Bitmap transferImage(){  
  213.         Matrix matrix = new Matrix();  
  214.         matrix.setValues(new float[]{  
  215.             .5f,0,0,//這裡只會影響到x軸,所以,圖片的長度將是原來的一半  
  216.             0,1,0,  
  217.             0,0,1 
  218.         });  
  219.         return this.getDstImage(matrix);  
  220.     }  
  221.       
  222.     /**  
  223.      * 該方法中我們將對圖像的顏色,亮度,對比度等進行設置  
  224.      * 需要用到ColorMatrix類。ColorMatrix類是一個四行五列的矩陣  
  225.      * 每一行影響著[R,G,B,A]中的一個  
  226.      * -------------------------  
  227.      * a1 b1 c1 d1 e1  
  228.      * a2 b2 c2 d2 e2  
  229.      * a3 b3 c3 d3 e3  
  230.      * a4 b4 c4 d4 e4  
  231.      * -------------------------  
  232.      * Rnew => a1*R+b1*G+c1*B+d1*A+e1  
  233.      * Gnew => a2*R+b2*G+c2*B+d2*A+e2  
  234.      * Bnew => a3*R+b3*G+c3*B+d3*A+e3  
  235.      * Gnew => a4*R+b4*G+c4*B+d4*A+e4  
  236.      * 其中R,G,B的值是128,A的值是0  
  237.      *   
  238.      * 最後將顏色的修改,通過Paint.setColorFilter應用到Paint對象中。  
  239.      * 主要對於ColorMatrix,需要將其包裝成ColorMatrixColorFilter對象,再傳給Paint對象  
  240.      *   
  241.      * 同樣的,ColorMatrix提供給我們相應的方法,setSaturation()就可以設置一個飽和度  
  242.      */ 
  243.     private Bitmap ajustImage(){  
  244.         ColorMatrix cMatrix = new ColorMatrix();  
  245. //      int brightIndex = -25;  
  246. //      int doubleColor = 2;  
  247. //      cMatrix.set(new float[]{  
  248. //              doubleColor,0,0,0,brightIndex, //這裡將1改為2則我們讓Red的值為原來的兩倍  
  249. //              0,doubleColor,0,0,brightIndex,//改變最後一列的值,我們可以不改變RGB同道顏色的基礎上,改變亮度  
  250. //              0,0,doubleColor,0,brightIndex,  
  251. //              0,0,0,doubleColor,0  
  252. //      });  
  253.         //cMatrix.setSaturation(2.0f);//設置飽和度  
  254.         cMatrix.setScale(2.0f, 2.0f, 2.0f, 2.0f);//設置顏色同道色彩縮放  
  255.         Paint paint = new Paint();  
  256.         paint.setColorFilter(new ColorMatrixColorFilter(cMatrix));  
  257.         return this.getDstImage(null, paint);  
  258.     }  
  259.       
  260.     /**  
  261.      * 圖像的合成,可以通過在同一個Canvas中繪制兩張圖片。  
  262.      * 只是在繪制第二章圖片的時候,需要給Paint指定一個變幻模式TransferMode。  
  263.      * 在Android中有一個XFermode所有的變幻模式都是這個類的子類  
  264.      * 我們需要用到它的一個子類PorterDuffXfermode,關於這個類,其中用到PorterDuff類  
  265.      * 這個類很簡單,就包含一個Enum是Mode,其中定義了一組規則,這組規則就是如何將  
  266.      * 一張圖像和另一種圖像進行合成  
  267.      * 關於圖像合成有四種模式,LIGHTEN,DRAKEN,MULTIPLY,SCREEN  
  268.      */ 
  269.     private Bitmap compositeImages(){  
  270.           
  271.         Bitmap bmp = null;  
  272.         //下面這個Bitmap中創建的函數就可以創建一個空的Bitmap  
  273.         bmp = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), srcBitmap.getConfig());  
  274.         Paint paint = new Paint();  
  275.         Canvas canvas = new Canvas(bmp);  
  276.         //首先繪制第一張圖片,很簡單,就是和方法中getDstImage一樣  
  277.         canvas.drawBitmap(srcBitmap, 0, 0, paint);        
  278.           
  279.         //在繪制第二張圖片的時候,我們需要指定一個Xfermode  
  280.         //這裡采用Multiply模式,這個模式是將兩張圖片的對應的點的像素相乘  
  281.         //,再除以255,然後以新的像素來重新繪制顯示合成後的圖像  
  282.         paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));  
  283.         canvas.drawBitmap(dstBitmap, 0, 0, paint);  
  284.           
  285.         return bmp;  
  286.     }  
  287.     public void onActivityResult(int requestCode, int resultCode, Intent data){  
  288.         super.onActivityResult(requestCode, resultCode, data);  
  289.           
  290.         Log.v("Result OK Value:", resultCode+"");  
  291.         Log.v("RequestCode Value", requestCode+"");  
  292.           
  293.         if(resultCode == RESULT_OK){  
  294.             imageUri = data.getData();    
  295.             if(requestCode == FIRST_PIC){  
  296.                 //在Gallery中選中一個圖片時,返回來的Intent中的Data就是選擇圖片的Uri  
  297.                 srcBitmap = getSrcImage(imageUri);  
  298.                 srcImageView.setImageBitmap(srcBitmap);               
  299.             }else if(requestCode == SECOND_PIC){  
  300.                 //這裡處理用戶選擇的第二張圖片  
  301.                   
  302.                 dstBitmap = getSrcImage(imageUri);  
  303.                 dstImageView.setImageBitmap(dstBitmap);  
  304.             }  
  305.         }  
  306.     }  
  307.       
  308.     /**  
  309.      * 需要加載的圖片可能是大圖,我們需要對其進行合適的縮小處理  
  310.      * @param imageUri  
  311.      */ 
  312.     private Bitmap getSrcImage(Uri imageUri){  
  313.         //Display display = this.getWindowManager().getDefaultDisplay();  
  314.         try {  
  315.             BitmapFactory.Options ops = new BitmapFactory.Options();  
  316.             ops.inJustDecodeBounds = true;  
  317.             Bitmap bmp = BitmapFactory.decodeStream(this.getContentResolver().openInputStream(imageUri),null,ops);  
  318.             int wRatio = (int)Math.ceil(ops.outWidth/(float)MAX_WIDTH);  
  319.             int hRatio = (int)Math.ceil(ops.outHeight/(float)MAX_HEIGHT);  
  320.               
  321.             if(wRatio > 1 && hRatio > 1){  
  322.                 if(wRatio > hRatio){  
  323.                     ops.inSampleSize = wRatio;  
  324.                 }else{  
  325.                     ops.inSampleSize = hRatio;  
  326.                 }  
  327.             }  
  328.               
  329.             ops.inJustDecodeBounds = false;  
  330.             bmp = BitmapFactory.decodeStream(this.getContentResolver().openInputStream(imageUri),null,ops);  
  331.               
  332.             return bmp;  
  333.               
  334.         } catch (FileNotFoundException e) {  
  335.             // TODO Auto-generated catch block  
  336.             e.printStackTrace();  
  337.             Log.e(this.getClass().getName(), e.getMessage());  
  338.         }  
  339.           
  340.         return null;  
  341.     }  
  342. }  
  343.  

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved