2013年1月12日 星期六

Android拍照、存檔、縮放尺寸與壓縮


要使用拍照功能必須啟用的應用程式許可權
    
    
要存取檔必須啟用的應用程式許可權
    
public class CaptureImageActivity extends Activity {

 private static final int CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE = 100;
 private Uri uri;

 // 建立
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);

  final Intent imageIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

  // 資料夾不存在就建立
  File imagesFolder = new File(Environment.getExternalStorageDirectory(),
    "MyImages");
  imagesFolder.mkdirs();

  // 設定照片路徑與檔名
  File image = new File(imagesFolder, "image_001.jpg");
  uri = Uri.fromFile(image);
  imageIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);

  startActivityForResult(imageIntent, CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE);
 }

 @Override
 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
  if (requestCode == CAPTURE_IMAGE_ACTIVITY_REQUEST_CODE) {
   switch (resultCode) {
   case RESULT_CANCELED:
    break;

   case RESULT_OK:
    setupImage(uri, 320, 240, 100);
    break;
   }
  }
 }
 
 /**
 * 維持長寬比例縮放Bitmap
 *
 * @param bitmap
 * @param maxWidth
 * @param maxHeight
 * @return
 */
    public Bitmap resizeBitmap(Bitmap bitmap, int maxWidth, int maxHeight) {
        int originWidth  = bitmap.getWidth();
        int originHeight = bitmap.getHeight();

        if (originWidth < maxWidth && originHeight < maxHeight) {
            return bitmap;
        }

        int width  = originWidth;
        int height = originHeight;

        if (originWidth > maxWidth) {
            width = maxWidth;

            double i = originWidth * 1.0 / maxWidth;
            height = (int) Math.floor(originHeight / i);

            bitmap = Bitmap.createScaledBitmap(bitmap, width, height, false);
        }

        if (height > maxHeight) {
            height = maxHeight;
            bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height);
        }

        return bitmap;
    }

 /**
 * 載入影像檔並縮放縮影像檔大小與壓縮影像品質
 *
 * @param uri
 * @param maxWidth
 * @param maxHeight
 * @return
 */
 public Bitmap setupImage(Uri uri, int maxWidth, int maxHeight, int compress) {
  Bitmap tempBitmap = null;
  Bitmap bm = null;
  
  try {
   tempBitmap = BitmapFactory.decodeStream(getContentResolver().openInputStream(uri));
   
   // 縮族圖片
   bm = resizeBitmap(tempBitmap, maxWidth, maxHeight);

   Log.v("setupImage", "影像檔載入與縮放成功");

   FileOutputStream out = new FileOutputStream(uri.getPath());
   bm.compress(Bitmap.CompressFormat.JPEG, compress, out);
   out.close();
  } catch (Exception e) {
   Log.e("setupImage", "無法縮放或壓縮影像檔", e);
  }

  return bm;
 }
}

Android讀取Bar Code、QR Code

在Android開發讀取條碼(Bar Code、QR Code)最容易的方法就是使用ZXing, 在Android平板或手機上也必須安裝ZXing條碼掃描程式。

接著在專案中必須增加兩個Class, 分別是IntentIntegrator.java與IntentResult.java。


