java - 在从独立相机捕获的图像上绘制文本(时间戳)

标签 java android text bitmap timestamp

我的代码在下面,点击后会打开相机,拍照,从相机中获取照片,然后将其放入 ImageView 中。但是我想拍摄图像并在图像上应用文本(某种时间戳,最好是图像的时间戳,或者只是系统日期时间)并保存为 jpeg。

如果有人能帮助我,那就太棒了。

public class PhotoIntentActivity extends Activity {

private static final int ACTION_TAKE_PHOTO_B = 1;

private static final String BITMAP_STORAGE_KEY = "viewbitmap";
private static final String IMAGEVIEW_VISIBILITY_STORAGE_KEY =  "imageviewvisibility";
private ImageView mImageView;
private Bitmap mImageBitmap;

private String mCurrentPhotoPath;

private static final String JPEG_FILE_PREFIX = "IMG_";
private static final String JPEG_FILE_SUFFIX = ".jpg";

private AlbumStorageDirFactory mAlbumStorageDirFactory = null;


/* Photo album for this application */
private String getAlbumName() {
    return getString(R.string.album_name);
}


private File getAlbumDir() {
    File storageDir = null;

    if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {

        storageDir = mAlbumStorageDirFactory.getAlbumStorageDir(getAlbumName());

        if (storageDir != null) {
            if (! storageDir.mkdirs()) {
                if (! storageDir.exists()){
                    Log.d("CameraSample", "failed to create directory");
                    return null;
                }
            }
        }

    } else {
        Log.v(getString(R.string.app_name), "External storage is not mounted READ/WRITE.");
    }

    return storageDir;
}

private File createImageFile() throws IOException {
    // Create an image file name

    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
    String imageFileName = JPEG_FILE_PREFIX + timeStamp + "_";
    File albumF = getAlbumDir();
    File imageF = File.createTempFile(imageFileName, JPEG_FILE_SUFFIX, albumF);

    return imageF;
}

private File setUpPhotoFile() throws IOException {

    File f = createImageFile();
    mCurrentPhotoPath = f.getAbsolutePath();

    return f;
}

private void setPic() {

    /* There isn't enough memory to open up more than a couple camera photos */
    /* So pre-scale the target bitmap into which the file is decoded */

    /* Get the size of the ImageView */
    int targetW = mImageView.getWidth();
    int targetH = mImageView.getHeight();

    /* Get the size of the image */
    BitmapFactory.Options bmOptions = new BitmapFactory.Options();
    bmOptions.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions);
    int photoW = bmOptions.outWidth;
    int photoH = bmOptions.outHeight;

    /* Figure out which way needs to be reduced less */
    int scaleFactor = 1;
    if ((targetW > 0) || (targetH > 0)) {
        scaleFactor = Math.min(photoW/targetW, photoH/targetH); 
    }

    /* Set bitmap options to scale the image decode target */
    bmOptions.inJustDecodeBounds = false;
    bmOptions.inSampleSize = scaleFactor;
    bmOptions.inPurgeable = true;

 /* NEWELY ADDED CODE */
    /* Decode the JPEG file into a Bitmap */
    Bitmap bitmap = BitmapFactory.decodeFile(mCurrentPhotoPath, bmOptions); 
    Bitmap replacedBitmap = timestampItAndSave(bitmap); 

    /* Associate the Bitmap to the ImageView */
    mImageView.setImageBitmap(replacedBitmap); 
    mImageView.setVisibility(View.VISIBLE);
 /* NEWELY ADDED CODE */
}

private void galleryAddPic() {
        Intent mediaScanIntent = new Intent("android.intent.action.MEDIA_SCANNER_SCAN_FILE");
        File f = new File(mCurrentPhotoPath);
        Uri contentUri = Uri.fromFile(f);
        mediaScanIntent.setData(contentUri);
        this.sendBroadcast(mediaScanIntent);
}

private void dispatchTakePictureIntent(int actionCode) {

    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

    switch(actionCode) {
    case ACTION_TAKE_PHOTO_B:
        File f = null;

        try {
            f = setUpPhotoFile();
            mCurrentPhotoPath = f.getAbsolutePath();
            takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(f));
        } catch (IOException e) {
            e.printStackTrace();
            f = null;
            mCurrentPhotoPath = null;
        }
        break;

    default:
        break;          
    } // switch

    startActivityForResult(takePictureIntent, actionCode);
}

private void handleBigCameraPhoto() {

    if (mCurrentPhotoPath != null) {
        setPic();
        galleryAddPic();
        mCurrentPhotoPath = null;
    }

}


Button.OnClickListener mTakePicOnClickListener = 
    new Button.OnClickListener() {
    public void onClick(View v) {
        dispatchTakePictureIntent(ACTION_TAKE_PHOTO_B);
    }
};


