Je travaille avec des images en Java, j'ai conçu plus de 100+ images (.png) au format, elles étaient toutes transparentes et dessin en couleur noire.
Le problème est, Maintenant, on m'a demandé de changer la couleur du dessin (noir à).
J'ai recherché de nombreux codes coupés sur google, qui modifient le bitmap (pixels) de l'image, mais je ne devine pas ce que je dois faire pour correspondre au pixel exact et remplacer spécialement lorsque les images sont en mode transparent. Ci-dessous le code en .Net (C #)
Bitmap newBitmap = new Bitmap(scrBitmap.Width, scrBitmap.Height);
for (int i = 0; i < scrBitmap.Width; i++)
{
for (int j = 0; j < scrBitmap.Height; j++)
{
originalColor = scrBitmap.GetPixel(i, j);
if(originalColor = Color.Black)
newBitmap.SetPixel(i, j, Color.Red);
}
}
return newBitmap;
mais il ne correspondait pas du tout, je l'ai débogué, tout au long du fichier, il n'y avait pas de valeur de paramètres Rouge, Vert, Bleu de la variable Couleur (originalColor).
Quelqu'un peut-il aider?
Voici la solution que j'ai faite avec les pixels.
Attacher le code source pour que l'on puisse essayer l'exact et obtenir le résultat.
J'ai des exemples d'images de 128x128 (largeur x hauteur).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.IO;
//using System.Globalization;
namespace colorchange
{
class Program
{
static void Main(string[] args)
{
try
{
Bitmap bmp = null;
//The Source Directory in debug\bin\Big\
string[] files = Directory.GetFiles("Big\\");
foreach (string filename in files)
{
bmp = (Bitmap)Image.FromFile(filename);
bmp = ChangeColor(bmp);
string[] spliter = filename.Split('\\');
//Destination Directory debug\bin\BigGreen\
bmp.Save("BigGreen\\" + spliter[1]);
}
}
catch (System.Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
public static Bitmap ChangeColor(Bitmap scrBitmap)
{
//You can change your new color here. Red,Green,LawnGreen any..
Color newColor = Color.Red;
Color actualColor;
//make an empty bitmap the same size as scrBitmap
Bitmap newBitmap = new Bitmap(scrBitmap.Width, scrBitmap.Height);
for (int i = 0; i < scrBitmap.Width; i++)
{
for (int j = 0; j < scrBitmap.Height; j++)
{
//get the pixel from the scrBitmap image
actualColor = scrBitmap.GetPixel(i, j);
// > 150 because.. Images edges can be of low pixel colr. if we set all pixel color to new then there will be no smoothness left.
if (actualColor.A > 150)
newBitmap.SetPixel(i, j, newColor);
else
newBitmap.SetPixel(i, j, actualColor);
}
}
return newBitmap;
}
}
}
// Ci-dessous l'image échantillon et différents résultats en appliquant des couleurs différentes
Les modifications du code seront très appréciées.
Avant de parler de performance, vérifions votre code:
var originalColor = scrBitmap.GetPixel(i, j);
if (originalColor = Color.Black)
newBitmap.SetPixel(i, j, Color.Red);
Ici, il y a deux erreurs:
Color.Black
Mais vous affectez Color.Black
À originalColor
.Pour vérifier la transparence, vous devez comparer non pas l'objet Color
mais les valeurs R, G, B, passons à:
var originalColor = scrBitmap.GetPixel(i, j);
if (originalColor.R == 0 && originalColor.G == 0 && originalColor.B == 0)
newBitmap.SetPixel(i, j, Color.FromArgb(originalColor.A, Color.Red));
Vous verrez maintenant que cela fonctionne, mais le traitement de chaque image prend beaucoup de temps: GetPixel
et SetPixel
sont assez lents (principaux car ils vérifient et calculent tout pour chaque appel). Il est préférable de gérer directement les données bitmap. Si vous connaissez le format d'image à l'avance (et qu'il est fixe pour chaque image), vous pouvez le faire beaucoup plus rapidement avec un peu plus de code:
static unsafe Bitmap ReplaceColor(Bitmap source,
Color toReplace,
Color replacement)
{
const int pixelSize = 4; // 32 bits per pixel
Bitmap target = new Bitmap(
source.Width,
source.Height,
PixelFormat.Format32bppArgb);
BitmapData sourceData = null, targetData = null;
try
{
sourceData = source.LockBits(
new Rectangle(0, 0, source.Width, source.Height),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
targetData = target.LockBits(
new Rectangle(0, 0, target.Width, target.Height),
ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
for (int y = 0; y < source.Height; ++y)
{
byte* sourceRow = (byte*)sourceData.Scan0 + (y * sourceData.Stride);
byte* targetRow = (byte*)targetData.Scan0 + (y * targetData.Stride);
for (int x = 0; x < source.Width; ++x)
{
byte b = sourceRow[x * pixelSize + 0];
byte g = sourceRow[x * pixelSize + 1];
byte r = sourceRow[x * pixelSize + 2];
byte a = sourceRow[x * pixelSize + 3];
if (toReplace.R == r && toReplace.G == g && toReplace.B == b)
{
r = replacement.R;
g = replacement.G;
b = replacement.B;
}
targetRow[x * pixelSize + 0] = b;
targetRow[x * pixelSize + 1] = g;
targetRow[x * pixelSize + 2] = r;
targetRow[x * pixelSize + 3] = a;
}
}
}
finally
{
if (sourceData != null)
source.UnlockBits(sourceData);
if (targetData != null)
target.UnlockBits(targetData);
}
return target;
}
Bien sûr, cela peut être optimisé et vous devrez peut-être gérer différents formats ( voir cette liste de formats de pixels et cet article à propos de leur disposition) mais considérez-le comme un point de départ pour travailler avec des bitmaps.
Pour être complet, il s'agit d'une couleur équivalente sans accès direct aux données bitmap. Veuillez noter que cela devrait être rarement utilisé car il est terriblement lent.
static Bitmap ReplaceColor(Bitmap source,
Color toReplace,
Color replacement)
{
var target = new Bitmap(source.Width, source.Height);
for (int x = 0; x < source.Width; ++x)
{
for (int y = 0; y < source.Height; ++y)
{
var color = source.GetPixel(x, y);
target.SetPixel(x, y, color == toReplace ? replacement : color);
}
}
return target;
}
Veuillez également noter que cela considère le canal alpha en comparaison (donc 50% de vert transparent, par exemple, n'est pas de la même couleur que 30% de vert transparent). Pour ignorer alpha, vous pouvez utiliser quelque chose comme ceci:
if (color.R == toReplace.R && color.G == toReplace.G && color.B == toReplace.B)
Enfin, si vous savez que les pixels à remplacer sont peu nombreux, vous pouvez créer une copie brute de l'image originale (en utilisant Graphics.FromImage
Pour créer un contexte et y dessiner source
bitmap), de cette manière vous ' ll n'appelle SetPixel()
qu'en cas de remplacement. IMO toute optimisation ici est assez inutile: si vous avez besoin de performances, utilisez la première solution ...
Une façon de remplacer efficacement une couleur est d'utiliser une table de remappage. Dans l'exemple suivant, une image est dessinée à l'intérieur d'une zone d'image. Dans l'événement Paint, la couleur Color.Black est remplacée par Color.Blue:
private void pictureBox_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
using (Bitmap bmp = new Bitmap("myImage.png"))
{
// Set the image attribute's color mappings
ColorMap[] colorMap = new ColorMap[1];
colorMap[0] = new ColorMap();
colorMap[0].OldColor = Color.Black;
colorMap[0].NewColor = Color.Blue;
ImageAttributes attr = new ImageAttributes();
attr.SetRemapTable(colorMap);
// Draw using the color map
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
g.DrawImage(bmp, rect, 0, 0, rect.Width, rect.Height, GraphicsUnit.Pixel, attr);
}
}
Plus d'informations: http://msdn.Microsoft.com/en-us/library/4b4dc1kz%28v=vs.110%29.aspx
Je vais vous donner une autre solution car cela ne calcule pas pour chaque pixel.
C'est court et simple. Le temps de conversion est de 62 ms:
public Bitmap Color(Bitmap original)
{
//create a blank bitmap the same size as original
Bitmap newBitmap = new Bitmap(original.Width, original.Height);
//get a graphics object from the new Image
Graphics g = Graphics.FromImage(newBitmap);
//create the color you want ColorMatrix
//now is set to red, but with different values
//you can get anything you want.
ColorMatrix colorMatrix = new ColorMatrix(
new float[][]
{
new float[] {1f, .0f, .0f, 0, 0},
new float[] {1f, .0f, .0f, 0, 0},
new float[] {1f, .0f, .0f, 0, 0},
new float[] {0, 0, 0, 1, 0},
new float[] {0, 0, 0, 0, 1}
});
//create some image attributes
ImageAttributes attributes = new ImageAttributes();
//set the color matrix attribute
attributes.SetColorMatrix(colorMatrix);
//draw original image on the new image using the color matrix
g.DrawImage(original, new Rectangle(0, 0, original.Width, original.Height),
0, 0, original.Width, original.Height, GraphicsUnit.Pixel, attributes);
//release sources used
g.Dispose();
return newBitmap;
}