- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有以下ColorMatrixFilter。但我想将其用作减混模式的蒙版,而不是直接使用它。我该如何实现这一目标?
ColorMatrix:
colorMatrix[
0.393, 0.7689999, 0.18899999, 0, 0,
0.349, 0.6859999, 0.16799999, 0, 0,
0.272, 0.5339999, 0.13099999, 0, 0,
0, 0, 0, 1, 0
];
最佳答案
长话短说
Android中没有开箱即用的减法混合功能。但是,您可以使用OpenGL实现所需的颜色混合。 Here是要点,您可以这样使用:
BlendingFilterUtil.subtractMatrixColorFilter(bitmap, new float[]{
0.393f, 0.7689999f, 0.18899999f, 0, 0,
0.349f, 0.6859999f, 0.16799999f, 0, 0,
0.272f, 0.5339999f, 0.13099999f, 0, 0,
0, 0, 0, 1, 0
}, activity, callback);
ColorFilter
子类描述。正如您从文档中看到的,
ColorFilter
有三种可用的实现:
PorterDuffColorFilter
本质上是讨论的混合模式LightingColorFilter
非常简单。它由两个参数组成,其中一个用作因子,另一个用作红色,绿色和蓝色 channel 的附加值。 Alpha channel 保持不变。因此,您可以使某些图像看起来更亮(如果因数在0到1之间,或者加法为负数,则可以看起来更暗)。 ColorMatrixColorFilter
是一个更花哨的东西。此过滤器是由 ColorMatrix
构造的。某种程度上ColorMatrixColorFilter
与LightingColorFilter
相似,它还对原始颜色执行一些数学运算并构成用于其中的参数,但功能更强大。让我们引用ColorMatrix
文档以了解有关其实际工作方式的更多信息:4x5 matrix for transforming the color and alpha components of a Bitmap. The matrix can be passed as single array, and is treated as follows:
[ a, b, c, d, e,
f, g, h, i, j,
k, l, m, n, o,
p, q, r, s, t ]When applied to a color [R, G, B, A], the resulting color is computed as:
R’ = a*R + b*G + c*B + d*A + e;
G’ = f*R + g*G + h*B + i*A + j;
B’ = k*R + l*G + m*B + n*A + o;
A’ = p*R + q*G + r*B + s*A + t;
ColorMatrixColorFilter
(因为没有其他方法可以利用此矩阵)。从上面的描述中可以看到,“减法混合模式”采用两种颜色,而“颜色矩阵”滤色器采用一种颜色和一种可以更改该颜色的矩阵。这是两个不同的函数,它们采用不同类型的参数。我想到它们如何组合的唯一方法是采用原始颜色(Cdst),首先对其应用
ColorMatrix
(过滤器函数),然后从原始颜色中减去此操作的结果,因此我们应得出以下公式:
ColorMatrixColorFilter
,然后将后续的
PorterDuffColorFilter
与减法模式一起使用,并使用过滤后的结果作为源图像。但是,如果您仔细阅读
PorterDuff.Mode
引用,您会发现
Android系统中没有减法混合模式。 Android OS使用下面的
Google's Skia库进行 Canvas 绘制,由于某种原因,它实际上是
lacks Subtract mode,因此我们将不得不以另一种方式进行减法。
GLSurfaceView
,它在后台设置了Open GL上下文并提供了我们所有需要的功能,但是直到我们将该 View 添加到View层次结构中,它才起作用,所以我的计划是实例化
GLSurfaceView
,并将其附加到我们的应用程序中窗口,给它一个位图,我们要对其应用效果并在那里执行所有花哨的东西。由于它与问题不直接相关,因此我不会过多介绍OpenGL本身,但是,如果您需要澄清任何内容,请随时提出评论。
GLSurfaceView
GLSurfaceView
实例,并设置目标参数所需的所有参数:
GLSurfaceView hostView = new GLSurfaceView(activityContext);
hostView.setEGLContextClientVersion(2);
hostView.setEGLConfigChooser(8, 8, 8, 8, 0, 0);
// View should be of bitmap size
final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(width, height, TYPE_APPLICATION, 0, PixelFormat.OPAQUE);
view.setLayoutParams(layoutParams);
final WindowManager windowManager = (WindowManager) view.getContext().getSystemService(Context.WINDOW_SERVICE);
Objects.requireNonNull(windowManager).addView(view, layoutParams);
width
和
height
参数应与我们要处理的位图的
width
和
height
相匹配。
GLSurfaceView
本身不会绘制任何内容。这项工作由
Renderer
类完成。让我们定义一个包含几个字段的类:
class BlendingFilterRenderer implements GLSurfaceView.Renderer {
private final Bitmap mBitmap;
private final WeakReference<GLSurfaceView> mHostViewReference;
private final float[] mColorFilter;
private final BlendingFilterUtil.Callback mCallback;
private boolean mFinished = false;
BlendingFilterRenderer(@NonNull GLSurfaceView hostView, @NonNull Bitmap bitmap,
@NonNull float[] colorFilter,
@NonNull BlendingFilterUtil.Callback callback)
throws IllegalArgumentException {
if (colorFilter.length != 4 * 5) {
throw new IllegalArgumentException("Color filter should be a 4 x 5 matrix");
}
mBitmap = bitmap;
mHostViewReference = new WeakReference<>(hostView);
mColorFilter = colorFilter;
mCallback = callback;
}
// ========================================== //
// GLSurfaceView.Renderer
// ========================================== //
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {}
@Override
public void onDrawFrame(GL10 gl) {}
}
Bitmap
。我们将使用普通的
ColorMatrix
java数组,而不是实际的
float[]
实例,因为最终我们将不会使用Android工具来应用此效果,也不需要此类。我们还需要保留对
GLSurfaceView
的引用,以便在工作完成后将其从应用程序窗口中删除。最后但并非最不重要的是回调。
GLSurfaceView
中的所有绘图都发生在单独的线程中,因此我们无法同步执行此工作,因此需要回调以返回结果。我定义了回调接口(interface),如下所示:
interface Callback {
void onSuccess(@NonNull Bitmap blendedImage);
void onFailure(@Nullable Exception error);
}
mFinished
标志,以防止任何进一步的操作。定义渲染器后,返回
GLSurfaceView
设置并设置渲染器实例。我还建议将渲染模式设置为
RENDERMODE_WHEN_DIRTY
以防止每秒绘制60次:
hostView.setRenderer(new BlendingFilterRenderer(hostView, image, filterValues, callback));
hostView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
private int loadShader(int type, String shaderCode) throws GLException {
int reference = GLES20.glCreateShader(type);
GLES20.glShaderSource(reference, shaderCode);
GLES20.glCompileShader(reference);
int[] compileStatus = new int[1];
GLES20.glGetShaderiv(reference, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
if (compileStatus[0] != GLES20.GL_TRUE) {
GLES20.glDeleteShader(reference);
final String message = GLES20.glGetShaderInfoLog(reference);
throw new GLException(compileStatus[0], message);
}
return reference;
}
attribute vec2 aPosition;
void main() {
gl_Position = vec4(aPosition.x, aPosition.y, 0.0, 1.0);
}
aPosition
属性将在规范化坐标系中获取x和y坐标(x和y坐标从-1到1),并将它们传递给全局
gl_Position
变量。
precision mediump float;
void main() {
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
gl_FragColor
,该变量定义输出颜色(这是实际的魔术发生的地方)。
private int loadProgram() {
int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, "precision mediump float;" +
"void main() {" +
" gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);" +
"}");
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, "attribute vec2 aPosition;" +
"void main() {" +
" gl_Position = vec4(aPosition.x, aPosition.y, 0.0, 1.0);" +
"}");
int programReference = GLES20.glCreateProgram();
GLES20.glAttachShader(programReference, vertexShader);
GLES20.glAttachShader(programReference, fragmentShader);
GLES20.glLinkProgram(programReference);
return programReference;
}
private void enableVertexAttribute(int program, String attributeName, int size, int stride, int offset) {
final int attributeLocation = GLES20.glGetAttribLocation(program, attributeName);
GLES20.glVertexAttribPointer(attributeLocation, size, GLES20.GL_FLOAT, false, stride, offset);
GLES20.glEnableVertexAttribArray(attributeLocation);
}
GLSurfaceSize
相匹配,在归一化设备坐标系(NDCS)中,它非常简单,对于x和y坐标,整个表面坐标都可以用-1到1的范围来表示。 ,因此这是我们的坐标:
new float[] {
-1, 1,
-1, -1,
1, 1,
1, -1,
}
private FloatBuffer convertToBuffer(float[] array) {
final ByteBuffer buffer = ByteBuffer.allocateDirect(array.length * PrimitiveSizes.FLOAT);
FloatBuffer output = buffer.order(ByteOrder.nativeOrder()).asFloatBuffer();
output.put(array);
output.position(0);
return output;
}
private void initVertices(int programReference) {
final float[] verticesData = new float[] {
-1, 1,
-1, -1,
1, 1,
1, -1,
}
int buffers[] = new int[1];
GLES20.glGenBuffers(1, buffers, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[0]);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, verticesData.length * 4, convertToBuffer(verticesData), GLES20.GL_STREAM_DRAW);
enableVertexAttribute(programReference, "aPosition", 2, 0, 0);
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES20.glViewport(0, 0, width, height);
final int program = loadProgram();
GLES20.glUseProgram(program);
initVertices(program);
}
@Override
public void onDrawFrame(GL10 gl) {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
}
attribute vec2 aPosition;
attribute vec2 aTextureCoord;
varying vec2 vTextureCoord;
void main() {
gl_Position = vec4(aPosition.x, aPosition.y, 0.0, 1.0);
vTextureCoord = aTextureCoord;
}
precision mediump float;
uniform sampler2D uSampler;
varying vec2 vTextureCoord;
void main() {
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
gl_FragColor = texture2D(uSampler, vTextureCoord);
}
aTextureCoord
属性中),然后顶点着色器将这些坐标传递到类型不同的特殊变量
vTextureCoord
中,该变量在顶点之间进行插值,并将内插值传递给片段着色器。片段着色器通过
uSampler
统一参数获取纹理,并从
texture2D
函数获取所需像素的颜色以及从顶点着色器传递的纹理坐标。
initVertices
更改为如下所示:
private void initVertices(int programReference) {
final float[] verticesData = new float[] {
//NDCS coords //UV map
-1, 1, 0, 1,
-1, -1, 0, 0,
1, 1, 1, 1,
1, -1, 1, 0
}
int buffers[] = new int[1];
GLES20.glGenBuffers(1, buffers, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[0]);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, verticesData.length * 4, convertToBuffer(verticesData), GLES20.GL_STREAM_DRAW);
final int stride = 4 * 4;
enableVertexAttribute(programReference, "aPosition", 2, stride, 0);
enableVertexAttribute(programReference, "aTextureCoord", 2, stride, 2 * 4);
}
private void attachTexture(int programReference) {
final int[] textures = new int[1];
GLES20.glGenTextures(1, textures, 0);
final int textureId = textures[0];
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, mBitmap, 0);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
final int samplerLocation = GLES20.glGetUniformLocation(programReference, "uSampler");
GLES20.glUniform1i(samplerLocation, 0);
}
onSurfaceChanged
方法中调用此方法:
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES20.glViewport(0, 0, width, height);
final int program = loadProgram();
GLES20.glUseProgram(program);
initVertices(program);
attachTexture(program);
}
precision mediump float;
struct ColorFilter {
mat4 factor;
vec4 shift;
};
uniform sampler2D uSampler;
uniform ColorFilter uColorFilter;
varying vec2 vTextureCoord;
void main() {
gl_FragColor = texture2D(uSampler, vTextureCoord);
vec4 originalColor = texture2D(uSampler, vTextureCoord);
vec4 filteredColor = (originalColor * uColorFilter.factor) + uColorFilter.shift;
gl_FragColor = originalColor - filteredColor;
}
private void attachColorFilter(int program) {
final float[] colorFilterFactor = new float[4 * 4];
final float[] colorFilterShift = new float[4];
for (int i = 0; i < mColorFilter.length; i++) {
final float value = mColorFilter[i];
final int calculateIndex = i + 1;
if (calculateIndex % 5 == 0) {
colorFilterShift[calculateIndex / 5 - 1] = value / 255;
} else {
colorFilterFactor[i - calculateIndex / 5] = value;
}
}
final int colorFactorLocation = GLES20.glGetUniformLocation(program, "uColorFilter.factor");
GLES20.glUniformMatrix4fv(colorFactorLocation, 1, false, colorFilterFactor, 0);
final int colorShiftLocation = GLES20.glGetUniformLocation(program, "uColorFilter.shift");
GLES20.glUniform4fv(colorShiftLocation, 1, colorFilterShift, 0);
}
onSurfaceChanged
方法中调用此方法:
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES20.glViewport(0, 0, width, height);
final int program = loadProgram();
GLES20.glUseProgram(program);
initVertices(program);
attachTexture(program);
attachColorFilter(program);
}
hostView.setEGLConfigChooser(8, 8, 8, 8, 0, 0);
时,我们实际上在OpenGL上下文中为Alpha channel 添加了缓冲区。否则,我们将始终为输出图像获取一些背景(考虑到png图像对于某些像素往往具有不同的alpha channel ,这是不正确的)。坏消息是它破坏了alpha混合机制,对于某些特殊情况,您将获得意想不到的颜色。好消息-我们可以轻松修复它。首先,我们需要在片段着色器中应用alpha混合:
precision mediump float;
struct ColorFilter {
mat4 factor;
vec4 shift;
};
uniform sampler2D uSampler;
uniform ColorFilter uColorFilter;
varying vec2 vTextureCoord;
void main() {
vec4 originalColor = texture2D(uSampler, vTextureCoord);
originalColor.rgb *= originalColor.a;
vec4 filteredColor = (originalColor * uColorFilter.factor) + uColorFilter.shift;
filteredColor.rgb *= filteredColor.a;
gl_FragColor = originalColor - filteredColor
gl_FragColor = vec4(originalColor.rgb - filteredColor.rgb, originalColor.a);
}
ImageView
。但是,我们没有将颜色设置为清晰的颜色,并且似乎没有任何改变:
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ZERO);
}
GLSurfaceView
获取位图,我从
another stackoverflow answer借出了一个出色的解决方案:
private Bitmap retrieveBitmapFromGl(int width, int height) {
final ByteBuffer pixelBuffer = ByteBuffer.allocateDirect(width * height * PrimitiveSizes.FLOAT);
pixelBuffer.order(ByteOrder.LITTLE_ENDIAN);
GLES20.glReadPixels(0,0, width, height, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, pixelBuffer);
final Bitmap image = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
image.copyPixelsFromBuffer(pixelBuffer);
return image;
}
private GLException getGlError() {
int errorValue = GLES20.glGetError();
switch (errorValue) {
case GLES20.GL_NO_ERROR:
return null;
default:
return new GLException(errorValue);
}
}
private void postResult() {
if (mFinished) {
return;
}
final GLSurfaceView hostView = mHostViewReference.get();
if (hostView == null) {
return;
}
GLException glError = getGlError();
if (glError != null) {
hostView.post(() -> {
mCallback.onFailure(glError);
removeHostView(hostView);
});
} else {
final Bitmap result = retrieveBitmapFromGl(mBitmap.getWidth(), mBitmap.getHeight());
hostView.post(() -> {
mCallback.onSuccess(result);
removeHostView(hostView);
});
}
mFinished = true;
}
private void removeHostView(@NonNull GLSurfaceView hostView) {
if (hostView.getParent() == null) {
return;
}
final WindowManager windowManager = (WindowManager) hostView.getContext().getSystemService(Context.WINDOW_SERVICE);
Objects.requireNonNull(windowManager).removeView(hostView);
}
onDrawFrame
方法中调用它:
@Override
public void onDrawFrame(GL10 gl) {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
postResult();
}
BlendingFilterUtil.subtractMatrixColorFilter(bitmap, new float[]{
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0
}, activity, callback);
BlendingFilterUtil.subtractMatrixColorFilter(bitmap, new float[]{
1, 0, 0, 0, 0,
0, 1, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 1, 0
}, activity, callback);
BlendingFilterUtil.subtractMatrixColorFilter(bitmap, new float[]{
0.393f, 0.7689999f, 0.18899999f, 0, 0,
0.349f, 0.6859999f, 0.16799999f, 0, 0,
0.272f, 0.5339999f, 0.13099999f, 0, 0,
0, 0, 0, 1, 0
}, activity, callback);
关于java - 在Android中使用ColorMatrixFilter减去混合模式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33358030/
我在网上搜索但没有找到任何合适的文章解释如何使用 javascript 使用 WCF 服务,尤其是 WebScriptEndpoint。 任何人都可以对此给出任何指导吗? 谢谢 最佳答案 这是一篇关于
我正在编写一个将运行 Linux 命令的 C 程序,例如: cat/etc/passwd | grep 列表 |剪切-c 1-5 我没有任何结果 *这里 parent 等待第一个 child (chi
所以我正在尝试处理文件上传,然后将该文件作为二进制文件存储到数据库中。在我存储它之后,我尝试在给定的 URL 上提供文件。我似乎找不到适合这里的方法。我需要使用数据库,因为我使用 Google 应用引
我正在尝试制作一个宏,将下面的公式添加到单元格中,然后将其拖到整个列中并在 H 列中复制相同的公式 我想在 F 和 H 列中输入公式的数据 Range("F1").formula = "=IF(ISE
问题类似于this one ,但我想使用 OperatorPrecedenceParser 解析带有函数应用程序的表达式在 FParsec . 这是我的 AST: type Expression =
我想通过使用 sequelize 和 node.js 将这个查询更改为代码取决于在哪里 select COUNT(gender) as genderCount from customers where
我正在使用GNU bash,版本5.0.3(1)-发行版(x86_64-pc-linux-gnu),我想知道为什么简单的赋值语句会出现语法错误: #/bin/bash var1=/tmp
这里,为什么我的代码在 IE 中不起作用。我的代码适用于所有浏览器。没有问题。但是当我在 IE 上运行我的项目时,它发现错误。 而且我的 jquery 类和 insertadjacentHTMl 也不
我正在尝试更改标签的innerHTML。我无权访问该表单,因此无法编辑 HTML。标签具有的唯一标识符是“for”属性。 这是输入和标签的结构:
我有一个页面,我可以在其中返回用户帖子,可以使用一些 jquery 代码对这些帖子进行即时评论,在发布新评论后,我在帖子下插入新评论以及删除 按钮。问题是 Delete 按钮在新插入的元素上不起作用,
我有一个大约有 20 列的“管道分隔”文件。我只想使用 sha1sum 散列第一列,它是一个数字,如帐号,并按原样返回其余列。 使用 awk 或 sed 执行此操作的最佳方法是什么? Accounti
我需要将以下内容插入到我的表中...我的用户表有五列 id、用户名、密码、名称、条目。 (我还没有提交任何东西到条目中,我稍后会使用 php 来做)但由于某种原因我不断收到这个错误:#1054 - U
所以我试图有一个输入字段,我可以在其中输入任何字符,但然后将输入的值小写,删除任何非字母数字字符,留下“。”而不是空格。 例如,如果我输入: 地球的 70% 是水,-!*#$^^ & 30% 土地 输
我正在尝试做一些我认为非常简单的事情,但出于某种原因我没有得到想要的结果?我是 javascript 的新手,但对 java 有经验,所以我相信我没有使用某种正确的规则。 这是一个获取输入值、检查选择
我想使用 angularjs 从 mysql 数据库加载数据。 这就是应用程序的工作原理;用户登录,他们的用户名存储在 cookie 中。该用户名显示在主页上 我想获取这个值并通过 angularjs
我正在使用 autoLayout,我想在 UITableViewCell 上放置一个 UIlabel,它应该始终位于单元格的右侧和右侧的中心。 这就是我想要实现的目标 所以在这里你可以看到我正在谈论的
我需要与 MySql 等效的 elasticsearch 查询。我的 sql 查询: SELECT DISTINCT t.product_id AS id FROM tbl_sup_price t
我正在实现代码以使用 JSON。 func setup() { if let flickrURL = NSURL(string: "https://api.flickr.com/
我尝试使用for循环声明变量,然后测试cols和rols是否相同。如果是,它将运行递归函数。但是,我在 javascript 中执行 do 时遇到问题。有人可以帮忙吗? 现在,在比较 col.1 和
我举了一个我正在处理的问题的简短示例。 HTML代码: 1 2 3 CSS 代码: .BB a:hover{ color: #000; } .BB > li:after {
我是一名优秀的程序员,十分优秀!