【问题标题】:Android bitmap compression is not goodAndroid位图压缩不好
【发布时间】:2013-06-12 16:02:50
【问题描述】:

我得到以下输出流代码:

        String output_file = APP_FILE_PATH + "/AudienceSignatures/" + CaptureSignature.this.sessionNumber + ".png";

        final FileOutputStream out = new FileOutputStream(new File( output_file ));
        nBitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
        out.flush();
        out.close();

但看起来结果图像不是我所期望的。如您所见,它有一些线条,我想摆脱那些水平的白线。这可能是什么原因?

非常感谢您提供的任何帮助! :)

更新:这是 CaptureSignature.java 类,“我认为”我遇到了问题:

package com.first.MyApp.drawings;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;

import com.first.Engagia.Camera;
import com.first.Engagia.R;
import com.first.Engagia.R.id;
import com.first.Engagia.R.layout;
import com.first.Engagia.drawings.brush.Brush;
import com.first.Engagia.drawings.brush.CircleBrush;
import com.first.Engagia.drawings.brush.PenBrush;

import java.io.File;
import java.io.FileOutputStream;

public class CaptureSignature extends Activity implements View.OnTouchListener{
    private DrawingSurface drawingSurface;
    private DrawingPath currentDrawingPath;
    private Paint currentPaint;

    private Brush currentBrush;

    private File APP_FILE_PATH = new File(Environment.getExternalStorageDirectory() + "/Engagia/AudienceSignatures");

    //..some other instance variables here

    public static final String LOG_TAG = "-------->>>> CAPTURE SIGNATURE <<<<-------";
    private ProgressDialog mProgressDialog;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.drawing_activity);

        Log.d(LOG_TAG, "Inside capture signature");

        PopIt("Camera", "Please sign on the whitespace provided.");

        Bundle extras = getIntent().getExtras(); 

        if(extras != null){
            this.userId = extras.getString("userId");
            this.appview_username = extras.getString("username");
            this.appview_password = extras.getString("password");

            this.userfirstname = extras.getString("userfirstname");
            this.userlastname = extras.getString("userlastname");
            this.companyname = extras.getString("companyname");

            this.sessionNumber = extras.getString("sessionNumber");
            this.sessionFirstname = extras.getString("sessionFirstname");
            this.sessionLastname = extras.getString("sessionLastname");

            this.AudienceFirstnameLastname = extras.getString("AudienceFirstnameLastname");

        }

        setCurrentPaint();
        currentBrush = new PenBrush();

        drawingSurface = (DrawingSurface) findViewById(R.id.drawingSurface);
        drawingSurface.setOnTouchListener(this);
        drawingSurface.previewPath = new DrawingPath();
        drawingSurface.previewPath.path = new Path();
        drawingSurface.previewPath.paint = getPreviewPaint();


    }

    public void PopIt(String title, String message){
        android.content.DialogInterface.OnClickListener arg1 = null;
        new AlertDialog.Builder(this)
        .setTitle( title )
        .setMessage( message )
        .setPositiveButton("OK", arg1).show();
    }


    private void setCurrentPaint(){
        currentPaint = new Paint();
        currentPaint.setDither(true);
        currentPaint.setColor(0xff000000);
        currentPaint.setStyle(Paint.Style.STROKE);
        currentPaint.setStrokeJoin(Paint.Join.ROUND);
        currentPaint.setStrokeCap(Paint.Cap.ROUND);
        currentPaint.setStrokeWidth(8);

    }

    private Paint getPreviewPaint(){
        final Paint previewPaint = new Paint();
        previewPaint.setColor(0xff000000);
        previewPaint.setStyle(Paint.Style.STROKE);
        previewPaint.setStrokeJoin(Paint.Join.ROUND);
        previewPaint.setStrokeCap(Paint.Cap.ROUND);
        previewPaint.setStrokeWidth(8);
        return previewPaint;
    }




    public boolean onTouch(View view, MotionEvent motionEvent) {
        if(motionEvent.getAction() == MotionEvent.ACTION_DOWN){
            drawingSurface.isDrawing = true;

            currentDrawingPath = new DrawingPath();
            currentDrawingPath.paint = currentPaint;
            currentDrawingPath.path = new Path();
            currentBrush.mouseDown(currentDrawingPath.path, motionEvent.getX(), motionEvent.getY());
            currentBrush.mouseDown(drawingSurface.previewPath.path, motionEvent.getX(), motionEvent.getY());


        }else if(motionEvent.getAction() == MotionEvent.ACTION_MOVE){
            drawingSurface.isDrawing = true;
            currentBrush.mouseMove( currentDrawingPath.path, motionEvent.getX(), motionEvent.getY() );
            currentBrush.mouseMove(drawingSurface.previewPath.path, motionEvent.getX(), motionEvent.getY());


        }else if(motionEvent.getAction() == MotionEvent.ACTION_UP){


            currentBrush.mouseUp(drawingSurface.previewPath.path, motionEvent.getX(), motionEvent.getY());
            drawingSurface.previewPath.path = new Path();
            drawingSurface.addDrawingPath(currentDrawingPath);

            currentBrush.mouseUp( currentDrawingPath.path, motionEvent.getX(), motionEvent.getY() );

        }

        return true;
    }


    public void onClick(View view){
        switch (view.getId()){
            case R.id.saveBtn:
                Log.d(LOG_TAG, "Save Button clicked!");


                showDialog(0);
                CaptureSignature.this.mProgressDialog.setMessage("Saving your signature...");

                final Activity currentActivity  = this;
                Handler saveHandler = new Handler(){
                    @Override
                    public void handleMessage(Message msg) {
                        final AlertDialog alertDialog = new AlertDialog.Builder(currentActivity).create();
                        alertDialog.setTitle("Done");
                        alertDialog.setMessage("Your signature has been captured.");
                        alertDialog.setButton("OK", new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int which) {

                                Log.d(LOG_TAG, "Going to camera activity");

                                //...intent to next activity after signature was taken

                                return;
                            }
                        });

                        if( CaptureSignature.this.mProgressDialog.isShowing() ){
                            dismissDialog(0);
                        }

                        alertDialog.show();
                    }
                } ;
               new ExportBitmapToFile(this,saveHandler, drawingSurface.getBitmap()).execute();
            break;
            case R.id.resetBtn:
                Log.d(LOG_TAG, "Reset Button clicked!");

                //..reset intent here

                break;

        }
    }


    private class ExportBitmapToFile extends AsyncTask<Intent,Void,Boolean> {
        private Context mContext;
        private Handler mHandler;
        private Bitmap nBitmap;

        public ExportBitmapToFile(Context context,Handler handler,Bitmap bitmap) {
            mContext = context;
            nBitmap = bitmap;
            mHandler = handler;
        }

        @Override
        protected Boolean doInBackground(Intent... arg0) {
            try {
                if (!APP_FILE_PATH.exists()) {
                    APP_FILE_PATH.mkdirs();
                }
                Log.d(LOG_TAG, "Sig.output stream area.");

                final FileOutputStream out = new FileOutputStream(new File(APP_FILE_PATH + "/" +  CaptureSignature.this.sessionNumber + ".png"));
                nBitmap.setDensity(50);
                nBitmap.compress(Bitmap.CompressFormat.PNG, 50, out);

                out.flush();
                out.close();

                Log.d(LOG_TAG, "Done bitmap compress.");
                return true;
            }catch (Exception e) {
                e.printStackTrace();
            }

            return false;
        }


        @Override
        protected void onPostExecute(Boolean bool) {
            super.onPostExecute(bool);
            if ( bool ){
                mHandler.sendEmptyMessage(1);
            }
        }
    }

    @Override
    public void onBackPressed() {

    }

    @Override
    protected Dialog onCreateDialog(int id) {
        switch (id) {
            case 0:
                mProgressDialog = new ProgressDialog(this);
                mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
                mProgressDialog.show();
                return mProgressDialog;
            default:
                return null;
        }
    }
}

