Estoy trabajando en una interfaz de usuario para una aplicación, y estoy intentando utilizar la escala de grises iconos, y permitir al usuario cambiar el tema a un color de su elección. Para hacer esto, estoy tratando de simplemente aplicar un ColorFilter de algún tipo a la superposición de un color en la parte superior de la imagen. He intentado usar PorterDuff.Modo.MULTIPLIQUE, y funciona casi exactamente lo que yo necesito, excepto que los blancos obtener superpuestas con el color así. Lo que estoy idealmente buscando es algo como el «Color» modo de fusión en Photoshop, donde el gráfico conserva su transparencia y luminosidad, y sólo modifica el color de la imagen. Por ejemplo:

Comprensión del Uso de ColorMatrix y ColorMatrixColorFilter para Modificar un objeto Dibujable el Tono

Después de hacer algunas investigaciones, parece que la ColorMatrixColorFilter clase puede hacer lo que necesito, pero me parece que no puede encontrar cualquiera de los recursos, señalando cómo la matriz se utiliza. Es una matriz de 4×5, pero lo que necesito saber es cómo voy sobre el diseño de la matriz. Alguna idea?

EDIT: Lo bueno, lo que he encontrado hasta el momento en que esto es como sigue:

1 0 0 0 0 //red
0 1 0 0 0 //green
0 0 1 0 0 //blue
0 0 0 1 0 //alpha

Donde esta matriz es la matriz de identidad (cuando se aplica, no hace ningún cambio), y los números en el rango de 0 a 1 (flotadores). Esta matriz se multiplica con cada píxel a convertir en el nuevo color. Así que esto es donde empieza a ser borroso para mí. Así que yo creo que sería cada pixel de 1 x 4 vector que contiene los argb de valores (por ejemplo,0.2, 0.5, 0.8, 1) que sería de puntos con la matriz de transformación. Así que el doble de la intensidad del rojo de una imagen, se utiliza una matriz tales como:

2 0 0 0 0 
0 1 0 0 0 
0 0 1 0 0 
0 0 0 1 0 

lo que le daría un vector (de color) de 0.4, 0.5, 0.8, 1. De la limitación de las pruebas, este parece ser el caso, y funciona correctamente, pero en realidad yo todavía terminan con el mismo problema (es decir, los blancos de ganancia para colorear). Seguir leyendo me dice que esto es porque está haciendo la conversión en valores RGB, mientras que para el tono cambio, los valores deben primero ser convertidos a valores HSL. Así que, posiblemente, podría escribir una clase que lea la imagen y convertir los colores, y volver a dibujar la imagen con los nuevos colores. Esto crea OTRO problema con StateListDrawables, como no estoy seguro de cómo iba a ir sobre cómo obtener cada uno de estos en el código y en la modificación de todos ellos, y la lentitud de un proceso que sería. :/

Hmm, bueno, así que supongo que otra pregunta que me gustaría tener es si una matriz se puede utilizar para convertir de RGB a otro espacio de color con la luminosidad de la información, tales como Lunb o HSL? Si es así, me podría multiplicar la matriz para que converstion, a continuación, hacer el ajuste de tono a QUE la matriz, a continuación, aplicar dicha matriz como la ColorFilter.

InformationsquelleAutor kcoppock | 2010-12-04

