【问题标题】:How to combine two opaque bitmaps into one with alpha channel?如何使用 Alpha 通道将两个不透明位图合并为一个?
【发布时间】:2011-07-03 04:34:36
【问题描述】:

我有一个透明的 PNG 文件,用作 OpenGL 纹理。我用BitmapFactory.decodeResource将它加载到Bitmap,然后上传到GPU。

PNG 文件非常大,为了减少 APK 的大小,我尝试使用两个 JPG,一个带有 RGB 数据,另一个带有 alpha 通道(灰度)。

如何将两个 JPG 合并到一个带有 alpha 通道的 Bitmap 对象中? 我尝试将 alpha 通道加载为 Bitmap.Config.ALPHA_8,然后使用 Canvas 将它们相互叠加但到目前为止还没有运气。

【问题讨论】:

  • 啊,我怀念一个简单的 BitBlt 的日子 :)
  • 我现在不知道 tinypng.com 是否适合您...有时会将您的图像缩小 60% 以上。问候
  • 嗨@Dusty,感谢您的评论,今天我肯定会给 tinypng、pngquant 和这样的镜头。将 PNG 拆分为两个不透明的 JPG 的好处是,我可以单独且精确地控制两层的压缩/质量。

标签: android graphics


【解决方案1】:

看看Kevin Dion's answerthis related question。他解释了如何组合 4 个单独的图像(R、G、B 和 A 通道),但您应该能够调整它以处理两个图像。

【讨论】:

  • 谢谢,这有帮助。通过稍微调整一下,我能够从 RGB 位图和仅具有 Alpha 通道的 PNG 生成我的纹理。我希望 alpha 通道也存储在 JPG 中,所以还有一个问题 - 如何将灰度位图转换为 ALPHA_8 位图。
  • 发布了一个关于将灰度位图转换为 alpha 蒙版的后续问题:stackoverflow.com/questions/5106122/…
  • 找到剩余灰度的解决方案->alpha 问题:stackoverflow.com/questions/5106122/…
【解决方案2】:

这是一个完整的例子:

import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;

public class ImageOps {

    private static final ColorMatrix sRedToAlphaMatrix = new ColorMatrix(new float[] {
        0, 0, 0, 0, 0,
        0, 0, 0, 0, 0,
        0, 0, 0, 0, 0,
        1, 0, 0, 0, 0});

    private static final ColorMatrixColorFilter sRedToAlphaFilter = new ColorMatrixColorFilter(sRedToAlphaMatrix);

    public static Bitmap composeAlpha(Bitmap target, Resources resources, int rgbDrawableId, int alphaDrawableId) {
        final BitmapFactory.Options options = new BitmapFactory.Options();          
        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
        options.inScaled = false;       

        // Load RGB data
        Bitmap rgb = BitmapFactory.decodeResource(resources, rgbDrawableId, options);

        if (target == null) {
            // Prepare result Bitmap
            target = Bitmap.createBitmap(rgb.getWidth(), rgb.getHeight(), Bitmap.Config.ARGB_8888);
        }
        Canvas c = new Canvas(target);
        c.setDensity(Bitmap.DENSITY_NONE);

        // Draw RGB data on our result bitmap
        c.drawBitmap(rgb, 0, 0, null);

        // At this point, we don't need rgb data any more: discard!
        rgb.recycle();
        rgb = null;

        // Load Alpha data
        Bitmap alpha = BitmapFactory.decodeResource(resources, alphaDrawableId, options);

        // Draw alpha data on our result bitmap
        final Paint grayToAlpha = new Paint();
        grayToAlpha.setColorFilter(sRedToAlphaFilter);
        grayToAlpha.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
        c.drawBitmap(alpha, 0, 0, grayToAlpha); 

        // Don't need alpha data any more: discard!
        alpha.recycle();
        alpha = null;

        return target;
    }

}

【讨论】:

    【解决方案3】:

    尝试以下操作:遍历两个图像的宽度 * 高度,并在每个图像上使用 Bitmap.getPixel(x,y)。

    int alpha = Color.red(grayscaleBitmap.getPixel(x, y)); // grayscale, so any color will do
    int red = Color.red(colorBitmap.getPixel(x, y));
    int green = Color.green(colorBitmap.getPixel(x, y));
    int blue = Color.blue(colorBitmap.getPixel(x, y));
    int mergedColor = Color.argb(alpha, red, green, blue);
    // save mergedColor in an int[]
    

    然后使用 Bitmap.createBitmap(int[] colors, int width, int height, Bitmap.Config config) 创建新的位图。

    【讨论】:

    • 当然。 :) CPU 便宜将是 PNG。我不知道它比其他任何东西都特别贵。
    • 这确实会阻塞 CPU 不少。我有一些 1024x1024 的纹理。
    • 我现在对此有点恼火。 getPixel 应该是 O(1) 因为它只是一个数组索引方法。双循环仍然是 O(n),其中 n 是像素数。你们真的认为会有比 O(n) 更好的算法吗?仅仅因为您正在调用其他一些更高级别的传输方法并不意味着您仍然没有迭代像素。我宁愿听到“我尝试的时候还不够快”,而不是“我没有尝试过,但我敢打赌它对我来说太慢了”。
    • 对不起 Micah,我应该检查一下我的假设,毕竟这并不难。所以在我的 Nexus One 上,使用 1024x1024 位图的 Canvas 方法大约需要 450 毫秒,而 getPixel 方法大约需要 7000 毫秒。我在某处读到 Canvas 操作有时可以在 GPU 上执行,也许这就是造成如此巨大的速度差异的部分原因。
    • 另外,忘了提一下,您建议的逐像素方法更短且更易于理解。因此,它可能非常适合较小的图形,例如 48x48 图标。
    猜你喜欢
    • 2011-10-12
    • 2015-02-03
    • 2023-03-26
    • 2017-08-31
    • 2018-09-19
    • 2011-04-25
    • 1970-01-01
    • 2014-05-28
    • 2016-05-02
    相关资源
    最近更新 更多