才談得perfromance讓我們來檢查你的代碼:
var originalColor = scrBitmap.GetPixel(i, j);
if (originalColor = Color.Black)
newBitmap.SetPixel(i, j, Color.Red);
在這裏有兩個誤區:
- 你不比較
Color.Black
但你分配Color.Black
到originalColor
。
- 您不處理透明度。
要檢查的透明度,你應該比較不Color
對象,但R,G,B值,讓我們更改爲:
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));
現在你會看到它的工作原理,但它需要一個很長時間處理每個圖像:GetPixel
和SetPixel
是相當緩慢(主要是因爲他們檢查並計算每個電話的一切)。直接處理位圖數據要好得多。如果你事先知道圖像格式(和它的固定每幅圖像),那麼你可以用多一點的代碼做要快得多:
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;
}
當然,這可能是further optimized,你可能需要處理不同格式(有關其佈局的see this list of pixel formats和this article),但認爲它是使用位圖的起點。
爲了完整起見,這是等效的顏色,不能直接訪問位圖數據。請注意,這應該很少使用,因爲它非常緩慢。
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;
}
另外請注意,這比較考慮alpha通道(例如50%透明綠色,與30%透明綠色不同)。要忽略阿爾法你可以使用這樣的事情:
if (color.R == toReplace.R && color.G == toReplace.G && color.B == toReplace.B)
最後,如果你知道像素替換是一點,你就可以創建原始圖像的原始拷貝(使用Graphics.FromImage
創建上下文,並吸引到它source
位圖),這樣你只有在有替換時纔會撥打SetPixel()
。 IMO在這裏的任何優化都是無用的:如果你需要性能使用第一個解決方案...
這是最好的答覆,我相信我的要求滿足,感謝DareDevil –
那麼這將取代每個顏色到新的(不只是一個選定的),並檢查alpha將產生次優結果,如果有梯度,但如果它滿足OP ... :) –
以及此代碼適用於單一顏色的圖像。 – DareDevil