8 Comentarios

  1. 73

    Esto es lo que yo uso para mi juego. Esta es la recopilación de varias partes se encuentran en diversos artículos en las páginas web. Créditos va para el autor original de la @ver los enlaces.
    Tenga en cuenta que mucho más se puede hacer con matrices de color. Incluyendo la inversión, etc…

    public class ColorFilterGenerator
    {
    /**
    * Creates a HUE ajustment ColorFilter
    * @see http://groups.google.com/group/android-developers/browse_thread/thread/9e215c83c3819953
    * @see http://gskinner.com/blog/archives/2007/12/colormatrix_cla.html
    * @param value degrees to shift the hue.
    * @return
    */
    public static ColorFilter adjustHue( float value )
    {
    ColorMatrix cm = new ColorMatrix();
    adjustHue(cm, value);
    return new ColorMatrixColorFilter(cm);
    }
    /**
    * @see http://groups.google.com/group/android-developers/browse_thread/thread/9e215c83c3819953
    * @see http://gskinner.com/blog/archives/2007/12/colormatrix_cla.html
    * @param cm
    * @param value
    */
    public static void adjustHue(ColorMatrix cm, float value)
    {
    value = cleanValue(value, 180f) / 180f * (float) Math.PI;
    if (value == 0)
    {
    return;
    }
    float cosVal = (float) Math.cos(value);
    float sinVal = (float) Math.sin(value);
    float lumR = 0.213f;
    float lumG = 0.715f;
    float lumB = 0.072f;
    float[] mat = new float[]
    { 
    lumR + cosVal * (1 - lumR) + sinVal * (-lumR), lumG + cosVal * (-lumG) + sinVal * (-lumG), lumB + cosVal * (-lumB) + sinVal * (1 - lumB), 0, 0, 
    lumR + cosVal * (-lumR) + sinVal * (0.143f), lumG + cosVal * (1 - lumG) + sinVal * (0.140f), lumB + cosVal * (-lumB) + sinVal * (-0.283f), 0, 0,
    lumR + cosVal * (-lumR) + sinVal * (-(1 - lumR)), lumG + cosVal * (-lumG) + sinVal * (lumG), lumB + cosVal * (1 - lumB) + sinVal * (lumB), 0, 0, 
    0f, 0f, 0f, 1f, 0f, 
    0f, 0f, 0f, 0f, 1f };
    cm.postConcat(new ColorMatrix(mat));
    }
    protected static float cleanValue(float p_val, float p_limit)
    {
    return Math.min(p_limit, Math.max(-p_limit, p_val));
    }
    }

    Para completar esto debo agregar un ejemplo:

    ImageView Sun = (ImageView)findViewById(R.id.sun);
    Sun.setColorFilter(ColorFilterGenerator.adjustHue(162)); //162 degree rotation
    • Wow, gracias! No voy a pretender que entender exactamente lo que está pasando con los valores de la matriz, pero tengo curiosidad, ¿qué hace el cleanValue() método de hacer?
    • se asegura de no salir de obligado y causar artefactos.
    • Gracias!! Funciona perfecto!
    • Puede usted explicar por qué la matriz mat en el código tiene 5 filas? ¿No debería ser de 4 filas sólo (uno para cada R G B a)?
    • OK yo tengo, es para permitir que la matriz de concatenación, ¿no? Me corrija si estoy equivocado.
    • Después de mirar el código fuente de ColorMatrix, yo la tome de la espalda. La última fila en mat nunca se utiliza en absoluto. El ColorMatrix constructor toma solo las primeras 4 filas (copias de los primeros 20 carrozas de la fuente dada la matriz).
    • Volví a visitar uno de los enlaces y encuentra que la última columna es en realidad un desplazamiento. Vea Aquí Cómo Funciona en el siguiente link: code.tutsplus.com/tutorials/…
    • También, creo que la fuente original de la que el código era incorrecto. La 5ª fila, probablemente puede ser llevado a cabo desde la clase realmente sólo necesita 4 de acuerdo a la documentación: developer.android.com/reference/android/graphics/…. No tengo el proyecto en la mano así que si alguien está dispuesto a probar sin el último de la fila, por favor, comparta los resultados de vuelta por aquí.
    • Acabo de probar sin la 5ª fila y los resultados parecen ser el mismo.
    • Dulce Miguel. Gracias por la actualización de nosotros.
    • Me canse de tu código, haciendo de la misma clase y setColorFilter como usted menciona. Pero nada me funciona. Mi imagen es lo mismo 🙁
    • Yo estaba probé en la Imagen Transparente es por eso que el color de la imagen no cambia, pero cuando lo probé en una Imagen Roja su color convertir en Verde. Así, Es que no funciona en el caso de la transparencia de la Imagen ? Y por qué pasar exactamente «162» en el método de Ajuste de tono ?
    • 162 es el número de grados de un determinado matiz de rotación. Usted debe ajustar este número para que se ajuste a sus necesidades.
    • ¿Cómo le factor en un color existente en el ejemplo anterior supongamos que queremos generar un ColorFilter para el color, #FF6600 con un tono de 110?
    • Puede usted por favor mencione los documentos para la mejor comprensión de los números y de la fórmula que han utilizado? thannks
    • ¿cuáles son flotador lumR = 0.213 f; float lumG = 0.715 f; float lumB = 0.072 f; y ¿por qué han elegido los valores ?

  2. 40

    aquí está el código completo si desea ajustar el brillo, contraste, saturación y tono. ¡A disfrutar!
    Muchas gracias a @RichardLalancette

    public class ColorFilterGenerator {
    private static double DELTA_INDEX[] = {
    0,    0.01, 0.02, 0.04, 0.05, 0.06, 0.07, 0.08, 0.1,  0.11,
    0.12, 0.14, 0.15, 0.16, 0.17, 0.18, 0.20, 0.21, 0.22, 0.24,
    0.25, 0.27, 0.28, 0.30, 0.32, 0.34, 0.36, 0.38, 0.40, 0.42,
    0.44, 0.46, 0.48, 0.5,  0.53, 0.56, 0.59, 0.62, 0.65, 0.68, 
    0.71, 0.74, 0.77, 0.80, 0.83, 0.86, 0.89, 0.92, 0.95, 0.98,
    1.0,  1.06, 1.12, 1.18, 1.24, 1.30, 1.36, 1.42, 1.48, 1.54,
    1.60, 1.66, 1.72, 1.78, 1.84, 1.90, 1.96, 2.0,  2.12, 2.25, 
    2.37, 2.50, 2.62, 2.75, 2.87, 3.0,  3.2,  3.4,  3.6,  3.8,
    4.0,  4.3,  4.7,  4.9,  5.0,  5.5,  6.0,  6.5,  6.8,  7.0,
    7.3,  7.5,  7.8,  8.0,  8.4,  8.7,  9.0,  9.4,  9.6,  9.8, 
    10.0
    };
    /**
    * @see http://groups.google.com/group/android-developers/browse_thread/thread/9e215c83c3819953
    * @see http://gskinner.com/blog/archives/2007/12/colormatrix_cla.html
    * @param cm
    * @param value
    */
    public static void adjustHue(ColorMatrix cm, float value)
    {
    value = cleanValue(value, 180f) / 180f * (float) Math.PI;
    if (value == 0){
    return;
    }
    float cosVal = (float) Math.cos(value);
    float sinVal = (float) Math.sin(value);
    float lumR = 0.213f;
    float lumG = 0.715f;
    float lumB = 0.072f;
    float[] mat = new float[]
    { 
    lumR + cosVal * (1 - lumR) + sinVal * (-lumR), lumG + cosVal * (-lumG) + sinVal * (-lumG), lumB + cosVal * (-lumB) + sinVal * (1 - lumB), 0, 0, 
    lumR + cosVal * (-lumR) + sinVal * (0.143f), lumG + cosVal * (1 - lumG) + sinVal * (0.140f), lumB + cosVal * (-lumB) + sinVal * (-0.283f), 0, 0,
    lumR + cosVal * (-lumR) + sinVal * (-(1 - lumR)), lumG + cosVal * (-lumG) + sinVal * (lumG), lumB + cosVal * (1 - lumB) + sinVal * (lumB), 0, 0, 
    0f, 0f, 0f, 1f, 0f, 
    0f, 0f, 0f, 0f, 1f };
    cm.postConcat(new ColorMatrix(mat));
    }
    public static void adjustBrightness(ColorMatrix cm, float value) {
    value = cleanValue(value,100);
    if (value == 0) {
    return;
    }
    float[] mat = new float[]
    { 
    1,0,0,0,value,
    0,1,0,0,value,
    0,0,1,0,value,
    0,0,0,1,0,
    0,0,0,0,1
    };
    cm.postConcat(new ColorMatrix(mat));
    }
    public static void adjustContrast(ColorMatrix cm, int value) {
    value = (int)cleanValue(value,100);
    if (value == 0) { 
    return; 
    }
    float x;
    if (value < 0) {
    x = 127 + (float) value / 100*127;
    } else {
    x = value % 1;
    if (x == 0) {
    x = (float)DELTA_INDEX[value];
    } else {
    //x = DELTA_INDEX[(p_val<<0)]; //this is how the IDE does it.
    x = (float)DELTA_INDEX[(value<<0)]*(1-x) + (float)DELTA_INDEX[(value<<0)+1] * x; //use linear interpolation for more granularity.
    }
    x = x*127+127;
    }
    float[] mat = new float[]
    { 
    x/127,0,0,0, 0.5f*(127-x),
    0,x/127,0,0, 0.5f*(127-x),
    0,0,x/127,0, 0.5f*(127-x),
    0,0,0,1,0,
    0,0,0,0,1
    };
    cm.postConcat(new ColorMatrix(mat));
    }
    public static void adjustSaturation(ColorMatrix cm, float value) {
    value = cleanValue(value,100);
    if (value == 0) {
    return;
    }
    float x = 1+((value > 0) ? 3 * value / 100 : value / 100);
    float lumR = 0.3086f;
    float lumG = 0.6094f;
    float lumB = 0.0820f;
    float[] mat = new float[]
    { 
    lumR*(1-x)+x,lumG*(1-x),lumB*(1-x),0,0,
    lumR*(1-x),lumG*(1-x)+x,lumB*(1-x),0,0,
    lumR*(1-x),lumG*(1-x),lumB*(1-x)+x,0,0,
    0,0,0,1,0,
    0,0,0,0,1
    };
    cm.postConcat(new ColorMatrix(mat));
    }
    protected static float cleanValue(float p_val, float p_limit)
    {
    return Math.min(p_limit, Math.max(-p_limit, p_val));
    }
    public static ColorFilter adjustColor(int brightness, int contrast, int saturation, int hue){
    ColorMatrix cm = new ColorMatrix();
    adjustHue(cm, hue);
    adjustContrast(cm, contrast);
    adjustBrightness(cm, brightness);
    adjustSaturation(cm, saturation);
    return new ColorMatrixColorFilter(cm);
    }
    }
    • Muy bonito, gracias! 🙂
    • Está disponible para cambiar la saturación de un solo color (azul)?
    • «el valor de<<0» es el mismo «valor»
    • Gracias por una valiosa código. Dos comentarios con respecto a su adjustContrast método: (1) la expresión value<<0 parece redundante, ya que siempre sería igual a (solo) value. (2) Como value es un número entero, no value % 1 ser siempre igual a 0?
  3. 11

    Para cualquiera que esté interesado en cómo utilizar el ColorMatrixColorFilter. La muestra que se utiliza aquí, convertidos cada uno de los píxeles en color rojo cuando me dibujar el mapa de bits en el lienzo.

    El comentario en la clase es de: http://developer.android.com/reference/android/graphics/ColorMatrix.html esto le da algunas ideas sobre cómo esto está funcionando

    @Override
    protected void onDraw(Canvas canvas) {
    //The matrix is stored in a single array, and its 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 (after clamping) ;
    //  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; 
    Paint paint = new Paint();
    float[] matrix = { 
    1, 1, 1, 1, 1, //red
    0, 0, 0, 0, 0, //green
    0, 0, 0, 0, 0, //blue
    1, 1, 1, 1, 1 //alpha
    };
    paint.setColorFilter(new ColorMatrixColorFilter(matrix));
    Rect source = new Rect(0, 0, 100, 100);
    Rect dest = new Rect(0, 0, 100, 100);
    Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.sampleimage);
    canvas.drawBitmap(bitmap , source, dest, paint);
    }
  4. 8

    No hay una relación lineal entre la saturación y RGB. El tono es definida a trozos en 60° trozos (http://en.wikipedia.org/wiki/HSL_color_space#General_approach), y por lo tanto no es una simple conversión de la matriz entre HSV y RGB.
    Para cambiar el tono de una imagen, puede utilizar el siguiente método :

    public Bitmap changeHue( Bitmap source, double hue ) {
    Bitmap result = Bitmap.createBitmap( source.getWidth(), source.getHeight(), source.getConfig() );
    float[] hsv = new float[3];
    for( int x = 0; x < source.getWidth(); x++ ) {
    for( int y = 0; y < source.getHeight(); y++ ) {
    int c = source.getPixel( x, y );
    Color.colorToHSV( c, hsv );
    hsv[0] = (float) ((hsv[0] + 360 * hue) % 360);
    c = (Color.HSVToColor( hsv ) & 0x00ffffff) | (c & 0xff000000);
    result.setPixel( x, y, c );
    }
    }
    return result;
    }
  5. 7

    Creo que este método le dará lo que usted desea:

    http://android.okhelp.cz/hue-color-colored-filter-bitmap-image-android-example/

    bitmapOrg.setColorFilter(Color.RED, PorterDuff.Mode.MULTIPLY);
    • A tenga en cuenta que este método no va a cambiar el tono de la misma manera como la ColorFilterGenerator métodos que se muestran arriba. A ver lo que se puede producir abrir el mapa de bits en Photoshop o GIMP. Crear una capa por encima de la parte superior de la imagen y rellenar con el color deseado. A continuación, establezca el modo de capa superposición de multiplicar. Se el modo de capa a tono para una vista previa de lo que el ColorFilterGenerator métodos de hacer.
  6. 5

    Al igual que el resto de las respuestas que utiliza una matriz de color para implementar este comportamiento, pero puede pasar en un Android de color de los recursos. La matriz, se asigna el color en un rango entre el valor de imagen y de color blanco.

    /**
    * Color everything that isn't white, the tint color
    * @param tintColor the color to tint the icon
    */
    public void setInverseMultiplyFilter(Drawable imgCopy, @ColorInt int tintColor) {
    Drawable imgCopy = imageView.getDrawable().getConstantState().newDrawable();
    float colorRed = Color.red(tintColor) / 255f;
    float colorGreen = Color.green(tintColor) / 255f;
    float colorBlue = Color.blue(tintColor) / 255f;
    imgCopy.setColorFilter(new ColorMatrixColorFilter(new ColorMatrix(new float[]{
    1 - colorRed, 0,              0,             0,     colorRed * 255,
    0,            1 - colorGreen, 0,             0,     colorGreen * 255,
    0,            0,              1 - colorBlue, 0,     colorBlue * 255,
    0,            0,              0,             Color.alpha(tintColor) / 255f, 0,
    })));
    imageView.setImageDrawable(imgCopy);
    imageView.invalidate();
    }
    • Hola Benjamin, mediante el uso de arriba de la matriz podemos teñir todo excepto el Verde ?. Y también podemos combinar más de un color para ser conservado ? ejemplo de preservar el blanco y el verde, el tono resto. Por favor, su respuesta me ayudará
  7. 2

    Me hizo un poco ColorMatrixFilter probador, con base en el siguiente fragmento de código:

    private Bitmap setColorFilter(Bitmap drawable) {                
    Bitmap grayscale  = Bitmap.createBitmap(drawable.getWidth(), drawable.getHeight(), drawable.getConfig());
    //if(isRenderMode) bOriginal.recycle();
    Canvas c = new Canvas(grayscale );
    Paint p = new Paint();
    final ColorMatrix matrixA = new ColorMatrix();
    matrixA.setSaturation(sauturationValue/2);
    float[] mx = {
    r1Value,  r2Value,  r3Value,  r4Value,  r5Value,
    g1Value,  g2Value,  g3Value,  g4Value,  g5Value,
    b1Value,  b2Value,  b3Value,  b4Value,  b5Value,
    a1Value,  a2Value,  a3Value,  a4Value,  a5Value
    };
    final ColorMatrix matrixB = new ColorMatrix(mx);
    matrixA.setConcat(matrixB, matrixA);
    final ColorMatrixColorFilter filter = new ColorMatrixColorFilter(matrixA);
    p.setColorFilter(filter);
    c.drawBitmap(drawable, 0, 0, p);
    return grayscale;               
    } 

    Usted puede ver aquí:
    https://play.google.com/store/apps/details?id=org.vaelostudio.colormatrixtester

  8. 1

    A pesar de que un montón de efectos útiles que se puede lograr mediante el uso de la ColorMatrix yo personalmente podría considerar el uso de un ColorMap[] junto con ImageAttributes. Al hacer esto, podemos definir que los colores deben ser reemplazados con la que los colores.

    • ¿Qué es un ColorMap? Yo creo que no hay tal clase disponibles en el estándar java/ android libs.

Dejar respuesta

Please enter your comment!
Please enter your name here