2D Graphics Android

/*
 * Copyright (C) 2008-2010 aki@akjava.com
 *
 * 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 com.akjava.lib.android.image;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory.Options;
import android.util.Log;
/**
 * 
 * @author aki
 * @version 1.0
 * ?????????????
 * ????????????????
 *
 */
class ImageUtils {
  public static final String[] imageExtensions={"jpg","png","jpeg","gif"};
  
  private ImageUtils(){}
  /**
   * ????????·????????????????????????????????
   * ????????????????
   * 
   * @param baseImage ???
   * @param width ??
   * @param height ??
   * @return  ?????????????????
   */
  public static Bitmap fitImageNoMargin(Bitmap baseImage,int width,int height){
    
    Point pt=calculateFitImage(baseImage,width,height,null);//TODO gc free
    Bitmap resizedBitmap = Bitmap.createScaledBitmap(baseImage,
        pt.x, pt.y, true); 
    return resizedBitmap;
  }
  
  /**
   * ??????????????????????????????????
   * ?????????????????
   * ??????????????????????
   * 
   * @param path
   * @param width
   * @param config
   * @return
   */
  public static Bitmap sampleSizeOpenBitmapByWidth(String path,int width,Bitmap.Config config){
    Point size=parseJpegSize(path, null);
    int rw=size.x/width;
    
    int sampleSize=Math.max(rw, 1);
    Bitmap bitmap=sampleSizeOpenBitmap(path, sampleSize);
    return bitmap;
  }
  
/**
 * ???????????????·???????????
 * 
 * 
 * @param path
 * @param width
 * @param height
 * @param config null????Bitmap.Config.RGB_565??????
 * @return ?????·????????????????????????
 */
  public static Bitmap fitImage(String path,int width,int height,Bitmap.Config config){
    //TODO set bgcolor
    Point size=parseJpegSize(path, null);
    int rw=size.x/width;
    int rh=size.y/height;
    int sampleSize=Math.min(rw, rh);
    sampleSize=Math.max(sampleSize, 1);
    Bitmap bitmap=sampleSizeOpenBitmap(path, sampleSize,config);
    return fitImage(bitmap, width, height, config, true);
  }
  
    
  
  
  /**
   * ????????????
   * 
   * @param baseImage
   * @param width
   * @param height
   * @param config null????Bitmap.Config.RGB_565??????
   * @param doRecycleBase ???bitmap?recycle???????true??
   * @return ?????·????????????????????????
   */
  public static Bitmap fitImage(Bitmap baseImage,int width,int height,Bitmap.Config config,boolean doRecycleBase){
    if(baseImage==null){
      throw new RuntimeException("baseImage is null");
    }
    if(config==null){
      config=Bitmap.Config.RGB_565;
    }
    Point resizedP=calculateFitImage(baseImage, width, height, null);//TODO gc free
    
    
        Bitmap resizedBitmap =  Bitmap.createScaledBitmap(baseImage,
        resizedP.x, resizedP.y, true); 
        
        if(doRecycleBase){//to avoid memory error
          baseImage.recycle();
        }
        
        Bitmap returnBitmap=Bitmap.createBitmap(width, height, config);
        Canvas canvas=new Canvas(returnBitmap);
        canvas.drawBitmap(resizedBitmap, (width-resizedP.x)/2, (height-resizedP.y)/2,null);
        resizedBitmap.recycle();
        
    return returnBitmap;
  }
  
  /**
   * ????????????????????????????
   * 
   * @param baseImage
   * @param width
   * @param height
   * @param receiver
   * @return
   */
  public static Point calculateFitImage(Bitmap baseImage,int width,int height,Point receiver){
    if(baseImage==null){
      throw new RuntimeException("baseImage is null");
    }
    if(receiver==null){
      receiver=new Point();
    }
    int dw=width;
    int dh=height;
    
    
    if(dw!=0 && dh!=0 ){
      double waspect=(double)dw/baseImage.getWidth();
      double haspect=(double)dh/baseImage.getHeight();
      if(waspect>haspect){//fit h
        dw=(int) (baseImage.getWidth()*haspect);
        
      }else{
        dh=(int)(baseImage.getHeight()*waspect);
      }
    }
    receiver.x=dw;
    receiver.y=dh;
    return receiver;
  }
  /**
   *  ????????????????????recyle?????
   *  
   * @param baseImage
   * @param width
   * @param height
   * @return
   */
  public static Bitmap toTextureImage(Bitmap baseImage,int width,int height){
    return toTextureImage(baseImage, width, height,false);
  }
  
  /**
   * PNG ??????????
   * 
   * @param bitmap
   * @param output
   * @return
   * @throws FileNotFoundException
   */
  public static boolean writeAsPng(Bitmap bitmap,String output) throws FileNotFoundException{
    return bitmap.compress(Bitmap.CompressFormat.PNG, 1, new FileOutputStream(output));
  }
  
  /**
   * ???????????????
   * 
   * @param baseImage
   * @param width must be divided 2 (like 256 or 512)
   * @param height must be divided 2 (like 256 or 512)
   * @return
   */
  public static Bitmap toTextureImage(Bitmap baseImage,int width,int height,boolean recycle){
  
    int owidth = baseImage.getWidth(); 
        int oheight = baseImage.getHeight(); 
       
        
        // calculate the scale - in this case = 0.4f 
        float scaleWidth = ((float) width) / owidth; 
        float scaleHeight = ((float) height) / oheight; 
    
      
    Matrix matrix = new Matrix(); 
      
        // resize the bit map 
        matrix.postScale(scaleWidth, -scaleHeight); 
        // rotate the Bitmap 
        //matrix.postRotate(-180); 
        
        Bitmap resizedBitmap = Bitmap.createBitmap(baseImage, 0, 0, 
            owidth, oheight, matrix, true); 
        if(recycle){
          baseImage.recycle();
        }
        Log.i("myapp","resized:"+resizedBitmap.getWidth()+"x"+resizedBitmap.getHeight());
    
    return resizedBitmap;
  }
  
