Конвертирование 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 шт):

Автор решения: Anton Shchyrov

Нашел решение.

Нужно создать второй битмап нужного формата, нарисовать первый на втором, а потом через 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;
→ Ссылка