Изменение цветовой палитры изображения
Мне необходимо изменить цветовую палитру изображения с помощью SetBitmapBits, но у меня, к сожалению, ничего не получается.
Использование SetBitmapBits - не очень хорошая идея, поскольку она имеет дело с HBitmaps, в котором формат пикселя не определен. Несомненно, это более безопасная операция, но никаких гарантий по ее выполнению дать невозможно.
Взамен я предлагаю использовать функции DIB API. Вот некоторый код, позволяющий вам изменять таблицу цветов. Просто напишите метод с такими же параметрами, как у TFiddleProc и и изменяйте ColorTable, передаваемое как параметр. Затем просто вызовите процедуру FiddleBitmap, передающую TBitmap и ваш fiddle-метод, например так:
FiddleBitmap( MyBitmap, Fiddler ) ;
type TFiddleProc = procedure(var ColorTable: TColorTable) of object; const LogPaletteSize = sizeof(TLogPalette) + sizeof(TPaletteEntry) * 255; function PaletteFromDIB(BitmapInfo: PBitmapInfo): HPalette; var LogPalette: PLogPalette; i: integer; Temp: byte; begin with BitmapInfo^, bmiHeader do begin GetMem(LogPalette, LogPaletteSize); try with LogPalette^ do begin palVersion := $300; palNumEntries := 256; Move(bmiColors, palPalEntry, sizeof(TRGBQuad) * 256); for i := 0 to 255 do with palPalEntry[i] do begin Temp := peBlue; peBlue := peRed; peRed := Temp; peFlags := PC_NOCOLLAPSE; end; { создаем палитру } Result := CreatePalette(LogPalette^); end; finally FreeMem(LogPalette, LogPaletteSize); end; end; end; { Следующая процедура на основе изображения создает DIB, изменяет ее таблицу цветов, создавая тем самым новую палитру, после чего передает ее обратно изображению. При этом используется метод косвенного вызова, с помощью которого изменяется палитра цветов - ей передается array[ 0..255 ] of TRGBQuad. } procedure FiddleBitmap(Bitmap: TBitmap; FiddleProc: TFiddleProc); const BitmapInfoSize = sizeof(TBitmapInfo) + sizeof(TRGBQuad) * 255; var BitmapInfo: PBitmapInfo; Pixels: pointer; InfoSize: integer; ADC: HDC; OldPalette: HPalette; begin { получаем DIB } GetMem(BitmapInfo, BitmapInfoSize); try { меняем таблицу цветов - ПРИМЕЧАНИЕ: она использует 256 цветов DIB } FillChar(BitmapInfo^, BitmapInfoSize, 0); with BitmapInfo^.bmiHeader do begin biSize := sizeof(TBitmapInfoHeader); biWidth := Bitmap.Width; biHeight := Bitmap.Height; biPlanes := 1; biBitCount := 8; biCompression := BI_RGB; biClrUsed := 256; biClrImportant := 256; GetDIBSizes(Bitmap.Handle, InfoSize, biSizeImage); { распределяем место для пикселей } Pixels := GlobalAllocPtr(GMEM_MOVEABLE, biSizeImage); try { получаем пиксели DIB } ADC := GetDC(0); try OldPalette := SelectPalette(ADC, Bitmap.Palette, false); try RealizePalette(ADC); GetDIBits(ADC, Bitmap.Handle, 0, biHeight, Pixels, BitmapInfo^, DIB_RGB_COLORS); finally SelectPalette(ADC, OldPalette, true); end; finally ReleaseDC(0, ADC); end; { теперь изменяем таблицу цветов } FiddleProc(PColorTable(@BitmapInfo^.bmiColors)^); { создаем палитру на основе новой таблицы цветов } Bitmap.Palette := PaletteFromDIB(BitmapInfo); OldPalette := SelectPalette(Bitmap.Canvas.Handle, Bitmap.Palette, false); try RealizePalette(Bitmap.Canvas.Handle); StretchDIBits(Bitmap.Canvas.Handle, 0, 0, biWidth, biHeight, 0, 0, biWidth, biHeight, Pixels, BitmapInfo^, DIB_RGB_COLORS, SRCCOPY); finally SelectPalette(Bitmap.Canvas.Handle, OldPalette, true); end; finally GlobalFreePtr(Pixels); end; end; finally FreeMem(BitmapInfo, BitmapInfoSize); end; end; { Пример "fiddle"-метода } procedure TForm1.Fiddler(var ColorTable: TColorTable); var i: integer; begin for i := 0 to 255 do with ColorTable[i] do begin rgbRed := rgbRed * 9 div 10; rgbGreen := rgbGreen * 9 div 10; rgbBlue := rgbBlue * 9 div 10; end; end;
Взято с https://delphiworld.narod.ru