mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-30 15:13:43 +02:00
329 lines
7.7 KiB
ObjectPascal
329 lines
7.7 KiB
ObjectPascal
{
|
|
This file is part of the Free Pascal run time library.
|
|
Copyright (c) 2003 by the Free Pascal development team
|
|
|
|
XPM reader class.
|
|
|
|
See the file COPYING.FPC, included in this distribution,
|
|
for details about the copyright.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
**********************************************************************}
|
|
{$mode objfpc}{$h+}
|
|
unit FPReadXPM;
|
|
|
|
interface
|
|
|
|
uses FPImage, classes, sysutils;
|
|
|
|
type
|
|
TFPReaderXPM = class (TFPCustomImageReader)
|
|
private
|
|
width, height, ncols, cpp, xhot, yhot : integer;
|
|
xpmext : boolean;
|
|
palette : TStringList;
|
|
function HexToColor(s : string) : TFPColor;
|
|
function NameToColor(s : string) : TFPColor;
|
|
function DiminishWhiteSpace (s : string) : string;
|
|
protected
|
|
procedure InternalRead (Str:TStream; Img:TFPCustomImage); override;
|
|
function InternalCheck (Str:TStream) : boolean; override;
|
|
public
|
|
constructor Create; override;
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
implementation
|
|
|
|
const
|
|
WhiteSpace = ' '#8#10#13;
|
|
|
|
constructor TFPReaderXPM.create;
|
|
begin
|
|
inherited create;
|
|
palette := TStringList.Create;
|
|
end;
|
|
|
|
destructor TFPReaderXPM.Destroy;
|
|
begin
|
|
Palette.Free;
|
|
inherited destroy;
|
|
end;
|
|
|
|
function TFPReaderXPM.HexToColor(s : string) : TFPColor;
|
|
var l : integer;
|
|
function CharConv (c : char) : longword;
|
|
begin
|
|
if (c >= 'A') and (c <= 'F') then
|
|
result := ord (c) - ord('A') + 10
|
|
else if (c >= '0') and (c <= '9') then
|
|
result := ord (c) - ord('0')
|
|
else
|
|
raise exception.CreateFmt ('Wrong character (%s) in hexadecimal number', [c]);
|
|
end;
|
|
function convert (n : string) : word;
|
|
var t,r: integer;
|
|
begin
|
|
result := 0;
|
|
t := length(n);
|
|
if t > 4 then
|
|
raise exception.CreateFmt ('Too many bytes for color (%s)',[s]);
|
|
for r := 1 to length(n) do
|
|
result := (result shl 4) or CharConv(n[r]);
|
|
// fill missing bits
|
|
case t of
|
|
1: result:=result or (result shl 4) or (result shl 8) or (result shl 12);
|
|
2: result:=result or (result shl 8);
|
|
3: result:=result or (result shl 12);
|
|
end;
|
|
end;
|
|
begin
|
|
s := uppercase (s);
|
|
l := length(s) div 3;
|
|
result.red := (Convert(copy(s,1,l)));
|
|
result.green := (Convert(copy(s,l+1,l)));
|
|
result.blue := Convert(copy(s,l+l+1,l));
|
|
result.alpha := AlphaOpaque;
|
|
end;
|
|
|
|
function TFPReaderXPM.NameToColor(s : string) : TFPColor;
|
|
begin
|
|
s := lowercase (s);
|
|
if s = 'transparent' then
|
|
result := colTransparent
|
|
else if s = 'none' then
|
|
result := colTransparent
|
|
else if s = 'black' then
|
|
result := colBlack
|
|
else if s = 'blue' then
|
|
result := colBlue
|
|
else if s = 'green' then
|
|
result := colGreen
|
|
else if s = 'cyan' then
|
|
result := colCyan
|
|
else if s = 'red' then
|
|
result := colRed
|
|
else if s = 'magenta' then
|
|
result := colMagenta
|
|
else if s = 'yellow' then
|
|
result := colYellow
|
|
else if s = 'white' then
|
|
result := colWhite
|
|
else if s = 'gray' then
|
|
result := colGray
|
|
else if s = 'ltgray' then
|
|
result := colLtGray
|
|
else if s = 'dkblue' then
|
|
result := colDkBlue
|
|
else if s = 'dkgreen' then
|
|
result := colDkGreen
|
|
else if s = 'dkcyan' then
|
|
result := colDkCyan
|
|
else if s = 'dkred' then
|
|
result := colDkRed
|
|
else if s = 'dkmagenta' then
|
|
result := colDkMagenta
|
|
else if s = 'dkyellow' then
|
|
result := colDkYellow
|
|
else if s = 'maroon' then
|
|
result := colMaroon
|
|
else if s = 'ltgreen' then
|
|
result := colLtGreen
|
|
else if s = 'olive' then
|
|
result := colOlive
|
|
else if s = 'navy' then
|
|
result := colNavy
|
|
else if s = 'purple' then
|
|
result := colPurple
|
|
else if s = 'teal' then
|
|
result := colTeal
|
|
else if s = 'silver' then
|
|
result := colSilver
|
|
else if s = 'lime' then
|
|
result := colLime
|
|
else if s = 'fuchsia' then
|
|
result := colFuchsia
|
|
else if s = 'aqua' then
|
|
result := colAqua
|
|
else
|
|
result := colTransparent;
|
|
end;
|
|
|
|
function TFPReaderXPM.DiminishWhiteSpace (s : string) : string;
|
|
var r : integer;
|
|
Doit : boolean;
|
|
begin
|
|
Doit := true;
|
|
result := '';
|
|
for r := 1 to length(s) do
|
|
if pos(s[r],WhiteSpace)>0 then
|
|
begin
|
|
if DoIt then
|
|
result := result + ' ';
|
|
DoIt := false;
|
|
end
|
|
else
|
|
begin
|
|
DoIt := True;
|
|
result := result + s[r];
|
|
end;
|
|
end;
|
|
|
|
procedure TFPReaderXPM.InternalRead (Str:TStream; Img:TFPCustomImage);
|
|
var l : TStringList;
|
|
|
|
procedure TakeInteger (var s : string; var i : integer);
|
|
var r : integer;
|
|
begin
|
|
r := pos (' ', s);
|
|
if r = 0 then
|
|
begin
|
|
i := StrToInt(s);
|
|
s := '';
|
|
end
|
|
else
|
|
begin
|
|
i := StrToInt(copy(s,1,r-1));
|
|
delete (s, 1, r);
|
|
end;
|
|
end;
|
|
|
|
procedure ParseFirstLine;
|
|
var s : string;
|
|
begin
|
|
s := l[0];
|
|
// diminish all whitespace to 1 blank
|
|
s := DiminishWhiteSpace (trim(s));
|
|
Takeinteger (s, width);
|
|
Takeinteger (s, height);
|
|
Takeinteger (s, ncols);
|
|
Takeinteger (s, cpp);
|
|
if s <> '' then
|
|
begin
|
|
Takeinteger (s, xhot);
|
|
Takeinteger (s, yhot);
|
|
xpmext := (comparetext(s, 'XPMEXT') = 0);
|
|
if (s <> '') and not xpmext then
|
|
Raise Exception.Create ('Wrong word for XPMEXT tag');
|
|
end;
|
|
end;
|
|
|
|
procedure AddPalette (const code:string;const Acolor:TFPColor);
|
|
var r : integer;
|
|
begin
|
|
r := Palette.Add(code);
|
|
img.palette.Color[r] := Acolor;
|
|
end;
|
|
|
|
procedure AddToPalette(s : string);
|
|
var code : string;
|
|
c : TFPColor;
|
|
p : integer;
|
|
begin
|
|
code := copy(s,1,cpp);
|
|
s := trim(diminishWhiteSpace (copy(s,cpp+1,maxint)));
|
|
// Search for c-key in the color values
|
|
if s[1] = 'c' then
|
|
delete (s, 1, 2)
|
|
else
|
|
begin
|
|
p := pos (' c ',s);
|
|
if p = 0 then
|
|
s := ''
|
|
else
|
|
delete (s, 1, p+2);
|
|
end;
|
|
// c color value is first word, remove the rest of the line
|
|
p := pos(' ', s);
|
|
if p > 0 then
|
|
delete (s, p, maxint);
|
|
// check if exists
|
|
if s = '' then
|
|
raise exception.Create ('Only c-key is used for colors');
|
|
// convert #hexadecimal value to integer and place in palette
|
|
if s[1] = '#' then
|
|
c := HexToColor(copy(s,2,maxint))
|
|
else
|
|
c := NameToColor(s);
|
|
AddPalette(code,c);
|
|
end;
|
|
|
|
procedure ReadPalette;
|
|
var r : integer;
|
|
begin
|
|
Palette.Clear;
|
|
Img.Palette.Count := ncols;
|
|
for r := 1 to ncols do
|
|
AddToPalette (l[r]);
|
|
end;
|
|
|
|
procedure ReadLine (const s : string; imgindex : integer);
|
|
var color, r, p : integer;
|
|
code : string;
|
|
begin
|
|
p := 1;
|
|
for r := 1 to width do
|
|
begin
|
|
code := copy(s, p, cpp);
|
|
inc(p,cpp);
|
|
for color := 0 to Palette.Count-1 do
|
|
{ Can't use indexof, as compare must be case sensitive }
|
|
if code = Palette[color] then begin
|
|
img.pixels[r-1,imgindex] := color;
|
|
Break;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure ReadData;
|
|
var r : integer;
|
|
begin
|
|
for r := 1 to height do
|
|
ReadLine (l[ncols+r], r-1);
|
|
end;
|
|
|
|
var p, r : integer;
|
|
begin
|
|
l := TStringList.Create;
|
|
try
|
|
l.LoadFromStream (Str);
|
|
for r := l.count-1 downto 0 do
|
|
begin
|
|
p := pos ('"', l[r]);
|
|
if p > 0 then
|
|
l[r] := copy(l[r], p+1, lastdelimiter('"',l[r])-p-1)
|
|
else
|
|
l.delete(r);
|
|
end;
|
|
ParseFirstLine;
|
|
Img.SetSize (width, height);
|
|
ReadPalette;
|
|
ReadData;
|
|
finally
|
|
l.Free;
|
|
end;
|
|
end;
|
|
|
|
function TFPReaderXPM.InternalCheck (Str:TStream) : boolean;
|
|
var s : string[9];
|
|
l : integer;
|
|
begin
|
|
try
|
|
l := str.Read (s[1],9);
|
|
s[0] := char(l);
|
|
if l <> 9 then
|
|
result := False
|
|
else
|
|
result := (s = '/* XPM */');
|
|
except
|
|
result := false;
|
|
end;
|
|
end;
|
|
|
|
initialization
|
|
ImageHandlers.RegisterImageReader ('XPM Format', 'xpm', TFPReaderXPM);
|
|
end.
|