/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    mImageView = (ImageView) findViewById(R.id.imageView1);
    mImageBitmap = null;

    Button picBtn = (Button) findViewById(R.id.btnIntend);
    setBtnListenerOrDisable( 
            picBtn, 
            mTakePicOnClickListener,
            MediaStore.ACTION_IMAGE_CAPTURE
    );

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) {
        mAlbumStorageDirFactory = new FroyoAlbumDirFactory();
    } else {
        mAlbumStorageDirFactory = new BaseAlbumDirFactory();
    }
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch (requestCode) {
    case ACTION_TAKE_PHOTO_B: {
        if (resultCode == RESULT_OK) {
            handleBigCameraPhoto();
        }
        break;
    } // ACTION_TAKE_PHOTO_B
  }
}

// Some lifecycle callbacks so that the image can survive orientation change
@Override
protected void onSaveInstanceState(Bundle outState) {
    outState.putParcelable(BITMAP_STORAGE_KEY, mImageBitmap);
    outState.putBoolean(IMAGEVIEW_VISIBILITY_STORAGE_KEY, (mImageBitmap != null) );
    super.onSaveInstanceState(outState);
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
    mImageBitmap = savedInstanceState.getParcelable(BITMAP_STORAGE_KEY);
    mImageView.setImageBitmap(mImageBitmap);
    mImageView.setVisibility(
            savedInstanceState.getBoolean(IMAGEVIEW_VISIBILITY_STORAGE_KEY) ? 
                    ImageView.VISIBLE : ImageView.INVISIBLE
    );

}

/**
 * Indicates whether the specified action can be used as an intent. This
 * method queries the package manager for installed packages that can
 * respond to an intent with the specified action. If no suitable package is
 * found, this method returns false.
 * http://android-developers.blogspot.com/2009/01/can-i-use-this-intent.html
 *
 * @param context The application's environment.
 * @param action The Intent action to check for availability.
 *
 * @return True if an Intent with the specified action can be sent and
 *         responded to, false otherwise.
 */
public static boolean isIntentAvailable(Context context, String action) {
    final PackageManager packageManager = context.getPackageManager();
    final Intent intent = new Intent(action);
    List<ResolveInfo> list =
        packageManager.queryIntentActivities(intent,
                PackageManager.MATCH_DEFAULT_ONLY);
    return list.size() > 0;
}

private void setBtnListenerOrDisable( 
        Button btn, 
        Button.OnClickListener onClickListener,
        String intentName
) {
    if (isIntentAvailable(this, intentName)) {
        btn.setOnClickListener(onClickListener);            
    } else {
        btn.setText( 
            getText(R.string.cannot).toString() + " " + btn.getText());
        btn.setClickable(false);
    }
}

  }

在 4.0 模拟器上出现错误。登录目录。

 07-12 20:53:50.510: D/gralloc_goldfish(545): Emulator without GPU emulation detected.
 07-12 20:53:54.861: W/IInputConnectionWrapper(545): showStatusIcon on inactive      InputConnection
 07-12 20:54:00.700: D/dalvikvm(545): GC_FOR_ALLOC freed 114K, 3% free 10052K/10311K,      paused 217ms
 07-12 20:54:00.710: I/dalvikvm-heap(545): Grow heap (frag case) to 11.072MB for           1228816-byte allocation
 07-12 20:54:00.860: D/dalvikvm(545): GC_CONCURRENT freed 3K, 3% free 11249K/11527K,      paused 4ms+3ms
 07-12 20:54:00.960: D/AndroidRuntime(545): Shutting down VM
 07-12 20:54:00.960: W/dalvikvm(545): threadid=1: thread exiting with uncaught      exception (group=0x409961f8)
 07-12 20:54:01.000: E/AndroidRuntime(545): FATAL EXCEPTION: main
 07-12 20:54:01.000: E/AndroidRuntime(545): java.lang.RuntimeException: Failure      delivering result ResultInfo{who=null, request=1, result=-1, data=null} to activity      {com.example.android.photobyintent/com.example.android.photobyintent.PhotoIntentActivity}:      java.lang.IllegalStateException: Immutable bitmap passed to Canvas constructor
 07-12 20:54:01.000: E/AndroidRuntime(545):     at      android.app.ActivityThread.deliverResults(ActivityThread.java:2976)
 07-12 20:54:01.000: E/AndroidRuntime(545):     at      android.app.ActivityThread.handleSendResult(ActivityThread.java:3019)
 07-12 20:54:01.000: E/AndroidRuntime(545):     at      android.app.ActivityThread.access$1100(ActivityThread.java:122)
 07-12 20:54:01.000: E/AndroidRuntime(545):     at      android.app.ActivityThread$H.handleMessage(ActivityThread.java:1176)
 07-12 20:54:01.000: E/AndroidRuntime(545):     at android.os.Handler.dispatchMessage(Handler.java:99)
 07-12 20:54:01.000: E/AndroidRuntime(545):     at android.os.Looper.loop(Looper.java:137)
 07-12 20:54:01.000: E/AndroidRuntime(545):     at android.app.ActivityThread.main(ActivityThread.java:4340)
 07-12 20:54:01.000: E/AndroidRuntime(545):     at java.lang.reflect.Method.invokeNative(Native Method)
 07-12 20:54:01.000: E/AndroidRuntime(545):     at java.lang.reflect.Method.invoke(Method.java:511)
 07-12 20:54:01.000: E/AndroidRuntime(545):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
 07-12 20:54:01.000: E/AndroidRuntime(545):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
 07-12 20:54:01.000: E/AndroidRuntime(545):     at dalvik.system.NativeStart.main(Native Method)
 07-12 20:54:01.000: E/AndroidRuntime(545): Caused by: java.lang.IllegalStateException: Immutable bitmap passed to Canvas constructor
 07-12 20:54:01.000: E/AndroidRuntime(545):     at android.graphics.Canvas.<init>  (Canvas.java:133)
 07-12 20:54:01.000: E/AndroidRuntime(545):     at com.example.android.photobyintent.PhotoIntentActivity.timestampItAndSave(PhotoIntentActivity.java:103)
 07-12 20:54:01.000: E/AndroidRuntime(545):     at com.example.android.photobyinten