IntentIntegrator.java
/**
 * Copyright 2009 ZXing authors
 *
 * 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 tw.com.envimac.dieselreceiver;

import tw.com.envimac.dieselreceiver.IntentIntegrator;
import tw.com.envimac.dieselreceiver.IntentResult;

import android.app.AlertDialog;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;

/**
 * 

A utility class which helps ease integration with Barcode Scanner via {@link Intent}s. This is a simple * way to invoke barcode scanning and receive the result, without any need to integrate, modify, or learn the * project's source code.

* *

Initiating a barcode scan

* *

Integration is essentially as easy as calling {@link #initiateScan(Activity)} and waiting * for the result in your app.

* *

It does require that the Barcode Scanner application is installed. The * {@link #initiateScan(Activity)} method will prompt the user to download the application, if needed.

* *

There are a few steps to using this integration. First, your {@link Activity} must implement * the method {@link Activity#onActivityResult(int, int, Intent)} and include a line of code like this:

* *

{@code * public void onActivityResult(int requestCode, int resultCode, Intent intent) { * IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent); * if (scanResult != null) { * // handle scan result * } * // else continue with any other code you need in the method * ... * } * }

* *

This is where you will handle a scan result. * Second, just call this in response to a user action somewhere to begin the scan process:

* *

{@code IntentIntegrator.initiateScan(yourActivity);}

* *

You can use {@link #initiateScan(Activity, CharSequence, CharSequence, CharSequence, CharSequence)} or * {@link #initiateScan(Activity, int, int, int, int)} to customize the download prompt with * different text labels.

* *

Note that {@link #initiateScan(Activity)} returns an {@link AlertDialog} which is non-null if the * user was prompted to download the application. This lets the calling app potentially manage the dialog. * In particular, ideally, the app dismisses the dialog if it's still active in its {@link Activity#onPause()} * method.

* *

Sharing text via barcode

* *

To share text, encoded as a QR Code on-screen, similarly, see {@link #shareText(Activity, CharSequence)}.

* *

Some code, particularly download integration, was contributed from the Anobiit application.

* * @author Sean Owen * @author Fred Lin * @author Isaac Potoczny-Jones * @author Brad Drehmer */ public final class IntentIntegrator { public static final int REQUEST_CODE = 0x0ba7c0de; // get it? public static final String DEFAULT_TITLE = "Install Barcode Scanner?"; public static final String DEFAULT_MESSAGE = "This application requires Barcode Scanner. Would you like to install it?"; public static final String DEFAULT_YES = "Yes"; public static final String DEFAULT_NO = "No"; // supported barcode formats public static final String PRODUCT_CODE_TYPES = "UPC_A,UPC_E,EAN_8,EAN_13"; public static final String ONE_D_CODE_TYPES = PRODUCT_CODE_TYPES + ",CODE_39,CODE_93,CODE_128"; public static final String QR_CODE_TYPES = "QR_CODE"; public static final String ALL_CODE_TYPES = null; private IntentIntegrator() { } /** * See {@link #initiateScan(Activity, CharSequence, CharSequence, CharSequence, CharSequence)} -- * same, but uses default English labels. */ public static AlertDialog initiateScan(Activity activity) { return initiateScan(activity, DEFAULT_TITLE, DEFAULT_MESSAGE, DEFAULT_YES, DEFAULT_NO); } /** * See {@link #initiateScan(Activity, CharSequence, CharSequence, CharSequence, CharSequence)} -- * same, but takes string IDs which refer * to the {@link Activity}'s resource bundle entries. */ public static AlertDialog initiateScan(Activity activity, int stringTitle, int stringMessage, int stringButtonYes, int stringButtonNo) { return initiateScan(activity, activity.getString(stringTitle), activity.getString(stringMessage), activity.getString(stringButtonYes), activity.getString(stringButtonNo)); } /** * See {@link #initiateScan(Activity, CharSequence, CharSequence, CharSequence, CharSequence, CharSequence)} -- * same, but scans for all supported barcode types. * @param stringTitle title of dialog prompting user to download Barcode Scanner * @param stringMessage text of dialog prompting user to download Barcode Scanner * @param stringButtonYes text of button user clicks when agreeing to download * Barcode Scanner (e.g. "Yes") * @param stringButtonNo text of button user clicks when declining to download * Barcode Scanner (e.g. "No") * @return an {@link AlertDialog} if the user was prompted to download the app, * null otherwise */ public static AlertDialog initiateScan(Activity activity, CharSequence stringTitle, CharSequence stringMessage, CharSequence stringButtonYes, CharSequence stringButtonNo) { return initiateScan(activity, stringTitle, stringMessage, stringButtonYes, stringButtonNo, ALL_CODE_TYPES); } /** * Invokes scanning. * * @param stringTitle title of dialog prompting user to download Barcode Scanner * @param stringMessage text of dialog prompting user to download Barcode Scanner * @param stringButtonYes text of button user clicks when agreeing to download * Barcode Scanner (e.g. "Yes") * @param stringButtonNo text of button user clicks when declining to download * Barcode Scanner (e.g. "No") * @param stringDesiredBarcodeFormats a comma separated list of codes you would * like to scan for. * @return an {@link AlertDialog} if the user was prompted to download the app, * null otherwise * @throws InterruptedException if timeout expires before a scan completes */ public static AlertDialog initiateScan(Activity activity, CharSequence stringTitle, CharSequence stringMessage, CharSequence stringButtonYes, CharSequence stringButtonNo, CharSequence stringDesiredBarcodeFormats) { Intent intentScan = new Intent("com.google.zxing.client.android.SCAN"); intentScan.addCategory(Intent.CATEGORY_DEFAULT); // check which types of codes to scan for if (stringDesiredBarcodeFormats != null) { // set the desired barcode types intentScan.putExtra("SCAN_FORMATS", stringDesiredBarcodeFormats); } try { activity.startActivityForResult(intentScan, REQUEST_CODE); return null; } catch (ActivityNotFoundException e) { return showDownloadDialog(activity, stringTitle, stringMessage, stringButtonYes, stringButtonNo); } } private static AlertDialog showDownloadDialog(final Activity activity, CharSequence stringTitle, CharSequence stringMessage, CharSequence stringButtonYes, CharSequence stringButtonNo) { AlertDialog.Builder downloadDialog = new AlertDialog.Builder(activity); downloadDialog.setTitle(stringTitle); downloadDialog.setMessage(stringMessage); downloadDialog.setPositiveButton(stringButtonYes, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialogInterface, int i) { Uri uri = Uri.parse("market://search?q=pname:com.google.zxing.client.android"); Intent intent = new Intent(Intent.ACTION_VIEW, uri); activity.startActivity(intent); } }); downloadDialog.setNegativeButton(stringButtonNo, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialogInterface, int i) {} }); return downloadDialog.show(); } /** *

Call this from your {@link Activity}'s * {@link Activity#onActivityResult(int, int, Intent)} method.

* * @return null if the event handled here was not related to {@link IntentIntegrator}, or * else an {@link IntentResult} containing the result of the scan. If the user cancelled scanning, * the fields will be null. */ public static IntentResult parseActivityResult(int requestCode, int resultCode, Intent intent) { if (requestCode == REQUEST_CODE) { if (resultCode == Activity.RESULT_OK) { String contents = intent.getStringExtra("SCAN_RESULT"); String formatName = intent.getStringExtra("SCAN_RESULT_FORMAT"); return new IntentResult(contents, formatName); } else { return new IntentResult(null, null); } } return null; } /** * See {@link #shareText(Activity, CharSequence, CharSequence, CharSequence, CharSequence, CharSequence)} -- * same, but uses default English labels. */ public static void shareText(Activity activity, CharSequence text) { shareText(activity, text, DEFAULT_TITLE, DEFAULT_MESSAGE, DEFAULT_YES, DEFAULT_NO); } /** * See {@link #shareText(Activity, CharSequence, CharSequence, CharSequence, CharSequence, CharSequence)} -- * same, but takes string IDs which refer to the {@link Activity}'s resource bundle entries. */ public static void shareText(Activity activity, CharSequence text, int stringTitle, int stringMessage, int stringButtonYes, int stringButtonNo) { shareText(activity, text, activity.getString(stringTitle), activity.getString(stringMessage), activity.getString(stringButtonYes), activity.getString(stringButtonNo)); } /** * Shares the given text by encoding it as a barcode, such that another user can * scan the text off the screen of the device. * * @param text the text string to encode as a barcode * @param stringTitle title of dialog prompting user to download Barcode Scanner * @param stringMessage text of dialog prompting user to download Barcode Scanner * @param stringButtonYes text of button user clicks when agreeing to download * Barcode Scanner (e.g. "Yes") * @param stringButtonNo text of button user clicks when declining to download * Barcode Scanner (e.g. "No") */ public static void shareText(Activity activity, CharSequence text, CharSequence stringTitle, CharSequence stringMessage, CharSequence stringButtonYes, CharSequence stringButtonNo) { Intent intent = new Intent(); intent.setAction("com.google.zxing.client.android.ENCODE"); intent.putExtra("ENCODE_TYPE", "TEXT_TYPE"); intent.putExtra("ENCODE_DATA", text); try { activity.startActivity(intent); } catch (ActivityNotFoundException e) { showDownloadDialog(activity, stringTitle, stringMessage, stringButtonYes, stringButtonNo); } } }


