如何在覆盖其他图像后合并/保存图像?

时间:2015-04-14 10:01:15

标签: android android-layout image-processing

我正在实施一个有两个图像的应用程序。第一个图像是静态的,或者说是“drop-target”,用于android“Drag& Drop”概念,第二个图像是“draggable”。拖动可拖动的图像并将其放在另一图像上。直到这一点,应用程序工作正常,但我仍然坚持如何保存这个重叠的图像。

在这里,我提供了迄今为止我所做的事情:

DragNDropActivity.java

private static final String TAG = DragNDropActivity.class.getSimpleName();
private ImageView m_ivImage1, finalImage, sourceImage, targetImage,
        testImage;
private int m_counter = 0;
float m_lastTouchX, m_lastTouchY, m_posX, m_posY, m_prevX, m_prevY,
        m_imgXB, m_imgYB, m_imgXC, m_imgYC, m_dx, m_dy;
private LinearLayout m_llTop;
private AbsoluteLayout m_alTop;
private Button m_btnAddView, m_btnRemove, saveImage;
private Context m_context;

@Override
public void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.drag_drop_layout);

    m_context = this;
    testImage = new ImageView(m_context);

    m_prevX = 0;
    m_prevY = 0;
    m_imgXB = 50;
    m_imgYB = 100;
    m_imgXC = 150;
    m_imgYC = 100;

    m_ivImage1 = (ImageView) findViewById(R.id.ddivImage1);
    m_llTop = (LinearLayout) findViewById(R.id.ddllTop);
    m_alTop = (AbsoluteLayout) findViewById(R.id.ddalTop);
    m_btnAddView = (Button) findViewById(R.id.ddbtnAdd);
    m_btnRemove = (Button) findViewById(R.id.ddbtnRemove);
    finalImage = (ImageView) findViewById(R.id.finalImage);
    saveImage = (Button) findViewById(R.id.saveImage);

    m_ivImage1.setOnTouchListener(m_onTouchListener);
    m_btnAddView.setOnClickListener(m_onClickListener);
    m_btnRemove.setOnClickListener(m_onClickListener);
    saveImage.setOnClickListener(m_onClickListener);

    //Test code For Merging two images
    Bitmap bottomImage = BitmapFactory.decodeFile(Environment.getExternalStorageDirectory().getPath() + "/android.jpg");
    Bitmap topImage = BitmapFactory.decodeFile(Environment.getExternalStorageDirectory().getPath() + "/kitkat.jpg");

    Bitmap mutableBitmap = bottomImage.copy(Bitmap.Config.ARGB_8888, true);
    // use the canvas to combine them.
    // Start with the first in the constructor..
    Canvas comboImage = new Canvas(mutableBitmap);
    // Then draw the second on top of that
    comboImage.drawBitmap(topImage, 10f, 10f, null);

    // bottomImage is now a composite of the two.

    // To write the file out to the SDCard:
    OutputStream os = null;
    try
    {
        os = new FileOutputStream(Environment.getExternalStorageDirectory().getPath() + "/myNewFileName.jpg");
        mutableBitmap.compress(Bitmap.CompressFormat.PNG, 50, os);
    }
    catch (IOException e)
    {
        e.printStackTrace();
    }
    //End of Test Code

}

/**
 * Common click listener for clickable controls
 */
OnClickListener m_onClickListener = new OnClickListener()
{

    @Override
    public void onClick(View p_v)
    {
        switch (p_v.getId())
        {
        case R.id.ddbtnAdd:
            addView();
            break;
        case R.id.ddbtnRemove:
            removeView();
            break;
        case R.id.saveImage:
            saveImage();
            break;
        default:
            break;
        }
    }
};

@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private void saveImage()
{
    Drawable sourceDrawable = sourceImage.getDrawable();
    //              Drawable targetDrawable = targetImage.getDrawable();

    finalImage = new ImageView(m_context);

    if (null != testImage.getBackground())
    {
        //imageview have image

        Log.d(TAG, "Image is not null in SaveImage");
        finalImage.setVisibility(View.VISIBLE);
        finalImage.setBackgroundDrawable(testImage.getBackground());
    }
    else
    {
        //imageview have no image
        Log.d(TAG, "Image is null in SaveImage");
    }
}

/**
 * Touch listener for view
 */
