наложите два изображения в Android, чтобы установить просмотр изображения

100

Я пытаюсь наложить два изображения в своем приложении, но кажется, что они не работают на моей canvas.setBitmap()строке. Что я делаю не так?

private void test() {
    Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.t);
    Bitmap mBitmap2 = BitmapFactory.decodeResource(getResources(), R.drawable.tt);
    Bitmap bmOverlay = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), mBitmap.getConfig());
    Canvas canvas = new Canvas();
    canvas.setBitmap(bmOverlay);
    canvas.drawBitmap(mBitmap, new Matrix(), null);
    canvas.drawBitmap(mBitmap2, new Matrix(), null);
    testimage.setImageBitmap(bmOverlay);
}
Джон
источник
Также можно использовать раскладку кадров, например: stackoverflow.com/a/11658554/586484
Lysogen 06

Ответы:

235

Вы можете пропустить сложные манипуляции с Canvas и сделать это полностью с помощью Drawables, используя LayerDrawable. У вас есть один из двух вариантов: вы можете либо определить его в XML, а затем просто установить изображение, либо вы можете настроить его LayerDrawableдинамически в коде.

Решение №1 (через XML):

Создайте новый файл XML с возможностью рисования, назовем его layer.xml:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/t" />
    <item android:drawable="@drawable/tt" />
</layer-list>

Теперь установите изображение, используя этот Drawable:

testimage.setImageDrawable(getResources().getDrawable(R.layout.layer));

Решение №2 (динамическое):

Resources r = getResources();
Drawable[] layers = new Drawable[2];
layers[0] = r.getDrawable(R.drawable.t);
layers[1] = r.getDrawable(R.drawable.tt);
LayerDrawable layerDrawable = new LayerDrawable(layers);
testimage.setImageDrawable(layerDrawable);

(Я не тестировал этот код, поэтому может быть ошибка, но эта общая схема должна работать.)

Дэн Лью
источник
1
спасибо, сработало! одна опечатка, на случай, если кто-то другой использует код: LayerDrawable Layers2 = new LayerDrawable (Layers); testimage.setImageDrawable (слои2);
Джон
1
Отличный способ сэкономить место и повторно использовать изображения. Кроме того, вы можете использовать android: left, android: right, android: top и android: down для управления положением одного из слоев в файле .xml.
zabawaba99
Я использовал это, чтобы нарисовать круглую форму, которую можно рисовать за изображением, очень хорошее решение!
Дэниел Уилсон,
1
Есть ли способ программно скрыть только слои [1]? Я хочу показать слой изображения со слоем загрузчика ajax сверху. Через некоторое время я хочу скрыть только загрузчик ajax. Любое предложение?
harishannam
1
Хорошо работает для моих нужд (я использовал кодовый подход). У меня есть несколько «плиток», на которые пользователь нажимает, чтобы перемещаться по приложению. Используя этот подход, я смог получить одно фоновое изображение (общее для всех плиток) и множество изображений переднего плана (с прозрачным фоном), которые я могу загрузить во время выполнения. Не посмотрел бы на LayerDrawable без этого ответа :-)
DilbertDave
10

хорошо, просто чтобы вы знали, что есть программа под названием DroidDraw. С его помощью вы можете рисовать объекты и примерять их друг на друга. Я пробовал ваше решение, но у меня была анимация под меньшим изображением, поэтому это не сработало. Но затем я попытался поместить одно изображение в относительный макет, который предположительно должен быть первым, а затем поверх него я нарисовал другое изображение, которое предполагается наложить, и все сработало отлично. Итак, RelativeLayout, DroidDraw, и вам все в порядке :) Просто, без всякого вздора :) и вот вам небольшой код:

Логотип будет поверх фонового изображения Shazam.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:id="@+id/widget30"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
>
<ImageView
android:id="@+id/widget39"
android:layout_width="219px"
android:layout_height="225px"
android:src="@drawable/shazam_bkgd"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
>
</ImageView>
<ImageView
android:id="@+id/widget37"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/shazam_logo"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
>
</ImageView>
</RelativeLayout>
капли Юпитера
источник
6

