2017-07-10 5 views
1

描かれた円でキャンバス、ビットマップを保存し、上に表示されますスクリーン。ユーザーが画面にタッチすると、円が描かれます。は</p> <p>に成功したビットマップがロードされます。私は、ビューを拡張し、中にロードされたビットマップ上cirlesを描画するためにオーバーライドonDrawメソッドを持ってその下に以下のクラスを持っている

ビットマップをバイト[]に圧縮する浮動アクションボタンがあります。このバイト[]は、表示される別のアクティビティに送信されます。残念なことに、結果のビットマップには円がありません。

キャンバスはonDraw内のローカルオブジェクトであり、mCBitmapとtCanvasはグローバル変数であるため、メソッドsaveImageはデータにアクセスできます。

結果のビットマップに何も円がコピーされない理由は誰にでも分かりますか?以下、次へ

import android.content.Context; 
import android.content.res.AssetManager; 
import android.content.res.Resources; 
import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
import android.graphics.Canvas; 
import android.graphics.Color; 
import android.graphics.Paint; 
import android.graphics.Rect; 
import android.graphics.RectF; 
import android.os.Environment; 
import android.util.AttributeSet; 
import android.util.DisplayMetrics; 
import android.util.Log; 
import android.util.SparseArray; 
import android.util.TypedValue; 
import android.view.MotionEvent; 
import android.view.View; 
import android.widget.Toast; 

import org.apache.commons.io.IOUtils; 

import java.io.BufferedInputStream; 
import java.io.ByteArrayOutputStream; 
import java.io.DataInputStream; 
import java.io.File; 
import java.io.FileInputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 
import android.graphics.PointF; 

/** 
* Created by MatthewW on 14/06/2017. 
*/ 

public class TouchView extends View { 

    private static final String TAG = TouchView.class.getSimpleName(); 
    Bitmap bgr; 
    File tempFile; 
    private byte[] imageArray; 
    private Paint pTouch; 

    Context context; 

    private SparseArray<ColouredCircle> mPointers; 
    public int x; 
    public int y; 


    int circleCount; 
    int radius; 
    protected byte [] data; 

    Bitmap mCBitmap; 
    Canvas tCanvas; 




    public TouchView(Context context) { 
     super(context); 

     this.context = context; 

    } 



    public TouchView(Context context, AttributeSet attr) { 
     super(context,attr); 
     Log.e(TAG, "inside touchview constructor"); 

     this.context = context; 

     radius = 70; 
     circleCount = 0; 



     copyReadAssets(); 

     imageArray = new byte[(int)tempFile.length()]; 


     Log.e(TAG, "imageArray has length = " + imageArray.length); 



     try{ 

      InputStream is = new FileInputStream(tempFile); 
      BufferedInputStream bis = new BufferedInputStream(is); 
      DataInputStream dis = new DataInputStream(bis); 


      int i = 0; 

      while (dis.available() > 0) { 
       imageArray[i] = dis.readByte(); 
       i++; 
      } 

      dis.close(); 


     } catch (Exception e) { 

      e.printStackTrace(); 
     } 



     Bitmap bm = BitmapFactory.decodeByteArray(imageArray, 0, imageArray.length); 

     if(bm == null){ 
      Log.e(TAG, "bm = null"); 
     }else{ 
      Log.e(TAG, "bm = not null"); 
     } 



     mPointers = new SparseArray<ColouredCircle>(); 


     bgr = bm.copy(bm.getConfig(), true); 





     bm.recycle(); 

     pTouch = new Paint(Paint.ANTI_ALIAS_FLAG); 
     // pTouch.setXfermode(new PorterDuffXfermode(Mode.SRC_OUT)); 
     pTouch.setColor(Color.RED); 
     pTouch.setStyle(Paint.Style.STROKE); 

     pTouch.setStrokeWidth(5); 




    }// end of touchView constructor 