基本上,我正在尝试捕获用户的签名并将其保存到我的 android 设备 sdcard 中的 png 文件中。

【问题讨论】:

    标签: android bitmap compression


    【解决方案1】:

    我从未见过我们的 PNG 压缩存在这样的问题。不会是原始位图吗?

    【讨论】:

    • 非常感谢您的回复,原始位图是什么意思?我更新了我的问题,也许这会对我们有所帮助。
    • 为什么要使用 nBitmap.setDensity(50)?
    • 我只是在尝试是否有帮助。但即使我没有设置密度,我仍然得到相同的结果。
    【解决方案2】:

    签名时,原始位图可能因屏幕脏或油腻而出现线条。当它出现故障时,我还看到一个带有这样线条的屏幕。

    【讨论】:

      【解决方案3】:

      onTouch 方法内部发生了很多事情(比如内存分配——使用新的)。这似乎是您问题的根本原因。当用户触摸屏幕时,onTouch 每秒被调用多次。如果此方法没有及时返回,则不会发生对 onTouch 的下一次调用。这可能就是为什么您的结果图像中缺少一些“笔画”的原因。清理代码并查看结果。如果这没有帮助,或者甚至没有帮助,您可以使用我的代码:

      public boolean onTouchEvent(MotionEvent event){
          final int source = event.getSource();
          if(source!=InputDevice.SOURCE_TOUCHSCREEN &&
                  source!=InputDevice.SOURCE_MOUSE &&
                  source!=InputDevice.SOURCE_TOUCHPAD){
              Log.v(TAG, "returns false");
      
              return false;
          }
      
          switch(event.getActionMasked()){
          case MotionEvent.ACTION_DOWN:
              path.reset();
              path.moveTo(event.getX(), event.getY());
              break;
          case MotionEvent.ACTION_MOVE:
              path.lineTo(event.getX(), event.getY());
              break;
          case MotionEvent.ACTION_UP:
              path.lineTo(event.getX(), event.getY());
              charDrawn();
          }
          invalidate();//omit this. I need it since it calls the onDraw() method
          Log.v(TAG, "returns true");
          return true;
      }
      

      我通过扩展View 类创建了自己的“视图”。我只是在用户移动手指时提取路径。因为我使用 path.lineTo 我的路径永远不会被打破。我得到一条细线。一旦绘制了路径,我就可以用它做任何我想做的事情(在charDrwan() 方法中)。我通过创建Canvas 并使用其canvas.drawPath(Path,Paint) 方法来创建位图。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-04-23
        • 2014-01-03
        • 2013-11-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-15
        相关资源
        最近更新 更多