OnTouchListener m_onTouchListener = new OnTouchListener()
{

    @Override
    public boolean onTouch(View p_v, MotionEvent p_event)
    {
        switch (p_event.getAction())
        {
        case MotionEvent.ACTION_DOWN:
        {
            m_lastTouchX = p_event.getX();
            m_lastTouchY = p_event.getY();

            break;
        }
        case MotionEvent.ACTION_UP:
        {
            //It indicates that the pressure on image is released and it is stable now i.e it is not in motion.
            //Todo  Save final image
            //              saveImage();
            break;
        }

        case MotionEvent.ACTION_MOVE:
        {
            m_dx = p_event.getX() - m_lastTouchX;
            m_dy = p_event.getY() - m_lastTouchY;

            m_posX = m_prevX + m_dx;
            m_posY = m_prevY + m_dy;

            if (m_posX > 0 && m_posY > 0 && (m_posX + p_v.getWidth()) < m_alTop.getWidth() && (m_posY + p_v.getHeight()) < m_alTop.getHeight())
            {
                p_v.setLayoutParams(new AbsoluteLayout.LayoutParams(p_v.getMeasuredWidth(), p_v.getMeasuredHeight(), (int) m_posX, (int) m_posY));

                m_prevX = m_posX;
                m_prevY = m_posY;

            }

            break;

        }

        }
        return true;
    }
};

View.OnDragListener m_dragListener = new View.OnDragListener()
{
    @Override
    public boolean onDrag(View view, DragEvent dragEvent)
    {
        Log.d(" Drag Event", "Drop Event " + dragEvent.getAction());

        if (dragEvent.getAction() == DragEvent.ACTION_DROP)
        {
            Log.d(" Drag Event", "Drop Ended ");
        }

        return true;
    }
};

/**
 * Add view dynamically for drag and drop
 */
private void addView()
{
    sourceImage = new ImageView(m_context);
    targetImage = new ImageView(m_context);
    TextView m_tv = new TextView(m_context);
    if (m_counter < 6)
    {
        if (m_counter % 2 == 0)
        {

            sourceImage.setBackgroundResource(R.drawable.ic_launcher);

            //m_tv.setText("Hello! Drag Me! ");
            m_alTop.addView(m_tv, new LayoutParams(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT, ((int) m_imgXB), ((int) m_imgYB)));
            m_alTop.addView(sourceImage, new LayoutParams(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT, ((int) m_imgXB), ((int) m_imgYB)));
        }
        else
        {
            targetImage.setBackgroundResource(android.R.drawable.star_big_on);
            m_alTop.addView(targetImage, new LayoutParams(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT, ((int) m_imgXC), ((int) m_imgYC)));
        }
        m_counter++;
        if (m_counter == 6) m_btnAddView.setEnabled(false);
    }
    if (null != sourceImage.getBackground())
    {
        //imageview have image
        testImage = sourceImage;
        Log.d(TAG, "Image is not null in addView");
    }
    else
    {
        //imageview have no image
        Log.d(TAG, "Image is null");
    }

    //      sourceImage.setOnTouchListener(m_onTouchListener);
    targetImage.setOnTouchListener(m_onTouchListener);
    sourceImage.setOnTouchListener(m_onTouchListener);
    m_tv.setOnTouchListener(m_onTouchListener);
}

public void removeView()
{
    m_counter = 0;
    m_alTop.removeAllViews();
    m_alTop.invalidate();
    m_btnAddView.setEnabled(true);
}

@Override
public void onBackPressed()
{
    this.clearView();
    super.onBackPressed();
}

@Override
protected void onDestroy()
{
    this.clearView();
    super.onDestroy();
}

/**
 * Clear the views and free memory
 */
public void clearView()
{
    if (m_context != null) m_context = null;

    if (m_llTop != null) m_llTop = null;

    if (m_alTop != null) m_alTop = null;

    if (m_btnAddView != null) m_btnAddView = null;

    if (m_btnRemove != null) m_btnRemove = null;

    if (m_ivImage1 != null) m_ivImage1 = null;
}

@Override
public boolean onDrag(View view, DragEvent dragEvent)
{
    Log.d(TAG, "Drop Event " + dragEvent.getAction());
    return true;
}

此代码的输出:

正如你可以看到Droid上的明星。但是现在如何从中制作图像并保存原样?

2 个答案:

答案 0 :(得分:2)

此函数将视图转换为位图。将目标Image传递给以下方法,并返回其所有子视图的位图。