    private void copyReadAssets() { 

     AssetManager assetManager = context.getAssets(); 

     InputStream in = null; 
     OutputStream out = null; 
     tempFile = new File(context.getFilesDir(), "bodymap.jfif"); 
     try { 
      in = assetManager.open("bodymap.jfif"); 
      out = context.openFileOutput(tempFile.getName(), Context.MODE_WORLD_READABLE); 

      IOUtils.copy(in, out); 

      in.close(); 
      in = null; 
      out.flush(); 
      out.close(); 
      out = null; 
     } catch (Exception e) { 
      Log.e(TAG, e.getMessage()); 
     } 


    } 


    @Override 
    public void onDraw(Canvas canvas){ 
     super.onDraw(canvas); 



     Log.e(TAG, "about to draw bgr "); 
     // canvas.drawBitmap(bgr, 0, 0, null); 

     DisplayMetrics metrics = context.getResources().getDisplayMetrics(); 
     int width = metrics.widthPixels; 
     int height = metrics.heightPixels; 



     Rect frameToDraw = new Rect(0, 0, width, height); 
     RectF whereToDraw = new RectF(0, 0, width, height - 300); 

     canvas.drawBitmap(bgr,frameToDraw,whereToDraw, null); 




     if(mPointers != null) { 

      Log.e(TAG, "mPointers.size() = " + mPointers.size()); 

      for (int i = 0; i < mPointers.size(); i++) { 

       PointF p = mPointers.get(i).getPointF(); 
       x = (int) p.x; 
       y = (int) p.y; 

       pTouch.setColor(mPointers.get(i).getColour()); 


       canvas.drawCircle(x, y, radius, pTouch); 




       mCBitmap = Bitmap.createBitmap(bgr.getWidth(), bgr.getHeight(), bgr.getConfig()); 

       tCanvas = new Canvas(mCBitmap); 

       tCanvas.drawBitmap(bgr, 0, 0, null); 

       tCanvas.drawCircle(x, y, radius, pTouch); 

       tCanvas.drawBitmap(mCBitmap, 0, 0, null); 






      } 

     } 






    }//end of onDraw 





    @Override 
    public boolean onTouchEvent(MotionEvent me) { 
     switch (me.getActionMasked()) { 
      case MotionEvent.ACTION_DOWN: 

      case MotionEvent.ACTION_POINTER_DOWN: { 
       /*int ai = me.getActionIndex(); 
       PointF pt = new PointF(me.getX(ai), me.getY(ai)); 
       mPointers.put(me.getPointerId(ai), pt); 

       Log.e(TAG, "mPointers.size() = " + mPointers.size() + "me.getPointerId(ai) = " 
           + me.getPointerId(ai) + " me.getX(ai) = " + me.getX(ai) + " me.getY(ai) = " + me.getY(ai));*/ 

       int ai = me.getActionIndex(); 
       PointF pt = new PointF(me.getX(ai), me.getY(ai)); 

       ColouredCircle cc = new ColouredCircle(pTouch.getColor(),pt); 

       mPointers.put(circleCount, cc); 

       circleCount++; 

       invalidate(); 
       return true; 
      } 

      case MotionEvent.ACTION_UP: { 

      } 

      case MotionEvent.ACTION_POINTER_UP: { 
       /*int pid = me.getPointerId(me.getActionIndex()); 
       mPointers.remove(pid);*/ 
       return true; 
      } 

      case MotionEvent.ACTION_MOVE: { 
       /*for (int i = 0; i < me.getPointerCount(); ++i) { 
        PointF pt = mPointers.get(me.getPointerId(i)); 
        pt.set(me.getX(i), me.getY(i)); 
        invalidate(); 
       }*/ 
       return true; 
      } 
     } 
     return false; 
    } 



    public void showToastMessage(String mess){ 

     Toast.makeText(TouchView.this.getContext(), mess.toString(), Toast.LENGTH_SHORT).show(); 

    } 

    public int getRadius() { 
     return radius; 
    } 




    public void setRadius(int r) { 
     radius = r; 
     invalidate(); 
    } 


    public void setCircleColour(String colourMode){ 


     if(colourMode.equalsIgnoreCase("RED")){ 

      pTouch.setColor(Color.RED); 

     }else if(colourMode.equalsIgnoreCase("BLUE")){ 

      pTouch.setColor(Color.BLUE); 

     }else if(colourMode.equalsIgnoreCase("GREY")){ 

      pTouch.setColor(Color.GRAY); 

     } 

    } 



