Растровый объект C#, цвет выглядит прозрачным
Я работаю над программой на C#, которая делает скриншоты зелья на экране пользователя. По большей части это работает как надо, но я недавно столкнулся с одной проблемой. Кажется, что есть (по крайней мере) один пиксельный цвет, который всегда выглядит прозрачным в выходном изображении. Любой экземпляр цвета #0D0B0C (RGB 13, 11, 12) выглядит прозрачным в сохраненном png. Это с PixelFormat установлен в Format32bppArgb. Если я установлю его на Format32bppRgb или Format24bppRgb, тот же цвет пикселя будет выглядеть как черный в сохраненном png.
Я понятия не имею, что может быть причиной этого, но единственное, что я смог сделать, чтобы "исправить" это очистить графический объект от этого цвета перед выполнением CopyFromScreen(). Я не хочу этого делать по нескольким причинам. Во-первых, я не знаю, является ли это единственным цветом, который имеет проблему (у 16 777 216 цветов есть довольно много возможностей), и во-вторых, я ненавижу исправления взлома, это похоже на исправление взлома.
Может кто-нибудь пролить свет на то, что может быть причиной этой проблемы? Я перепутал с PixelFormat при создании растрового изображения и с CopyPixelOperation в методе CopyFromScreen, похоже, ничего не работает. Тот факт, что очистка графического объекта до этого цвета "исправляет", кажется, говорит мне, что прозрачность исходит от самих данных экрана, но это не имеет смысла. Я слишком долго смотрел на это, думаю, мне нужен свежий взгляд на это. Если у кого-то есть идея, почему это может происходить, я бы хотел это услышать. Спасибо.
4 ответа
Мне просто нужно было запросить CopyFromScreen в растровое изображение, которое вообще не имеет альфа-канала, например:
Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height, System.Drawing.Imaging.PixelFormat.Format32bppRgb);
Graphics graphics = Graphics.FromImage(bitmap as Image);
graphics.CopyFromScreen(bounds.Location, new Point(0, 0), bitmap.Size);
Я подтвердил, что у него есть прозрачные дыры в пикселях с Format32bppArgb, но не с Format32bppRgb
Значение альфа может быть 0? вы проверили?
Поскольку разница между Format32bppArgb и Format32bppRgb в том, что второй формат не знает альфа-канал.
Точно такая же проблема при отображении элемента управления в растровое изображение. Удалось исправить это, создав еще одно растровое изображение с PixelFormat.Format32bppRgb и добавив BitBlt к нему. Надеюсь это поможет!
public class ScreenCapture
{
[System.Runtime.InteropServices.DllImportAttribute("gdi32.dll")]
private static extern bool BitBlt(
IntPtr hdcDest, // handle to destination DC
int nXDest, // x-coord of destination upper-left corner
int nYDest, // y-coord of destination upper-left corner
int nWidth, // width of destination rectangle
int nHeight, // height of destination rectangle
IntPtr hdcSrc, // handle to source DC
int nXSrc, // x-coordinate of source upper-left corner
int nYSrc, // y-coordinate of source upper-left corner
System.Int32 dwRop // raster operation code
);
/// <summary>
/// Returns an image of the control
/// </summary>
/// <param name="control">The control object whose image is wanted</param>
/// <returns>Image of the control</returns>
/// <remarks>This is based on code from
/// http://www.dotnet247.com/247reference/a.aspx?u=http://www.c-sharpcorner.com/Code/2002/April/ScreenCaptureUtility.asp
/// with changes made to prevent 0D0B0C transparency issues</remarks>
public static Image GetControlImage(Control control)
{
Graphics g1 = control.CreateGraphics();
// Create a bitmap the same size as the control
Image MyImage = new Bitmap(control.ClientRectangle.Width, control.ClientRectangle.Height, PixelFormat.Format32bppRgb);
(MyImage as Bitmap).SetResolution(g1.DpiX, g1.DpiY);
Graphics g2 = Graphics.FromImage(MyImage);
IntPtr dc1 = g1.GetHdc();
IntPtr dc2 = g2.GetHdc();
// BitBlt from one DC to the other
BitBlt(dc2, 0, 0, control.ClientRectangle.Width, control.ClientRectangle.Height, dc1, 0, 0, 13369376);
// Release Device Contexts
g1.ReleaseHdc(dc1);
g2.ReleaseHdc(dc2);
// This statement runs the garbage collector manually
// (If not present, uses up large amounts of memory...)
GC.Collect();
return MyImage;
}
}