【问题标题】:Implementing different PorterDuff modes in android在android中实现不同的PorterDuff模式
【发布时间】:2012-10-25 14:05:09
【问题描述】:

我正在开发一个图片编辑工具,我需要在其中合并两张图片。大多数图像编辑工具(如 gimp)使用 PorterDuff 模式 来合并或混合图像。我也在 android 中使用相同的方法。
由于 android 提供的 PorterDuff 模式数量有限,我无法达到预期的效果。所以,我正在考虑实现 android 中不包含的 PorterDuff 模式(重叠、强光、柔光、颜色燃烧、颜色减淡)。
问题是我不知道从哪里开始。因此,在这方面的任何参考或指导都将受到高度赞赏。

【问题讨论】:

  • 我没有给你一个好的答案,我怀疑没有。这些模式在 C++ 中的 SKIA 库中处理。您将不得不对其进行更改、重新编译并包含在您的项目中,或者将其包含在自定义版本的 Android 中,这些都不是有吸引力的提议。 code.google.com/p/skia/source/browse/trunk/src/core/…, skia.googlecode.com/svn/trunk/include/core/SkXfermode.h Android SDK 类只不过是围绕 SKIA 的枚举和薄包装。
  • 我觉得C++能做的也能用Java做,唯一的问题就是速度。感谢您的链接。我会通过它们。
  • @Simon 感谢您的链接。我需要知道 PorterDuff 模式背后的数学原理,链接给出了完整的解释。我实现了叠加模式,它运行良好。我正在添加答案,以便其他人可以使用它。

标签: android image-processing porter-duff


【解决方案1】:

这是在android中实现Overlay PorterDuff模式的方法:

public class MyPorterDuffMode
{

    public Bitmap applyOverlayMode(Bitmap srcBmp, Bitmap destBmp)
    {
        int width = srcBmp.getWidth();
        int height = srcBmp.getHeight();
        int srcPixels[] = new int[width * height];;
        int destPixels[] = new int[width * height];
        int resultPixels[] = new int[width * height];
        int aS = 0, rS = 0, gS = 0, bS = 0;
        int rgbS = 0;
        int aD = 0, rD = 0, gD = 0, bD = 0;
        int rgbD = 0;

        try
        {
            srcBmp.getPixels(srcPixels, 0, width, 0, 0, width, height);
            destBmp.getPixels(destPixels, 0, width, 0, 0, width, height);
            srcBmp.recycle();
            destBmp.recycle();
        }
        catch(IllegalArgumentException e)
        {
        }
        catch(ArrayIndexOutOfBoundsException e)
        {
        }

        for(int y = 0; y < height; y++)
        {
            for(int x = 0; x < width; x++)
            {
                rgbS = srcPixels[y*width + x];
                aS = (rgbS >> 24) & 0xff;
                rS = (rgbS >> 16) & 0xff;
                gS = (rgbS >>  8) & 0xff;
                bS = (rgbS      ) & 0xff;

                rgbD = destPixels[y*width + x];
                aD = ((rgbD >> 24) & 0xff);
                rD = (rgbD >> 16) & 0xff;
                gD = (rgbD >>  8) & 0xff;
                bD = (rgbD      )  & 0xff;

                //overlay-mode
                rS = overlay_byte(rD, rS, aS, aD);
                gS = overlay_byte(gD, gS, aS, aD);
                bS = overlay_byte(bD, bS, aS, aD);
                aS = aS + aD - Math.round((aS * aD)/255f);

                resultPixels[y*width + x] = ((int)aS << 24) | ((int)rS << 16) | ((int)gS << 8) | (int)bS;
            }
        }

        return Bitmap.createBitmap(resultPixels, width, height, srcBmp.getConfig());
    }



    // kOverlay_Mode
    int overlay_byte(int sc, int dc, int sa, int da) {
        int tmp = sc * (255 - da) + dc * (255 - sa);
        int rc;
        if (2 * dc <= da) {
            rc = 2 * sc * dc;
        } else {
            rc = sa * da - 2 * (da - dc) * (sa - sc);
        }
        return clamp_div255round(rc + tmp);
    }


    int clamp_div255round(int prod) {
        if (prod <= 0) {
            return 0;
        } else if (prod >= 255*255) {
            return 255;
        } else {
            return Math.round((float)prod/255);
        }
    }

}

注意:在提取位图时将配置设置为 ARGB_8888,这很重要。
任何时候您想要进行图像混合或颜色处理,您都需要确保您处于 ARGB_8888 模式,而不是 RGB_565 模式。在 2.3 之前,android 通常会默认为 RGB_565 模式,除非您明确告诉它这样做以节省内存。

BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inPreferredConfig = Config.ARGB_8888;

【讨论】:

  • 你如何应用这个?我看到了这些类型的选项:myPaint.setColorFilter(new PorterDuffColorFilter(Color.RED, Mode.MULTIPLY));myPaint.setXfermode(new PorterDuffXfermode(Mode.SCREEN)); 我想制作一个柔光混合模式,但我不知道一旦我计算出如何应用它。
  • 当你使用默认的 android api 混合位图时,你首先绘制目标位图,然后绘制源位图,并将绘制设置为所需的 Porterduff 模式。在这里,我创建了自定义 porterduff 模式,因此无法使用此方法。我只是将需要混合的两个位图发送到我处理每个像素并最终返回混合位图的方法中。我在上面的例子中做了同样的事情。检查方法:public Bitmap applyOverlayMode(Bitmap srcBmp, Bitmap destBmp)
猜你喜欢
  • 2011-12-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多