public static Bitmap getBitmapFromView(View view) {
    //Define a bitmap with the same size as the view
    Bitmap returnedBitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(),Bitmap.Config.ARGB_8888);
    //Bind a canvas to it
    Canvas canvas = new Canvas(returnedBitmap);
    //Get the view's background
    Drawable bgDrawable =view.getBackground();
    if (bgDrawable!=null) 
        //has background drawable, then draw it on the canvas
        bgDrawable.draw(canvas);
    else 
        //does not have background drawable, then draw white background on the canvas
        canvas.drawColor(Color.WHITE);
    // draw the view on the canvas
    view.draw(canvas);
    //return the bitmap
    return returnedBitmap;
}

答案 1 :(得分:1)

请在saveImage()方法中尝试此操作:

try {
    // Create a new File instance to save the generated image;
    File file = new File(Environment.getExternalStorageDirectory()
            .getPath() + "/saved.png");
    // Check if File does not exist in the storage;
    if (!file.exists()) {
        // Create a physical File;
        file.createNewFile();
    }
    // Initialize a FileOutputStream to write to the File;
    FileOutputStream fos = new FileOutputStream(file);
    // Top edge Y coordinate of the top most child View;
    int boundTop = m_alTop.getMeasuredHeight();
    // Left edge X coordinate of the left most child View;
    int boundLeft = m_alTop.getMeasuredWidth();
    // Bottom edge Y coordinate of the bottom most child View;
    int boundBottom = 0;
    // Right edge X coordinate of the right most child View;
    int boundRight = 0;
    // Get the total number of child Views present in the Layout;
    int totalChildren = m_alTop.getChildCount();
    // Value to add as padding to the final image;
    int padding = 20;
    // Iterate through all the child Views;
    for(int i = 0; i < totalChildren; i++) {
        // Get the current child View;
        View vw = m_alTop.getChildAt(i);
        // Check if it is higher than the current top edge;
        if(vw.getTop() < boundTop) {
            // Update the top edge value;
            boundTop = vw.getTop();
        }
        // Check if it is more leftwards than the current left edge;
        if(vw.getLeft() < boundLeft) {
            // Update the left edge value;
            boundLeft = vw.getLeft();
        }
        // Check if it is lower than the current bottom edge;
        if(vw.getBottom() > boundBottom) {
            // Update the bottom edge value;
            boundBottom = vw.getBottom();
        }
        // Check if it is more rightwards than the current right edge;
        if(vw.getRight() > boundRight) {
            // Update the right edge value;
            boundRight = vw.getRight();
        }
    }
//  Toast.makeText(this, boundTop + ", " + boundLeft + ", " + boundBottom + ", " + boundRight, Toast.LENGTH_LONG)
//      .show();
    // Calculate the final Bitmap width;
    int bWidth = padding + boundRight - boundLeft;
    // Calculate the final Bitmap height;
    int bHeight = padding + boundBottom - boundTop;
    // Create a Bitmap Object with the specified width and height;
    Bitmap bitmap = Bitmap.createBitmap(bWidth,
            bHeight, Bitmap.Config.ARGB_8888);
    // Initialize a Canvas to draw to the Bitmap;
    Canvas canvas = new Canvas(bitmap);
    // Fill the Bitmap with transparency;
    canvas.drawColor(Color.TRANSPARENT);
    /*
     * Translate the Canvas towards top left direction to compensate for
     * the blank space between the extreme Views and the edges of the
     * Layout and also the extra padding.
     */
    canvas.translate(- boundLeft + padding/2, - boundTop + padding/2);
    // Make the Layout draw its child Views on the Canvas;
    m_alTop.draw(canvas);
    // Save the Bitmap to the File instance;
    bitmap.compress(Bitmap.CompressFormat.PNG, 81, fos);
    // Flush(Clear) the FileOutputStream;
    fos.flush();
    // Close the FileOutputStream;
    fos.close();
    // Flag the Bitmap for garbage collection;
    bitmap.recycle();
}catch (Exception e) {
    Toast.makeText(this, "ERROR WHILE SAVING", Toast.LENGTH_LONG)
            .show();
    e.printStackTrace();
}

TextView方法中添加了一个空白addView(),我必须注释才能正常工作:

if (m_counter % 2 == 0) {
    .
    .
    // m_alTop.addView(m_tv, new AbsoluteLayout.LayoutParams....
    m_alTop.addView(sourceImage, new AbsoluteLayout.LayoutParams....

修改:将ConfigRGB_565更改为ARGB_8888

Edit_2015_04_16:现在使用填充保存位图中的裁剪图像,并添加透明背景。