  /**
   * ?????????????????????????
   * 
   * @param baseImage
   * @param width
   * @param height
   * @param rotateRight
   * @return
   */
  public static Bitmap toRotateTextureImage(Bitmap baseImage,int width,int height,boolean rotateRight){
    
    int owidth = baseImage.getWidth(); 
        int oheight = baseImage.getHeight(); 
       
        
        // calculate the scale - in this case = 0.4f 
        float scaleWidth = ((float) width) / owidth; 
        float scaleHeight = ((float) height) / oheight; 
    
      
    Matrix matrix = new Matrix(); 
      
        // resize the bit map 
        matrix.postScale(scaleWidth, -scaleHeight); 
        // rotate the Bitmap 
        if(rotateRight){
        matrix.postRotate(90); 
        }else{
        matrix.postRotate(-90);   
        }
        
        Bitmap resizedBitmap = Bitmap.createBitmap(baseImage, 0, 0, 
            owidth, oheight, matrix, true); 
        
        Log.i("myapp","resized:"+resizedBitmap.getWidth()+"x"+resizedBitmap.getHeight());
    
    return resizedBitmap;
  }
  
  /**
   * ???????????sampleSize???????width?height??????????
   */
  public static int lastSampleSize=1;
  //public static BitmapFactory.Options bitmapOption;//cancel????????denger
  
  /**
   *  ?????????????????????
   *  ???????????????????????????????????????
   *  
   * @param path
   * @param startSize
   * @param config
   * @return
   */
  public static Bitmap sampleSizeOpenBitmap(String path, int startSize,
      Config config) {
    BitmapFactory.Options bitmapOption = new BitmapFactory.Options();
    bitmapOption.inPreferredConfig=config;
    return sampleSizeOpenBitmap(path, startSize,bitmapOption);
  }
  
  /**
   *  ?????????????????????
   *  ???????????????????????????????????????
   *  
   * @param path
   * @param startSize
   * @param bitmapOption
   * @return
   */
  public static Bitmap sampleSizeOpenBitmap(String path, int startSize,
      Options bitmapOption) {    
    int inSampleSize=startSize;
    Bitmap bitmap=null;
    for(int i=0;i<10;i++){
      
    try{
      bitmapOption.inSampleSize=inSampleSize;
      bitmap=BitmapFactory.decodeFile(path,bitmapOption);
      //Log.i("imageutils","decoded bitmap:"+bitmapOption.inSampleSize);
      lastSampleSize=inSampleSize;
      if(bitmap==null){
        System.gc();//ready for next
      }
    }catch(Error e){
      Log.i("imageutils","faild load:"+inSampleSize+" "+path);
    }
    if(bitmap!=null || bitmapOption.mCancel){
      break;
    }else{
      //inSampleSize*=2;
      inSampleSize+=1;
    }
  }
    return bitmap;
  }
  
  /**
   * ??????????????????????
   * 
   * @param path
   * @param width
   * @param height
   * @param config
   * @return
   */
  public static Bitmap sampleSizeOpenBitmap(String path,int width,int height,Config config){
    Point size=parseJpegSize(path, null);
    int rw=size.x/width;
    int rh=size.y/height;
    int sampleSize=Math.min(rw, rh);
    sampleSize=Math.max(sampleSize, 1);
    return sampleSizeOpenBitmap(path, sampleSize,config);
  }
  
  /**
   * MemoryError????????????Content://????????
   * ???? RGB565?????
   * @see MediaImageUtils#loadImageFileOrUri(android.content.ContentResolver, String)
   * @param path
   * @param startSize
   * @return
   */
  
  public static Bitmap sampleSizeOpenBitmap(String path,int startSize){
    return sampleSizeOpenBitmap(path, startSize,(Config) null);
  }
  
  /**
   * ????????????????????
   * @param name
   * @return
   */
  public static boolean isImageFile(String name){
    for (int i = 0; i < imageExtensions.length; i++) {
    if(name.toLowerCase().endsWith("."+imageExtensions[i]))  {
      return true;
    }
    }
    return false;
  }
  
  /**
   * ?????????
   * 
   * @param bitmap
   * @param rect
   * @return
   */
  public static Bitmap cropBitmap(Bitmap bitmap,Rect rect){
    int w=rect.right-rect.left;
    int h=rect.bottom-rect.top;
    Bitmap ret=Bitmap.createBitmap(w, h, bitmap.getConfig());
    Canvas canvas=new Canvas(ret);
    canvas.drawBitmap(bitmap, -rect.left, -rect.top, null);
    return ret;
  }
  
  /**
   * JPEG???????????
   * 
   * @param path
   * @param receiver
   * @return
   */
  public static Point parseJpegSize(String path,Point receiver){
    if(receiver==null){
      receiver=new Point();
    }
    
    Options option=new BitmapFactory.Options();
    option.inJustDecodeBounds=true;
    BitmapFactory.decodeFile(path,option);
    receiver.x=option.outWidth;
    receiver.y=option.outHeight;
    return receiver;
  }
  
}