2012-05-18 11 views
8

Así que esto es lo que tengo para un efecto de estilo de viñeta en Android (la imagen es un mapa de bits):Vignette en Android

public void vignette() { 
    float radius = (float) (image.getWidth()/1.5); 
    RadialGradient gradient = new RadialGradient(image.getWidth()/2, image.getHeight()/2, radius, Color.TRANSPARENT, Color.BLACK, Shader.TileMode.CLAMP); 

    Canvas canvas = new Canvas(image); 
    canvas.drawARGB(1, 0, 0, 0); 

    final Paint paint = new Paint(); 
    paint.setAntiAlias(true); 
    paint.setColor(Color.BLACK); 
    paint.setShader(gradient); 

    final Rect rect = new Rect(0, 0, image.getWidth(), image.getHeight()); 
    final RectF rectf = new RectF(rect); 

    canvas.drawRect(rectf, paint); 

    paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); 
    canvas.drawBitmap(image, rect, rect, paint); 
} 

Este "obras" pero hay un par de problemas. En primer lugar, esto no es realmente una viñeta, es solo un degradado, por lo que puedes ver trozos del negro yendo casi hasta el centro en lugar de desviarse hacia los bordes.

El RadialGradient utilizado también solo permite establecer el radio de un círculo en lugar de una elipse. Una elipse podría hacer coincidir más efectivamente las dimensiones de una imagen no cuadrada que un círculo.

La calidad del degradado tampoco es excelente.

Estoy tratando de replicar el método vignetteImage de ImageMagick (me refiero específicamente a la versión de php). Tengo este código en PHP que produce el estilo de imagen que yo quiero:

$im = new IMagick('city.png'); 
$im->vignetteImage($width/1.5, 350, 20, 20); 

He intentado edificio ImageMagick con el NDK, pero no han tenido éxito en vincular adecuadamente las diversas bibliotecas de imágenes (que he construido solamente con éxito con soporte gif pero no png, jpeg o tiff).

También adjunté una imagen que compara los dos métodos que se muestran arriba. La imagen de la izquierda se generó con ImageMagick a través de php y la imagen de la derecha se generó utilizando el método que se muestra arriba para Android.

left: vignette from php/ImageMagick. right: vignette from Android using method shown above

+1

Tiene alguna solución para eso ... Si es así, ¿me puede proporcionarla? ..... ... Gracias – Kalpesh

+0

Hasta ahora la respuesta de geeknizer es la mejor que tengo. Aún no lo he probado ... llegar a eso esta mañana. – gregghz

+0

Un poco tarde pero, ¿tienes alguna solución para este problema? Es así, ¿podría proporcionar el código? ¡Me salvarás la vida si es así! @ greggory.hz – Sebastian

Respuesta

4

Si se fijan bien en la imagen a la izquierda, tf utiliza aumento exponencial de Alfa (transparencia) vs. imagen a la derecha que es muy lineal.

Claramente Shader.TitleMode.CLAMP es una función lineal. Lo que debe hacer en su lugar es usar RadialGradient(float x, float y, float radius, int[] colors, float[] positions, Shader.TileMode tile) para definir 10 o más puntos en la imagen con valores de color exponencialmente decrecientes (negro a transparente).

Como alternativa, puede hacer referencia galería fuente 3d de la galería de ICS http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android-apps/4.0.1_r1/com/android/gallery3d/photoeditor/filters/VignetteFilter.java?av=h

+0

Este parece ser el camino a seguir para obtener paseo de la linealidad del gradiente. Probablemente voy a tener que jugar con la matriz de colores para hacerlo bien. ¿Cómo afecta el conjunto de posiciones a todo el asunto? No estoy seguro de entender totalmente eso. Ahora si pudiera descubrir cómo hacer que sea una elipse ... – gregghz

1

Sé que esto es un debate antiguo, pero puede ayudar a alguien. Puede usar AccelerateInterpolator para generar los puntos que Taranfx había mencionado y se bloqueará increíble.