IntentResult.java
/**
 * Copyright 2009 ZXing authors
 *
 * 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 tw.com.envimac.dieselreceiver;

import tw.com.envimac.dieselreceiver.IntentIntegrator;

/**
 * 

Encapsulates the result of a barcode scan invoked through {@link IntentIntegrator}.

* * @author Sean Owen */ public final class IntentResult { private final String contents; private final String formatName; IntentResult(String contents, String formatName) { this.contents = contents; this.formatName = formatName; } /** * @return raw content of barcode */ public String getContents() { return contents; } /** * @return name of format, like "QR_CODE", "UPC_A". See BarcodeFormat for more format names. */ public String getFormatName() { return formatName; } }



在頁面增加一個Button啟動條碼掃描的功能與顯示條碼內容。
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.scan_bar_code);
  
  intent = this.getIntent();
     
        final TextView tv1 = (TextView) ScanBarCodeActivity.this.findViewById(R.id.tvFormat);
        tv1.setText("");

  // 掃描條碼
  final Button b1 = (Button) this.findViewById(R.id.btnScan);
  b1.setOnClickListener(new Button.OnClickListener() {
   public void onClick(View v) {
    IntentIntegrator.initiateScan(ScanBarCodeActivity.this,
               "提示",
               "ZXing Barcode Scanner is not installed, download?",
               "Yes", "No",
               "PRODUCT_MODE");
   }
  });
 }

 
 public void onActivityResult(int requestCode, int resultCode, Intent intent) {
    switch (requestCode) {
    case IntentIntegrator.REQUEST_CODE:
       if (resultCode == Activity.RESULT_OK) {

          IntentResult intentResult =
             IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);

          if (intentResult != null) {

             String contents = intentResult.getContents();
             String format = intentResult.getFormatName();
         
             // 顯示條碼格式
             final TextView tv1 = (TextView) ScanBarCodeActivity.this.findViewById(R.id.tvFormat);
             tv1.setText(format);
          
             // 顯示條碼內容
             final EditText tv2 = (EditText) this.findViewById(R.id.edtCarNo);
             tv2.setText(contents);
          }
       }
  }
 }



參考來源:
http://stackoverflow.com/questions/12074316/how-to-create-for-intentintegrator-in-android-with-zxing

2013年1月7日 星期一

WCF『呼叫者未經過服務驗證。』的問題

最近開始使用VS2010的WCF, 跟以往的Web Service不太一樣的有資料傳遞、安全性、SOAP規範。

開發時在內部網域或是授權的電腦上使用都沒有問題, 用外部網路就會出現『呼叫者未經過服務驗證』。

工作進度為優先考量, 先將WCF預設的wsHttpBinding改成basicHttpBinding, 這樣就可以像以往的asmx類型的Web Service來使用。如果考量到資料加密性的問題, 日後還需要克服wsHttpBinding的問題。

使用WCF編輯器(WCF Service Configuration Editor), 可以在以下路徑找到
C:\Program Files\Microsoft SDKs\Windows\v6.0A\bin
C:\Program Files\Microsoft SDKs\Windows\v7.0A\bin

相關連結:
http://www.cnblogs.com/virusswb/archive/2010/02/21/1670225.html
http://www.codeproject.com/Articles/29475/Windows-Communication-Foundation-FAQ-quick-starter