Конвертирование RGB битмапа в RGBA
Есть у меня 24 битный RGB битмап (PixelFormat = PixelFormat24bppRGB). Я хочу его сконвертировать в PixelFormat32bppARGB, причем, чтобы определенный цвет (пускай [R: 0, G: 0x7F, B: 0xFF]) стал прозрачным. Как это сделать?
Я думал вызвать GdipInitializePalette() и передать в нее useTransparentColor = true, а потом вызвать GdipBitmapConvertFormat() и сконвертировать в PixelFormat32bppARGB. Но по-моему это путь в никуда. Я не понимаю, где этот прозрачный цвет искать в палитре.
Еще вариант - это вызвать GdipBitmapLockBits() с PixelFormat = PixelFormat32bppARGB, самому понаходить точки с нужным цветом, и спросить им альфа-канал в 0. Но сам битмап в объекте станется же 24 битным и моя установка альфа-канала проигнорируется.
If the pixel format of the temporary buffer is different from the pixel format of the Bitmap object, the pixel data is converted appropriately.
Ответы (1 шт):
Нашел решение.
Нужно создать второй битмап нужного формата, нарисовать первый на втором, а потом через GdipBitmapLockBits отредактировать нужные точки
Код на Делфи, но на Си он такой же
procedure ClearColor(ABitmap: GpBitmap; const ARect: GDIPAPI.TRect; AColor: ARGB);
var
LData: BitmapData;
Li, Lj: Integer;
LARGB: PARGB;
LNewColor: ARGB;
begin
GPCheck(GdipBitmapLockBits(ABitmap, @ARect,
ImageLockModeRead or ImageLockModeWrite, PixelFormat32bppARGB, @LData));
try
// Устанавливаем значение альфа-канала в 0
LNewColor := AColor and not ALPHA_MASK;
// пробегаемся по всем точкам
for Li := 0 to ARect.Height - 1 do begin
LARGB := PARGB(UINT_PTR(LData.Scan0) + Li * LData.Stride);
for Lj := 0 to ARect.Width - 1 do begin
// если точка нужного цвета
if LARGB^ = AColor then
LARGB^ := LNewColor; // заменяем ее цвет
Inc(LARGB);
end;
end;
finally
GPCheck(GdipBitmapUnlockBits(ABitmap, @LData))
end;
end;
procedure TForm1.Button3Click(Sender: TObject);
var
LSrcImg: GpImage;
LDstBmp: GpBitmap;
LGraphics: GpGraphics;
LPen: GpPen;
LFmt: PixelFormat;
LWidth, LHeight: Cardinal;
LGPRect: GDIPAPI.TRect;
LPngEncoder: TGUID;
begin
// Загружаем битмап из файла
GPCheck(GdipCreateBitmapFromFile(CFileName, LSrcImg));
try
GPCheck(GdipGetImageWidth(LSrcImg, LWidth));
GPCheck(GdipGetImageHeight(LSrcImg, LHeight));
// Создаем новый битмап нужного формата
GPCheck(GdipCreateBitmapFromScan0(
LWidth,
LHeight,
0,
PixelFormat32bppARGB,
nil,
LDstBmp
));
try
GPCheck(GdipGetImageGraphicsContext(LDstBmp, LGraphics));
try
// Рисуем первый битмап на втором
GPCheck(GdipDrawImageI(LGraphics, LSrcImg, 0, 0));
GPCheck(GdipGetImagePixelFormat(LSrcImg, LFmt));
// Если исходный битмап без альфа-канала
if LFmt and PixelFormatAlpha = 0 then begin
LGPRect.X := 0;
LGPRect.Y := 0;
LGPRect.Width := LWidth;
LGPRect.Height := LHeight;
// Очищаем нужный цвет
ClearColor(LDstBmp, LGPRect, MakeColor(0, $7f, $ff));
end;
finally
GPCheck(GdipDeleteGraphics(LGraphics));
end;
// Сохраняем полученный битмап как png
LPngEncoder := GetGDIpEncoder('image/png');
GPCheck(GdipSaveImageToFile(LDstBmp, CFileNameNew, @LPngEncoder, nil));
finally
GPCheck(GdipDisposeImage(LDstBmp));
end;
finally
GPCheck(GdipDisposeImage(LSrcImg));
end;
end;