type
TRASGraphic =
class
(TBitmap)
public
procedure
LoadFromStream(Stream: TStream); override;
procedure
SaveToStream(Stream: TStream); override;
end
;
//定義描述RAS文件頭的記錄類型
TRASHeader =
packed
record
Magic,
//標(biāo)記
Width,
//寬
Height,
//高
Depth,
//色深
Length,
//圖像數(shù)據(jù)長度,可能會等于0
RasType,
//格式類型
MapType,
//調(diào)色板類型
MapLength:
Cardinal
;
//調(diào)色板數(shù)據(jù)長度
end
;
//定義一個用來描述RAS文件頭的記錄類型是非常必要的
const
//定義代表RAS所有類型的常量
RT_OLD =
0
;
RT_STANDARD =
1
;
RT_BYTE_ENCODED =
2
;
RT_FORMAT_RGB =
3
;
RT_FORMAT_TIFF =
4
;
RT_FORMAT_IFF =
5
;
RT_EXPERIMENTAL =
$FFFF
;
//定義代表調(diào)色板類型的常量
RMT_NONE =
0
;
//無調(diào)色板數(shù)據(jù)
RMT_EQUAL_RGB =
1
;
RMT_RAW =
2
;
{如果RAS的格式為RT_OLD,數(shù)據(jù)長度可能為0}
function
SwapLong(
const
Value:
Cardinal
):
Cardinal
;
asm
BSWAP EAX
//調(diào)用字節(jié)交換指令
end
;
//拋出異常,參數(shù)為具體的異常信息
procedure
RasError(
const
ErrorString:
String
);
begin
raise
EInvalidGraphic
.
Create(ErrorString);
end
;
{下面是實現(xiàn)部分的代碼。}
procedure
TRASGraphic
.
LoadFromStream(Stream: TStream);
var
Header: TRASHeader;
Row8: PByte;
Row24: PRGBTriple;
Row32: PRGBQuad;
PMap: PByte;
Y:
Integer
;
I:
Integer
;
MapReaded:
Boolean
;
Pal: TMaxLogPalette;
R,G,B:
array
[
0..255
]
of
Byte
;
ColorByte:
Byte
;
begin
with
Stream
do
begin
ReadBuffer(Header, SizeOf(Header));
//將文件頭數(shù)據(jù)讀取到記錄Header中
with
Header
do
begin
Width := SwapLong(Width);
Height := SwapLong(Height);
Depth := SwapLong(Depth);
Length := SwapLong(Length);
RASType := SwapLong(RASType);
MapType := SwapLong(MapType);
MapLength := SwapLong(MapLength);
end
;
//由于讀取數(shù)據(jù)的順序問題,這里需要調(diào)用上面的SwapLong改動順序。
if
(Header
.
Magic =
$956AA659
)
and
(Header
.
Width<>
0
)
and
(Header
.
Height<>
0
)
and
(Header
.
Depth
in
[
1
,
8
,
24
,
32
])
and
(Header
.
RasType
in
[RT_OLD,RT_STANDARD,RT_BYTE_ENCODED,RT_FORMAT_RGB])
then
begin
Width := Header
.
Width;
Height := Header
.
Height;
MapReaded :=
False
;
case
Header
.
Depth
of
1
:PixelFormat := pf1Bit;
8
:
begin
PixelFormat := pf8Bit;
case
Header
.
MapType
of
RMT_NONE:
begin
Pal
.
palVersion:=
$300
;
Pal
.
palNumEntries:=
256
;
for
I :=
0
to
255
do
begin
Pal
.
palPalEntry[I].peRed:=I;
Pal
.
palPalEntry[I].peGreen:=I;
Pal
.
palPalEntry[I].peBlue:=I;
Pal
.
palPalEntry[I].peFlags:=
0
;
end
;
Palette := CreatePalette(PLogPalette(@Pal)^);
//當(dāng)圖像色深為8位,而又不存在調(diào)色板信息時,創(chuàng)建一個8位的灰度調(diào)色板
end
;
RMT_EQUAL_RGB:
begin
if
(Header
.
MapLength =
3
*
256
)
then
begin
Pal
.
palVersion:=
$300
;
Pal
.
palNumEntries:=
256
;
ReadBuffer(R,
256
);
ReadBuffer(G,
256
);
ReadBuffer(B,
256
);
for
I :=
0
to
255
do
begin
Pal
.
palPalEntry[I].peRed:=R[I];
Pal
.
palPalEntry[I].peGreen:=G[I];
Pal
.
palPalEntry[I].peBlue:=B[I];
Pal
.
palPalEntry[I].peFlags:=
0
;
end
;
Palette := CreatePalette(PLogPalette(@Pal)^);
//讀取文件中的調(diào)色板信息
//相關(guān)調(diào)色板操作的API請查詢MSDN
end
else
RasError(調(diào)色板長度錯誤!);
MapReaded :=
True
;
end
;
RMT_RAW:
begin
RasError(不支持的文件格式!);
end
;
end
;
end
;
24
:PixelFormat := pf24Bit;
32
:
begin
PixelFormat := pf32Bit;
//
end
;
end
;
if
(
not
MapReaded)
and
(Header
.
MapLength>
0
)
then
begin
Position := Position + Header
.
MapLength;
end
;
//如果調(diào)色板長度不為0,而又未正確讀取相關(guān)信息時,跳過這一段數(shù)據(jù)
case
Header
.
Depth
of
8
:
begin
if
Header
.
RasType = RT_BYTE_ENCODED
then
begin
//ENCODE
//關(guān)于RLE壓縮的編碼解碼請自行查閱資料
RasError(不支持壓縮格式!);
end
else
begin
for
Y :=
0
to
Height-
1
do
begin
Row8:=ScanLine[Y];
ReadBuffer(Row8^,Width);
if
(Width
mod
2
)=
1
then
begin
Position := Position +
1
;
end
;
end
;
end
;
end
;
{end of 8Bit}
24
:
begin
case
Header
.
RasType
of
RT_OLD,
RT_STANDARD:
begin
for
Y :=
0
to
Height-
1
do
begin
Row24:=ScanLine[Y];
ReadBuffer(Row24^,Width*
3
);
if
(Width
mod
2
)=
1
then
begin
Position := Position +
1
;
end
;
end
;
end
;
RT_BYTE_ENCODED:
begin
//ENCODE
//關(guān)于RLE壓縮的編碼解碼請自行查閱資料
RasError(不支持壓縮格式!);
end
;
RT_FORMAT_RGB:
begin
for
Y :=
0
to
Height-
1
do
begin
Row24:=ScanLine[Y];
ReadBuffer(Row24^,Width*
3
);
for
I :=
0
to
Width-
1
do
begin
ColorByte := Row24^.rgbtRed;
Row24^.rgbtRed := Row24^.rgbtBlue;
Row24^.rgbtBlue := ColorByte;
Inc(Row24);
end
;
//當(dāng)為RT_FORMAT_RGB格式時,按RGB獲取數(shù)據(jù),這里需要交換R和B的值
if
(Width
mod
2
)=
1
then
begin
Position := Position +
1
;
end
;
end
;
end
;
{end of RT_FORMAT_RGB}
else
RasError(不支持的文件格式!);
end
;
end
;
{end of 24Bit}
32
:
begin
case
Header
.
RasType
of
RT_OLD,
RT_STANDARD:
begin
for
Y :=
0
to
Height-
1
do
begin
Row32:=ScanLine[Y];
ReadBuffer(Row32^,Width*
4
);
for
I :=
0
to
Width-
1
do
begin
ColorByte := Row32^.rgbReserved;
Row32^.rgbReserved := Row32^.rgbBlue;
Row32^.rgbBlue := Row32^.rgbGreen;
Row32^.rgbGreen := Row32^.rgbRed;
Row32^.rgbRed := ColorByte;
Inc(Row32);
end
;
//32位色時,需要調(diào)整讀取后數(shù)據(jù)的順序
end
;
end
;
RT_BYTE_ENCODED:
begin
//ENCODE
//關(guān)于RLE壓縮的編碼解碼請自行查閱資料
RasError(不支持壓縮格式!);
end
;
RT_FORMAT_RGB:
begin
For
Y :=
0
to
Height-
1
do
begin
Row32:=ScanLine[Y];
ReadBuffer(Row32^,Width*
4
);
for
I :=
0
to
Width-
1
do
begin
ColorByte := Row32^.rgbBlue;
Row32^.rgbBlue := Row32^.rgbReserved;
Row32^.rgbReserved := ColorByte;
ColorByte := Row32^.rgbGreen;
Row32^.rgbGreen := Row32^.rgbRed;
Row32^.rgbRed := ColorByte;
Inc(Row32);
end
;
//這里將順序調(diào)整和R和B值的交換的代碼進(jìn)行了合并
end
;
end
;
{end of RT_FORMAT_RGB}
else
RasError(不支持的文件格式!);
end
;
{end of 32Bit}
end
;
else
begin
FreeImage;
RasError(不支持的文件格式!);
end
;
end
;
end
else
RasError(不支持的文件格式!);
end
;
{end with}
end
;
{上面的代碼中多次出現(xiàn)如下代碼:
if
(Width
mod
2
)=
1
then
begin
Position := Position +
1
;
end
;