2012-03-17 37 views
7

En Photoshop puede seleccionar "Color" (la segunda desde la parte inferior) para establecer el modo de fusión a la siguiente capa inferior:imagen Drenaje en la parte superior de otra imagen con la mezcla de color modo

Layer blending mode selection photoshop

Si usted tiene sólo un gradiente en la parte superior de una imagen, el resultado podría tener este aspecto:

Color blending example

la descripción del modo de mezcla de colores que encontré en alguna parte es:

El color cambia el tono y la saturación de la capa inferior al tono y la saturación de la capa superior, pero deja solo la luminosidad.

Mi código hasta ahora es:

using(var g = Graphics.FromImage(canvas)) 
{ 
    // draw the lower image 
    g.DrawImage(lowerImg, left, top); 

    // creating a gradient and draw on top 
    using (Brush brush = new LinearGradientBrush(new Rectangle(0, 0, canvasWidth, canvasHeight), Color.Violet, Color.Red, 20)) 
    { 
     g.FillRectangle(brush, 0, 0, canvasWidth, canvasHeight); 
    } 
} 

Pero eso es - por supuesto - sólo pintura sobre la imagen inferior.

Así que la pregunta es:

¿Cómo puedo sacar yo una imagen sobre otra imagen utilizando el modo de fusión "color" como está disponible en Photoshop?

EDIT:

para que sea un poco más clara de lo que quiero lograr:

enter image description here

Y si alguien quiere usar las imágenes para las pruebas:

enter image description here enter image description here

+0

Es necesario hacer algunos cálculos de color. Desearía tener tiempo para hacer eso y publicar una respuesta, ¡pero lo siento mucho! Tal vez esta noche :) –

+0

Eso no es un problema Tengo muchas otras cosas que hacer y puedo esperar por esto por un día, así que si quieres, siéntete libre de hacerlo, sería muy agradable :) Estoy bastante mal/nuevo al procesamiento de imágenes. – Marc

+0

¡Claro! Me encanta hacer este tipo de cosas;) –

Respuesta

6

Aquí está mi solución. Utilicé la clase HSLColor de Rich Newman para convertir valores RGB y HSL.

using (Bitmap lower = new Bitmap("lower.png")) 
using (Bitmap upper = new Bitmap("upper.png")) 
using (Bitmap output = new Bitmap(lower.Width, lower.Height)) 
{ 
    int width = lower.Width; 
    int height = lower.Height; 
    var rect = new Rectangle(0, 0, width, height); 

    BitmapData lowerData = lower.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); 
    BitmapData upperData = upper.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); 
    BitmapData outputData = output.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb); 

    unsafe 
    { 
     byte* lowerPointer = (byte*) lowerData.Scan0; 
     byte* upperPointer = (byte*) upperData.Scan0; 
     byte* outputPointer = (byte*) outputData.Scan0; 

     for (int i = 0; i < height; i++) 
     { 
      for (int j = 0; j < width; j++) 
      { 
       HSLColor lowerColor = new HSLColor(lowerPointer[2], lowerPointer[1], lowerPointer[0]); 
       HSLColor upperColor = new HSLColor(upperPointer[2], upperPointer[1], upperPointer[0]); 
       upperColor.Luminosity = lowerColor.Luminosity; 
       Color outputColor = (Color) upperColor; 

       outputPointer[0] = outputColor.B; 
       outputPointer[1] = outputColor.G; 
       outputPointer[2] = outputColor.R; 

       // Moving the pointers by 3 bytes per pixel 
       lowerPointer += 3; 
       upperPointer += 3; 
       outputPointer += 3; 
      } 

      // Moving the pointers to the next pixel row 
      lowerPointer += lowerData.Stride - (width * 3); 
      upperPointer += upperData.Stride - (width * 3); 
      outputPointer += outputData.Stride - (width * 3); 
     } 
    } 

    lower.UnlockBits(lowerData); 
    upper.UnlockBits(upperData); 
    output.UnlockBits(outputData); 

    // Drawing the output image 
} 
+0

Mejor que la respuesta que quería publicar. Solo necesita un poco de pulido. Es mejor hacerlo un método con interfaz definida. Y también deben considerarse las situaciones que proporcionaron imágenes que no son del mismo tamaño. –

+0

+1 y aceptar - Whoa, increíble, funciona como un encanto! ¡Muchas gracias! ¡Ojalá pudiera votar esto 10 veces! – Marc

0

Tendrá que reestructurar su código para que dibuje su degradado en un mapa de bits temporal, lea cada píxel del mapa de bits y lienzo temporal, y escriba un píxel compuesto en lienzo. Debería poder encontrar la conversión de código entre los colores RGB y HSL, y una vez que puede hacerlo, establecer el tono y la saturación de los píxeles en el lienzo de los valores de su mapa de bits temporal es trivial (aunque es un poco más difícil si quiere usar valores alfa).

0

Aquí hay una versión segura (y más lenta) de la respuesta aceptada para completarla.

 using (var lower = new Bitmap(@"lower.png")) 
     using (var upper = new Bitmap(@"upper.png")) 
     using (var output = new Bitmap(lower.Width, lower.Height)) 
     { 
      var width = lower.Width; 
      var height = lower.Height; 

      for (var i = 0; i < height; i++) 
      { 
       for (var j = 0; j < width; j++) 
       { 
        var upperPixel = upper.GetPixel(j, i); 
        var lowerPixel = lower.GetPixel(j, i); 

        var lowerColor = new HSLColor(lowerPixel.R, lowerPixel.G, lowerPixel.B); 
        var upperColor = new HSLColor(upperPixel.R, upperPixel.G, upperPixel.B) {Luminosity = lowerColor.Luminosity}; 
        var outputColor = (Color)upperColor; 

        output.SetPixel(j, i, outputColor); 
       } 
      } 

      // Drawing the output image 
     } 
Cuestiones relacionadas