| 1 | { This unit provides some optimisations of TFPReaderPCX: decompression using a read buffer.
|
|---|
| 2 | It also fixes the progress message and the InternalCheck. }
|
|---|
| 3 |
|
|---|
| 4 | unit BGRAReadPCX;
|
|---|
| 5 |
|
|---|
| 6 | {$mode objfpc}{$H+}
|
|---|
| 7 |
|
|---|
| 8 | interface
|
|---|
| 9 |
|
|---|
| 10 | uses FPImage, Classes, SysUtils, FPReadPCX;
|
|---|
| 11 |
|
|---|
| 12 | type
|
|---|
| 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 |
|
|---|
| 30 | implementation
|
|---|
| 31 |
|
|---|
| 32 | uses BGRABitmapTypes;
|
|---|
| 33 |
|
|---|
| 34 | procedure TBGRAReaderPCX.ReadScanLine(Row: integer; Stream: TStream);
|
|---|
| 35 | var
|
|---|
| 36 | P: PByte;
|
|---|
| 37 | B: NativeUint;
|
|---|
| 38 | bytes, Count: NativeUInt;
|
|---|
| 39 | begin
|
|---|
| 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);
|
|---|
| 72 | end;
|
|---|
| 73 |
|
|---|
| 74 | procedure TBGRAReaderPCX.InternalRead(Stream: TStream; Img: TFPCustomImage);
|
|---|
| 75 | var
|
|---|
| 76 | H, Row: integer;
|
|---|
| 77 | continue: boolean;
|
|---|
| 78 | emptyRect: TRect;
|
|---|
| 79 | begin
|
|---|
| 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);
|
|---|
| 104 | end;
|
|---|
| 105 |
|
|---|
| 106 | procedure TBGRAReaderPCX.WriteScanLine(Row: integer; Img: TFPCustomImage);
|
|---|
| 107 | var
|
|---|
| 108 | Col: integer;
|
|---|
| 109 | C: TFPColor;
|
|---|
| 110 | P, P1, P2, P3: PByte;
|
|---|
| 111 | Z2: word;
|
|---|
| 112 | color: byte;
|
|---|
| 113 | begin
|
|---|
| 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;
|
|---|
| 174 | end;
|
|---|
| 175 |
|
|---|
| 176 | procedure TBGRAReaderPCX.InitReadBuffer(AStream: TStream; ASize: integer);
|
|---|
| 177 | begin
|
|---|
| 178 | setLength(FBuffer,ASize);
|
|---|
| 179 | FBufferSize := AStream.Read(FBuffer[0],ASize);
|
|---|
| 180 | FBufferPos := 0;
|
|---|
| 181 | FBufferStream := AStream;
|
|---|
| 182 | end;
|
|---|
| 183 |
|
|---|
| 184 | procedure TBGRAReaderPCX.CloseReadBuffer;
|
|---|
| 185 | begin
|
|---|
| 186 | FBufferStream.Position:= FBufferStream.Position-FBufferSize+FBufferPos;
|
|---|
| 187 | end;
|
|---|
| 188 |
|
|---|
| 189 | function TBGRAReaderPCX.GetNextBufferByte: byte;
|
|---|
| 190 | begin
|
|---|
| 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;
|
|---|
| 209 | end;
|
|---|
| 210 |
|
|---|
| 211 | function TBGRAReaderPCX.InternalCheck({%H-}Stream: TStream): boolean;
|
|---|
| 212 | var
|
|---|
| 213 | {%H-}magic: packed array[0..3] of byte;
|
|---|
| 214 | oldPos: Int64;
|
|---|
| 215 | begin
|
|---|
| 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])
|
|---|
| 221 | end;
|
|---|
| 222 |
|
|---|
| 223 | initialization
|
|---|
| 224 |
|
|---|
| 225 | DefaultBGRAImageReader[ifPcx] := TBGRAReaderPCX;
|
|---|
| 226 |
|
|---|
| 227 | end.
|
|---|