Идёт загрузка страницы...

htp://aptem.net.ru





Delphi 1

Изменение цветовой палитры изображения

Мне необходимо изменить цветовую палитру изображения с помощью 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 ;

- Mike Scott [000827]