Вы можете использовать приведенный ниже код для решения проблемы или загрузить демо здесь

Создайте две функции для обработки каждой.

Сначала рисуется холст, и изображения рисуются друг над другом из точки (0,0)

При нажатии кнопки

public void buttonMerge(View view) {

        Bitmap bigImage = BitmapFactory.decodeResource(getResources(), R.drawable.img1);
        Bitmap smallImage = BitmapFactory.decodeResource(getResources(), R.drawable.img2);
        Bitmap mergedImages = createSingleImageFromMultipleImages(bigImage, smallImage);

        img.setImageBitmap(mergedImages);
    }

Функция для создания наложения.

private Bitmap createSingleImageFromMultipleImages(Bitmap firstImage, Bitmap secondImage){

    Bitmap result = Bitmap.createBitmap(firstImage.getWidth(), firstImage.getHeight(), firstImage.getConfig());
    Canvas canvas = new Canvas(result);
    canvas.drawBitmap(firstImage, 0f, 0f, null);
    canvas.drawBitmap(secondImage, 10, 10, null);
    return result;
}

Читать далее

Даниэль Ньямасё
источник
2

Это немного запоздалый ответ, но он касается слияния изображений с URL-адресов с помощью Picasso.

MergeImageView

import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Build;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.widget.ImageView;
import com.squareup.picasso.Picasso;

import java.io.IOException;
import java.util.List;

public class MergeImageView extends ImageView {

    private SparseArray<Bitmap> bitmaps = new SparseArray<>();
    private Picasso picasso;
    private final int DEFAULT_IMAGE_SIZE = 50;
    private int MIN_IMAGE_SIZE = DEFAULT_IMAGE_SIZE;
    private int MAX_WIDTH = DEFAULT_IMAGE_SIZE * 2, MAX_HEIGHT = DEFAULT_IMAGE_SIZE * 2;
    private String picassoRequestTag = null;

    public MergeImageView(Context context) {
        super(context);
    }

    public MergeImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MergeImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public MergeImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public boolean isInEditMode() {
        return true;
    }

    public void clearResources() {
        if (bitmaps != null) {
            for (int i = 0; i < bitmaps.size(); i++)
                bitmaps.get(i).recycle();
            bitmaps.clear();
        }
        // cancel picasso requests
        if (picasso != null && AppUtils.ifNotNullEmpty(picassoRequestTag))
            picasso.cancelTag(picassoRequestTag);
        picasso = null;
        bitmaps = null;
    }

