source: trunk/Packages/bgrabitmap/bgrareadpcx.pas

Last change on this file was 2, checked in by chronos, 5 years ago
File size: 5.6 KB
Line 
1{ This unit provides some optimisations of TFPReaderPCX: decompression using a read buffer.
2 It also fixes the progress message and the InternalCheck. }
3
4unit BGRAReadPCX;
5
6{$mode objfpc}{$H+}
7
8interface
9
10uses FPImage, Classes, SysUtils, FPReadPCX;
11
12type
13
14 { TBGRAReaderPCX }
15
16 TBGRAReaderPCX = class(TFPReaderPCX)
17 protected
18 FBuffer: packed array of byte;
19 FBufferPos, FBufferSize: integer;
20 FBufferStream: TStream;
21 function InternalCheck(Stream: TStream): boolean; override;
22 procedure InternalRead(Stream: TStream; Img: TFPCustomImage); override;
23 procedure ReadScanLine({%H-}Row: integer; Stream: TStream); override;
24 procedure WriteScanLine(Row: integer; Img: TFPCustomImage); override;
25 procedure InitReadBuffer(AStream: TStream; ASize: integer);
26 procedure CloseReadBuffer;
27 function GetNextBufferByte: byte;
28 end;
29
30implementation
31
32uses BGRABitmapTypes;
33
34procedure TBGRAReaderPCX.ReadScanLine(Row: integer; Stream: TStream);
35var
36 P: PByte;
37 B: NativeUint;
38 bytes, Count: NativeUInt;
39begin
40 if FLineSize <= 0 then exit;
41 P := FScanLine;
42 bytes := FLineSize;
43 if Compressed then
44 begin
45 while bytes > 0 do
46 begin
47 B := GetNextBufferByte;
48 if (B < $c0) then
49 Count := 1
50 else
51 begin
52 Count := B - $c0;
53 B := GetNextBufferByte;
54 end;
55 if Count = 0 then continue else
56 if Count = 1 then
57 begin
58 P^ := B;
59 Inc(P);
60 Dec(bytes);
61 end else
62 begin
63 if Count > bytes then Count := bytes;
64 fillchar(p^, count, B);
65 Inc(p, count);
66 dec(bytes, count);
67 end;
68 end;
69 end
70 else
71 Stream.ReadBuffer(FScanLine^, FLineSize);
72end;
73
74procedure TBGRAReaderPCX.InternalRead(Stream: TStream; Img: TFPCustomImage);
75var
76 H, Row: integer;
77 continue: boolean;
78 emptyRect: TRect;
79begin
80 emptyRect := rect(0,0,0,0);
81 continue := True;
82 Progress(psStarting, 0, False, emptyRect, '', continue);
83 Stream.Read(Header, SizeOf(Header));
84 AnalyzeHeader(Img);
85 case BytesPerPixel of
86 1: CreateBWPalette(Img);
87 4: CreatePalette16(Img);
88 8: ReadPalette(stream, Img);
89 else
90 if (Header.PaletteType = 2) then
91 CreateGrayPalette(Img);
92 end;
93 H := Img.Height;
94 if Compressed then InitReadBuffer(Stream,2048);
95 for Row := 0 to H - 1 do
96 begin
97 ReadScanLine(Row, Stream);
98 WriteScanLine(Row, Img);
99 Progress(psRunning, (Row+1) div H, False, emptyRect, '', continue);
100 end;
101 if Compressed then CloseReadBuffer;
102 Progress(psEnding, 100, False, emptyRect, '', continue);
103 freemem(FScanLine);
104end;
105
106procedure TBGRAReaderPCX.WriteScanLine(Row: integer; Img: TFPCustomImage);
107var
108 Col: integer;
109 C: TFPColor;
110 P, P1, P2, P3: PByte;
111 Z2: word;
112 color: byte;
113begin
114 C.Alpha := AlphaOpaque;
115 P := FScanLine;
116 Z2 := Header.BytesPerLine;
117 begin
118 case BytesPerPixel of
119 1:
120 begin
121 for Col := 0 to Img.Width - 1 do
122 begin
123 if (P[col div 8] and (128 shr (col mod 8))) <> 0 then
124 Img.Colors[Col, Row] := Img.Palette[1]
125 else
126 Img.Colors[Col, Row] := Img.Palette[0];
127 end;
128 end;
129 4:
130 begin
131 P1 := P;
132 Inc(P1, Z2);
133 P2 := P;
134 Inc(P2, Z2 * 2);
135 P3 := P;
136 Inc(P3, Z2 * 3);
137 for Col := 0 to Img.Width - 1 do
138 begin
139 color := 0;
140 if (P[col div 8] and (128 shr (col mod 8))) <> 0 then
141 Inc(color, 1);
142 if (P1[col div 8] and (128 shr (col mod 8))) <> 0 then
143 Inc(color, 1 shl 1);
144 if (P2[col div 8] and (128 shr (col mod 8))) <> 0 then
145 Inc(color, 1 shl 2);
146 if (P3[col div 8] and (128 shr (col mod 8))) <> 0 then
147 Inc(color, 1 shl 3);
148 Img.Colors[Col, Row] := Img.Palette[color];
149 end;
150 end;
151 8:
152 begin
153 for Col := 0 to Img.Width - 1 do
154 begin
155 Img.Colors[Col, Row] := Img.Palette[P[Col]];
156 end;
157 end;
158 24:
159 begin
160 for Col := 0 to Img.Width - 1 do
161 begin
162 with C do
163 begin
164 Red := P[col] or (P[col] shl 8);
165 Blue := P[col + Z2 * 2] or (P[col + Z2 * 2] shl 8);
166 Green := P[col + Z2] or (P[col + Z2] shl 8);
167 Alpha := alphaOpaque;
168 end;
169 Img[col, row] := C;
170 end;
171 end;
172 end;
173 end;
174end;
175
176procedure TBGRAReaderPCX.InitReadBuffer(AStream: TStream; ASize: integer);
177begin
178 setLength(FBuffer,ASize);
179 FBufferSize := AStream.Read(FBuffer[0],ASize);
180 FBufferPos := 0;
181 FBufferStream := AStream;
182end;
183
184procedure TBGRAReaderPCX.CloseReadBuffer;
185begin
186 FBufferStream.Position:= FBufferStream.Position-FBufferSize+FBufferPos;
187end;
188
189function TBGRAReaderPCX.GetNextBufferByte: byte;
190begin
191 if FBufferPos < FBufferSize then
192 begin
193 result := FBuffer[FBufferPos];
194 inc(FBufferPos);
195 end else
196 if FBufferSize = 0 then
197 result := 0
198 else
199 begin
200 FBufferSize := FBufferStream.Read(FBuffer[0],length(FBuffer));
201 FBufferPos := 0;
202 if FBufferPos < FBufferSize then
203 begin
204 result := FBuffer[FBufferPos];
205 inc(FBufferPos);
206 end else
207 result := 0;
208 end;
209end;
210
211function TBGRAReaderPCX.InternalCheck({%H-}Stream: TStream): boolean;
212var
213 {%H-}magic: packed array[0..3] of byte;
214 oldPos: Int64;
215begin
216 oldPos:= stream.Position;
217 result := stream.Read({%H-}magic,SizeOf(magic)) = sizeof(magic);
218 stream.Position:= oldPos;
219 if result then
220 result := (magic[0] in[$0a,$0c,$cd]) and (magic[1] in [0,2,3,4,5]) and (magic[2] in[0,1]) and (magic[3] in[1,2,4,8])
221end;
222
223initialization
224
225 DefaultBGRAImageReader[ifPcx] := TBGRAReaderPCX;
226
227end.
Note: See TracBrowser for help on using the repository browser.