    public byte[] saveImage(){ 



     ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
     mCBitmap.compress(Bitmap.CompressFormat.JPEG, 100 /*ignored for PNG*/, bos); 
     data = bos.toByteArray(); 
     try { 
      bos.flush(); 
      bos.close(); 
     } catch (IOException e1) { 
      // TODO Auto-generated catch block 
      e1.printStackTrace(); 
     } 

     try { 
      bos.flush(); 
      bos.close(); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 

     if (data == null){ 
      Log.e(TAG, "data in touchview before save clicked is null"); 
     }else{ 
      Log.e(TAG, "data in touchview before saved clicked is not null and has length + " + data.length); 
     } 

     return data; 

    } 

}//end of class 

[EDIT1]

は私が変更されている私のonDraw()とsaveImage()メソッド。これで、イメージがサークルと一緒に保存されます。

しかし、bgrイメージは非常に小さく、画面の左上にあります(画面の残りは黒です)。円は元の位置に正確な位置にあり、フルサイズではないbg画像です。

どのようにして、結果のビットマップにフルサイズのbgイメージをコピーできますか?

@Override 
    public void onDraw(Canvas canvas){ 
     super.onDraw(canvas); 



     Log.e(TAG, "about to draw bgr "); 
     // canvas.drawBitmap(bgr, 0, 0, null); 

     DisplayMetrics metrics = context.getResources().getDisplayMetrics(); 
     int width = metrics.widthPixels; 
     int height = metrics.heightPixels; 



     Rect frameToDraw = new Rect(0, 0, width, height); 
     RectF whereToDraw = new RectF(0, 0, width, height - 300); 

     canvas.drawBitmap(bgr,frameToDraw,whereToDraw, null); 




     if(mPointers != null) { 

      Log.e(TAG, "mPointers.size() = " + mPointers.size()); 

      for (int i = 0; i < mPointers.size(); i++) { 

       PointF p = mPointers.get(i).getPointF(); 
       x = (int) p.x; 
       y = (int) p.y; 

       pTouch.setColor(mPointers.get(i).getColour()); 


       canvas.drawCircle(x, y, radius, pTouch); 





      } 

     } 






    }//end of onDraw 

public byte[] saveImage(){ 

     DisplayMetrics metrics = context.getResources().getDisplayMetrics(); 
     int width = metrics.widthPixels; 
     int height = metrics.heightPixels - 300; 

     Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 
     //Bitmap bitmap = Bitmap.createBitmap(bgr.getWidth(), bgr.getHeight(), bgr.getConfig()); 

     Canvas canvas = new Canvas(bitmap); 
     this.draw(canvas); 

     ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
     bitmap.compress(Bitmap.CompressFormat.JPEG, 100 /*ignored for PNG*/, bos); 
     data = bos.toByteArray(); 
     try { 
      bos.flush(); 
      bos.close(); 
     } catch (IOException e1) { 
      // TODO Auto-generated catch block 
      e1.printStackTrace(); 
     } 

     try { 
      bos.flush(); 
      bos.close(); 
     } catch (IOException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 

     if (data == null){ 
      Log.e(TAG, "data in touchview before save clicked is null"); 
     }else{ 
      Log.e(TAG, "data in touchview before saved clicked is not null and has length + " + data.length); 
     } 

     return data; 

    } 

ここでは、ユーザーが画像に円を配置できるようにするアクティビティの図を示します。 bgイメージはフルスクリーンです。以下

enter image description here

丸付き画像は[]バイトになって表示される次のアクティビティにおける出力のPICです。あなたが見ることができるように、bg画像はフルスクリーンではありませんが、cirlesは正しい位置にあります。 onDraw(...)

enter image description here

答えて

2

、変更:

Rect frameToDraw = new Rect(0, 0, width, height); 

へ:あなたはonDraw(...)で画像を表示しているこの問題を持っていない

Rect frameToDraw = new Rect(0, 0, bgr.getWidth(), bgr.getHeight()); 

一つの理由は、onDraw(...)フレームワークによって呼び出される場合、フレームワークによって提供されるCanvasオブジェクトがハードウェアアクセhere見られるように、あなたがターゲットSDK> = 14(source、第二段落、最初の文)

を持っている場合、デフォルトでlerated、キャンバスがハードウェアアクセラレーションされたとき、あなたならば、その密度は、しかし0に設定されているようですフィールドTouchView#bgrBitmap.getDensity()と電話すると、0にならないことがわかります。これは、作成時のビットマップが現在のデバイスの画面の濃度を持つためです。

次に、0 ppiキャンバスに高密度ビットマップを描画しました(私のデバイス上では、密度は320 ppiです)、より大きく見えるように描画されます。

しかし、saveImageに、あなたは、あなたはそのビットマップからCanvasを作成し、あなたがdraw(...)を呼び出すために、このキャンバスを供給し、ゼロからBitmapを作成します。作成したばかりのこの新しいキャンバスはハードウェアアクセラレーションされず、新しく作成されたビットマップ(私の場合は320ppi)の密度も持ちます。

身体地図の画像をonDraw(...)に描画すると、画像と同じ320dpでこのキャンバスに描画されます。

bodywidth x screenHeight(1920x1080と仮定します)の領域を描画することを指定しますが、身体マップから体型マップを作成することを指定します。これは、おそらく小さく、1000x600と仮定してframeToDrawとします。

この場合、Androidは何をしますか?

注:塗料が は、ビットマップの元の幅/高さ(例えば BlurMaskFilter)を超えて拡張したマスクを生成maskfilterが含まれている場合、ビットマップはなりますまあ、Canvas#drawBitmap(...)のJavadocは、以下を教えてくれるまるでそれがCLAMPモードの シェーダにあるかのように描画されます。したがって、オリジナルの外側の色は、 の幅/高さが複製されたエッジカラーになります。

基本的には:私はあなたの1000x600を取って、描画する必要があるのでピクセルを描画し、1920x1080まではピクセルの残りの部分を選択します(おそらく黒または白または透明?)

ここでは、whereToDrawによって、1920x1080領域を1620x1080領域にマッピングするとします。これを行うために、アンドロイドはさらにビットマップを縮小し、bodymapをさらに小さくします。

frameToDraw領域を作成するときに、onDraw(...)にビットマップの実際のサイズを指定するのが最も簡単な解決方法です。

また、これらのコードフラグメントがテストコードである場合は、onDraw(...)を使用してコードをクリーンアップする場合は、hereのガイドラインに従ってください。

最も重要なポイントは、次のようになります。

  • 、彼らは非常に頻繁に呼び出される可能性があるので、あなたは本当に、あなたのonDraw(...)方法でオブジェクトを割り当てるべきではない、とこれはあなたのガベージコレクタを殺すでしょう。 (つまり、frameToDraw & whereToDraw - これらをコンストラクタで事前に割り当てることができます)

  • ビューの描画キャッシュを利用すると、より簡単に画面のビットマップを取得できます。

ちょうどあなたのsaveImageに変更します。

public byte[] saveImage() { 
    //reder the view once, in software. 
    buildDrawingCache(); 
    //get the rendered bitmap 
    Bitmap bitmap = getDrawingCache(); 

    ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
    bitmap.compress(Bitmap.CompressFormat.JPEG, 100 /*ignored for PNG*/, bos); 
    byte[] data = bos.toByteArray(); 
    //destroy the drawing cache, to clear up the memory 
    destroyDrawingCache(); 

    try { 
     bos.flush(); 
     bos.close(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 

    if (data == null) { 
     Log.e(TAG, "data in touchview before save clicked is null"); 
    } else { 
     Log.e(TAG, "data in touchview before saved clicked is not null and has length + " + data.length); 
    } 

    return data; 
} 

参照:

希望の方は

+0

こんにちは、このような詳細な回答ありがとうございます。私はアンドロイドのグラフィックについてもっと読む必要があると思う。今はうまくいく!また、これらの変更を行って、オブジェクトをコンストラクタ内に配置します。再度、感謝します! – turtleboy

関連する問題