t.PhotoIntentActivity.setPic(PhotoIntentActivity.java:154) 07-12 20:54:01.000:E/AndroidRuntime(545):在 com.example.android.photobyintent.PhotoIntentActivity.handleBigCameraPhoto(PhotoIntentActivity.java:199) 07-12 20:54:01.000:E/AndroidRuntime(545):在 com.example.android.photobyintent.PhotoIntentActivity.onActivityResult(PhotoIntentActivity.java:244) 07-12 20:54:01.000: E/AndroidRuntime(545): 在 android.app.Activity.dispatchActivityResult(Activity.java:4649) 07-12 20:54:01.000:E/AndroidRuntime(545):在 android.app.ActivityThread.deliverResults(ActivityThread.java:2972) 07-12 20:54:01.000: E/AndroidRuntime(545): ... 11 更多

更新了绘制位图的代码。

  private Bitmap timestampItAndSave(Bitmap toEdit){
    Bitmap dest = Bitmap.createBitmap(toEdit.getWidth(), toEdit.getHeight(), Bitmap.Config.ARGB_8888);

       SimpleDateFormat sdf = new     SimpleDateFormat("YYYY-MM-DD HH:MM:SS");
      String dateTime = sdf.format(Calendar.getInstance().getTime()); // reading local time in the system

    Canvas cs = new Canvas(dest);
    Paint tPaint = new Paint();
    tPaint.setTextSize(35);
    tPaint.setColor(Color.BLUE);
    tPaint.setStyle(Style.FILL);
    float height = tPaint.measureText("yY");
    cs.drawText(dateTime, 20f, height+15f, tPaint);
    cs.drawBitmap(dest,0 ,0,tPaint);
   try {
        dest.compress(Bitmap.CompressFormat.JPEG, 100, new FileOutputStream(new File(Environment.getExternalStorageDirectory() + "/timestamped")));

    } catch (FileNotFoundException e) {
    e.printStackTrace();
    return null;
  }
    return dest;
}

最佳答案

您不想将它放在 onDraw 方法中,因为每当 View 无效(您不想要)时都会调用它。

只需创建一个方法并将代码放入其中。获取图像后调用它,如下所示:

private Bitmap timestampItAndSave(Bitmap toEdit){
    Bitmap dest = Bitmap.createBitmap(toEdit.getWidth(), toEdit.getHeight(), Bitmap.Config.ARGB_8888);

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    String dateTime = sdf.format(Calendar.getInstance().getTime()); // reading local time in the system

    Canvas cs = new Canvas(dest);
    Paint tPaint = new Paint();
    tPaint.setTextSize(35);
    tPaint.setColor(Color.BLUE);
    tPaint.setStyle(Style.FILL);
    float height = tPaint.measureText("yY");
    cs.drawText(dateTime, 20f, height+15f, tPaint);
    try {
        dest.compress(Bitmap.CompressFormat.JPEG, 100, new FileOutputStream(new File(Environment.getExternalStorageDirectory() + "/timestamped")));
    } catch (FileNotFoundException e) {
    e.printStackTrace();
    return null;
  }
    return dest;
}

我还建议不要将它保存到“/sdcard/”,而是使用 Environment.getExternalStorageDirectory()(已经为您实现)

编辑:还注意到您正在从 myImageBitmap 中创建第二个位图;有必要吗?

关于java - 在从独立相机捕获的图像上绘制文本(时间戳),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11436201/

相关文章:

java - 最简单的 JSF 2.0 应用程序将无法运行

java - 对于子查询器 - 什么是好的? HQL 或标准 -DetachedCriteria

android - OpenGLRenderer 试图缩小位图 - 当到达 ViewPager 的末尾时

android - IN 子句和占位符

c - 恼人的 strcat() 输出

python - 提取不同表中2列之间的常用词python

java - 一个 Web 应用程序中设置的系统属性是否会与同一服务器中的另一个应用程序相矛盾?

java - 如何在 Selenium 中映射 XPath?

android opengl 纹理重叠

javascript - 如何从 FullCalendar 上的自定义按钮动态更改文本?