    public void createMergedBitmap(Context context, List<String> imageUrls, String picassoTag) {
        picasso = Picasso.with(context);
        int count = imageUrls.size();
        picassoRequestTag = picassoTag;

        boolean isEven = count % 2 == 0;
        // if url size are not even make MIN_IMAGE_SIZE even
        MIN_IMAGE_SIZE = DEFAULT_IMAGE_SIZE + (isEven ? count / 2 : (count / 2) + 1);
        // set MAX_WIDTH and MAX_HEIGHT to twice of MIN_IMAGE_SIZE
        MAX_WIDTH = MAX_HEIGHT = MIN_IMAGE_SIZE * 2;
        // in case of odd urls increase MAX_HEIGHT
        if (!isEven) MAX_HEIGHT = MAX_WIDTH + MIN_IMAGE_SIZE;

        // create default bitmap
        Bitmap bitmap = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_wallpaper),
                MIN_IMAGE_SIZE, MIN_IMAGE_SIZE, false);

        // change default height (wrap_content) to MAX_HEIGHT
        int height = Math.round(AppUtils.convertDpToPixel(MAX_HEIGHT, context));
        setMinimumHeight(height * 2);

        // start AsyncTask
        for (int index = 0; index < count; index++) {
            // put default bitmap as a place holder
            bitmaps.put(index, bitmap);
            new PicassoLoadImage(index, imageUrls.get(index)).execute();
            // if you want parallel execution use
            // new PicassoLoadImage(index, imageUrls.get(index)).(AsyncTask.THREAD_POOL_EXECUTOR);
        }
    }

    private class PicassoLoadImage extends AsyncTask<String, Void, Bitmap> {

        private int index = 0;
        private String url;

        PicassoLoadImage(int index, String url) {
            this.index = index;
            this.url = url;
        }

        @Override
        protected Bitmap doInBackground(String... params) {
            try {
                // synchronous picasso call
                return picasso.load(url).resize(MIN_IMAGE_SIZE, MIN_IMAGE_SIZE).tag(picassoRequestTag).get();
            } catch (IOException e) {
            }
            return null;
        }

        @Override
        protected void onPostExecute(Bitmap output) {
            super.onPostExecute(output);
            if (output != null)
                bitmaps.put(index, output);

            // create canvas
            Bitmap.Config conf = Bitmap.Config.RGB_565;
            Bitmap canvasBitmap = Bitmap.createBitmap(MAX_WIDTH, MAX_HEIGHT, conf);
            Canvas canvas = new Canvas(canvasBitmap);
            canvas.drawColor(Color.WHITE);

            // if height and width are equal we have even images
            boolean isEven = MAX_HEIGHT == MAX_WIDTH;
            int imageSize = bitmaps.size();
            int count = imageSize;

            // we have odd images
            if (!isEven) count = imageSize - 1;
            for (int i = 0; i < count; i++) {
                Bitmap bitmap = bitmaps.get(i);
                canvas.drawBitmap(bitmap, bitmap.getWidth() * (i % 2), bitmap.getHeight() * (i / 2), null);
            }
            // if images are not even set last image width to MAX_WIDTH
            if (!isEven) {
                Bitmap scaledBitmap = Bitmap.createScaledBitmap(bitmaps.get(count), MAX_WIDTH, MIN_IMAGE_SIZE, false);
                canvas.drawBitmap(scaledBitmap, scaledBitmap.getWidth() * (count % 2), scaledBitmap.getHeight() * (count / 2), null);
            }
            // set bitmap
            setImageBitmap(canvasBitmap);
        }
    }
}

xml

<com.example.MergeImageView
    android:id="@+id/iv_thumb"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

пример

List<String> urls = new ArrayList<>();
String picassoTag = null;
// add your urls
((MergeImageView)findViewById(R.id.iv_thumb)).
        createMergedBitmap(MainActivity.this, urls,picassoTag);
Харис Куреши
источник
1

это мое решение:

    public Bitmap Blend(Bitmap topImage1, Bitmap bottomImage1, PorterDuff.Mode Type) {

        Bitmap workingBitmap = Bitmap.createBitmap(topImage1);
        Bitmap topImage = workingBitmap.copy(Bitmap.Config.ARGB_8888, true);

        Bitmap workingBitmap2 = Bitmap.createBitmap(bottomImage1);
        Bitmap bottomImage = workingBitmap2.copy(Bitmap.Config.ARGB_8888, true);

        Rect dest = new Rect(0, 0, bottomImage.getWidth(), bottomImage.getHeight());
        new BitmapFactory.Options().inPreferredConfig = Bitmap.Config.ARGB_8888;
        bottomImage.setHasAlpha(true);
        Canvas canvas = new Canvas(bottomImage);
        Paint paint = new Paint();

        paint.setXfermode(new PorterDuffXfermode(Type));

        paint.setFilterBitmap(true);
        canvas.drawBitmap(topImage, null, dest, paint);
        return bottomImage;
    }

использование :

imageView.setImageBitmap(Blend(topBitmap, bottomBitmap, PorterDuff.Mode.SCREEN));

или

imageView.setImageBitmap(Blend(topBitmap, bottomBitmap, PorterDuff.Mode.OVERLAY));

и результаты:

Режим наложения: Режим наложения

Режим экрана: Режим экрана

Садек Намени
источник
Это хорошо. Но если вы хотите отображать два изображения рядом, каково решение?
маньяк