| 1 | {
|
|---|
| 2 | This original file was part of the Free Pascal run time library.
|
|---|
| 3 | Copyright (c) 2008 by the Free Pascal development team
|
|---|
| 4 |
|
|---|
| 5 | Psd reader for fpImage.
|
|---|
| 6 |
|
|---|
| 7 | See the file COPYING.FPC, included in this distribution,
|
|---|
| 8 | for details about the copyright.
|
|---|
| 9 |
|
|---|
| 10 | This program is distributed in the hope that it will be useful,
|
|---|
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|---|
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|---|
| 13 |
|
|---|
| 14 | **********************************************************************
|
|---|
| 15 |
|
|---|
| 16 | 03/2014 changes by circular :
|
|---|
| 17 | - added MinifyHeight,WantedHeight and OutputHeight (useful for thumbnails)
|
|---|
| 18 | }
|
|---|
| 19 | unit BGRAReadPSD;
|
|---|
| 20 |
|
|---|
| 21 | {$mode objfpc}{$H+}
|
|---|
| 22 |
|
|---|
| 23 | interface
|
|---|
| 24 |
|
|---|
| 25 | uses
|
|---|
| 26 | Classes, SysUtils, FPimage, FPReadPSD;
|
|---|
| 27 |
|
|---|
| 28 | type
|
|---|
| 29 | { TBGRAReaderPSD }
|
|---|
| 30 |
|
|---|
| 31 | TBGRAReaderPSD = class(TFPReaderPSD)
|
|---|
| 32 | private
|
|---|
| 33 | FCompressed: boolean;
|
|---|
| 34 | protected
|
|---|
| 35 | FScanLines : array of PByte;
|
|---|
| 36 | FInputLine : array of record
|
|---|
| 37 | StreamOffset: Int64;
|
|---|
| 38 | Size: PtrInt;
|
|---|
| 39 | end;
|
|---|
| 40 | FOutputHeight: integer;
|
|---|
| 41 | function ReadPalette(Stream: TStream): boolean;
|
|---|
| 42 | procedure AnalyzeHeader;
|
|---|
| 43 | procedure InternalRead(Stream: TStream; Img: TFPCustomImage); override;
|
|---|
| 44 | function ReadScanLine(Stream: TStream; AInputSize: PtrInt; AChannel: integer): boolean; overload;
|
|---|
| 45 | procedure WriteScanLine(Img: TFPCustomImage; Row: integer); overload;
|
|---|
| 46 | function InternalCheck(Stream: TStream) : boolean; override;
|
|---|
| 47 | public
|
|---|
| 48 | MinifyHeight,WantedHeight: integer;
|
|---|
| 49 | constructor Create; override;
|
|---|
| 50 | property Compressed: Boolean read FCompressed;
|
|---|
| 51 | property OutputHeight: integer read FOutputHeight;
|
|---|
| 52 | end;
|
|---|
| 53 |
|
|---|
| 54 | implementation
|
|---|
| 55 |
|
|---|
| 56 | uses BGRABitmapTypes;
|
|---|
| 57 |
|
|---|
| 58 | function clamp(AValue, AMax: integer): integer;
|
|---|
| 59 | begin
|
|---|
| 60 | if AValue < 0 then result := 0 else
|
|---|
| 61 | if AValue > AMax then result := AMax else
|
|---|
| 62 | result := AValue;;
|
|---|
| 63 | end;
|
|---|
| 64 |
|
|---|
| 65 | function CMYKtoRGB ( C : TFPColor): TFPColor;
|
|---|
| 66 | var r,g,b: integer;
|
|---|
| 67 | begin
|
|---|
| 68 | r := $ffff - c.red + c.green div 10 + c.blue div 10 - c.alpha;
|
|---|
| 69 | g := $ffff + c.red div 10 - c.green + c.blue div 10 - c.alpha;
|
|---|
| 70 | b := $ffff + c.red div 10 + c.green div 10 - c.blue - c.alpha;
|
|---|
| 71 | result.red := clamp(r, 65535);
|
|---|
| 72 | result.green := clamp(g, 65535);
|
|---|
| 73 | result.blue := clamp(b, 65535);
|
|---|
| 74 | Result.alpha:=alphaOpaque;
|
|---|
| 75 | end;
|
|---|
| 76 |
|
|---|
| 77 | function fInv(t: single): single;
|
|---|
| 78 | begin
|
|---|
| 79 | if t > 6/29 then result := t*t*t else
|
|---|
| 80 | result := 3*(6/29)*(6/29)*(t-4/29);
|
|---|
| 81 | end;
|
|---|
| 82 |
|
|---|
| 83 | function Csrgb(linear: single): single;
|
|---|
| 84 | begin
|
|---|
| 85 | if linear <= 0.0031308 then
|
|---|
| 86 | result := 12.92*linear else
|
|---|
| 87 | result := (1+0.055)*exp(ln(linear)*(1/2.4)) - 0.055;
|
|---|
| 88 | end;
|
|---|
| 89 |
|
|---|
| 90 | function LabToRGB(L,a,b: single):TFPColor; overload;
|
|---|
| 91 | var r,g,blue: single;
|
|---|
| 92 | begin
|
|---|
| 93 | if a < 0 then
|
|---|
| 94 | r := L + a + 0.25*b
|
|---|
| 95 | else
|
|---|
| 96 | r := L + 0.75*a + 0.25*b;
|
|---|
| 97 | g := L - 0.25*a;
|
|---|
| 98 | blue := L - b;
|
|---|
| 99 | Result.red:= clamp(round((r)*65535),65535);
|
|---|
| 100 | Result.green:= clamp(round((g)*65535),65535);
|
|---|
| 101 | Result.blue:= clamp(round((blue)*65535),65535);
|
|---|
| 102 | result.alpha := 65535;
|
|---|
| 103 | end;
|
|---|
| 104 |
|
|---|
| 105 | function LabToRGB(const Lab:TLab):TFPColor; overload;
|
|---|
| 106 | var L: single;
|
|---|
| 107 | begin
|
|---|
| 108 | L := 1/255*Lab.L;
|
|---|
| 109 | result := LabToRGB(L,(Lab.a-128)/127,(Lab.b-128)/127);
|
|---|
| 110 | end;
|
|---|
| 111 |
|
|---|
| 112 | { TBGRAReaderPSD }
|
|---|
| 113 |
|
|---|
| 114 | function TBGRAReaderPSD.ReadPalette(Stream: TStream): boolean;
|
|---|
| 115 | Var
|
|---|
| 116 | I : Integer;
|
|---|
| 117 | c : TFPColor;
|
|---|
| 118 | OldPos: Integer;
|
|---|
| 119 | BufSize:Longint;
|
|---|
| 120 | {%H-}PalBuf: array[0..767] of Byte;
|
|---|
| 121 | ContProgress: Boolean;
|
|---|
| 122 | begin
|
|---|
| 123 | Result:=false;
|
|---|
| 124 | ThePalette.count := 0;
|
|---|
| 125 | OldPos := Stream.Position;
|
|---|
| 126 | BufSize:=0;
|
|---|
| 127 | Stream.Read(BufSize, SizeOf(BufSize));
|
|---|
| 128 | BufSize:=BEtoN(BufSize);
|
|---|
| 129 | Stream.Read({%H-}PalBuf, BufSize);
|
|---|
| 130 | ContProgress:=true;
|
|---|
| 131 | Progress(FPimage.psRunning, 0, False, Rect(0,0,0,0), '', ContProgress);
|
|---|
| 132 | if not ContProgress then exit;
|
|---|
| 133 | For I:=0 To BufSize div 3 Do
|
|---|
| 134 | Begin
|
|---|
| 135 | With c do
|
|---|
| 136 | begin
|
|---|
| 137 | Red:=PalBuf[I] shl 8;
|
|---|
| 138 | Green:=PalBuf[I+(BufSize div 3)] shl 8;
|
|---|
| 139 | Blue:=PalBuf[I+(BufSize div 3)* 2] shl 8;
|
|---|
| 140 | Alpha:=alphaOpaque;
|
|---|
| 141 | end;
|
|---|
| 142 | ThePalette.Add(C);
|
|---|
| 143 | End;
|
|---|
| 144 | Stream.Position := OldPos;
|
|---|
| 145 | Result:=true;
|
|---|
| 146 | end;
|
|---|
| 147 |
|
|---|
| 148 | procedure TBGRAReaderPSD.AnalyzeHeader;
|
|---|
| 149 | var channel: integer;
|
|---|
| 150 | begin
|
|---|
| 151 | With FHeader do
|
|---|
| 152 | begin
|
|---|
| 153 | Depth:=BEtoN(Depth);
|
|---|
| 154 | if (Signature <> '8BPS') then
|
|---|
| 155 | Raise Exception.Create('Unknown/Unsupported PSD image type');
|
|---|
| 156 | Channels:=BEtoN(Channels);
|
|---|
| 157 | if Channels > 4 then
|
|---|
| 158 | FBytesPerPixel:=Depth*4
|
|---|
| 159 | else
|
|---|
| 160 | FBytesPerPixel:=Depth*Channels;
|
|---|
| 161 | Mode:=BEtoN(Mode);
|
|---|
| 162 | FWidth:=BEtoN(Columns);
|
|---|
| 163 | FHeight:=BEtoN(Rows);
|
|---|
| 164 | FChannelCount:=Channels;
|
|---|
| 165 | FLineSize:=(PtrInt(FWidth)*Depth+7) div 8;
|
|---|
| 166 | setlength(FScanLines, FChannelCount);
|
|---|
| 167 | for channel := 0 to FChannelCount-1 do
|
|---|
| 168 | GetMem(FScanLines[channel],FLineSize);
|
|---|
| 169 | end;
|
|---|
| 170 | end;
|
|---|
| 171 |
|
|---|
| 172 | procedure TBGRAReaderPSD.InternalRead(Stream: TStream; Img: TFPCustomImage);
|
|---|
| 173 | var
|
|---|
| 174 | H,HOutput,InputLineIndex,LenOfLineIndex,channel: Integer;
|
|---|
| 175 | LenOfLineFactor: PtrInt;
|
|---|
| 176 | BufSize:Cardinal;
|
|---|
| 177 | Encoding:word;
|
|---|
| 178 | ContProgress: Boolean;
|
|---|
| 179 | CurOffset: int64;
|
|---|
| 180 | PrevOutputRow, OutputRow, OutputRowAdd, OutputRowAcc, OutputRowAccAdd, OutputRowMod: integer;
|
|---|
| 181 | begin
|
|---|
| 182 | FScanLines:=nil;
|
|---|
| 183 | FPalette:=nil;
|
|---|
| 184 | try
|
|---|
| 185 | Stream.Position:=0;
|
|---|
| 186 | ContProgress:=true;
|
|---|
| 187 | Progress(FPimage.psStarting, 0, False, Rect(0,0,0,0), '', ContProgress);
|
|---|
| 188 | if not ContProgress then exit;
|
|---|
| 189 | // read header
|
|---|
| 190 | Stream.Read(FHeader, SizeOf(FHeader));
|
|---|
| 191 | Progress(FPimage.psRunning, 0, False, Rect(0,0,0,0), '', ContProgress);
|
|---|
| 192 | if not ContProgress then exit;
|
|---|
| 193 | AnalyzeHeader;
|
|---|
| 194 | Case FHeader.Mode of
|
|---|
| 195 | 0:begin // Bitmap (monochrome)
|
|---|
| 196 | FPalette := TFPPalette.Create(0);
|
|---|
| 197 | CreateBWPalette;
|
|---|
| 198 | end;
|
|---|
| 199 | 1, 8:begin // Gray-scale
|
|---|
| 200 | FPalette := TFPPalette.Create(0);
|
|---|
| 201 | CreateGrayPalette;
|
|---|
| 202 | end;
|
|---|
| 203 | 2:begin // Indexed color (palette color)
|
|---|
| 204 | FPalette := TFPPalette.Create(0);
|
|---|
| 205 | if not ReadPalette(stream) then exit;
|
|---|
| 206 | end;
|
|---|
| 207 | end;
|
|---|
| 208 |
|
|---|
| 209 | if Assigned(OnCreateImage) then
|
|---|
| 210 | OnCreateImage(Self,Img);
|
|---|
| 211 |
|
|---|
| 212 | if (MinifyHeight > 0) and (FHeight > MinifyHeight) then
|
|---|
| 213 | FOutputHeight:= MinifyHeight
|
|---|
| 214 | else
|
|---|
| 215 | if WantedHeight > 0 then
|
|---|
| 216 | FOutputHeight:= WantedHeight
|
|---|
| 217 | else
|
|---|
| 218 | FOutputHeight:= FHeight;
|
|---|
| 219 | Img.SetSize(FWidth,FOutputHeight);
|
|---|
| 220 |
|
|---|
| 221 | // color palette
|
|---|
| 222 | BufSize:=0;
|
|---|
| 223 | Stream.Read(BufSize, SizeOf(BufSize));
|
|---|
| 224 | BufSize:=BEtoN(BufSize);
|
|---|
| 225 | Stream.Seek(BufSize, soCurrent);
|
|---|
| 226 | // color data block
|
|---|
| 227 | Stream.Read(BufSize, SizeOf(BufSize));
|
|---|
| 228 | BufSize:=BEtoN(BufSize);
|
|---|
| 229 | Stream.Read(FColorDataBlock, SizeOf(FColorDataBlock));
|
|---|
| 230 | Stream.Seek(BufSize-SizeOf(FColorDataBlock), soCurrent);
|
|---|
| 231 | // mask
|
|---|
| 232 | Stream.Read(BufSize, SizeOf(BufSize));
|
|---|
| 233 | BufSize:=BEtoN(BufSize);
|
|---|
| 234 | Stream.Seek(BufSize, soCurrent);
|
|---|
| 235 | // compression type
|
|---|
| 236 | Encoding:=0;
|
|---|
| 237 | Stream.Read(Encoding, SizeOf(Encoding));
|
|---|
| 238 | FCompressed:=BEtoN(Encoding) = 1;
|
|---|
| 239 | if BEtoN(Encoding)>1 then
|
|---|
| 240 | Raise Exception.Create('Unknown compression type');
|
|---|
| 241 | If FCompressed then
|
|---|
| 242 | begin
|
|---|
| 243 | SetLength(FLengthOfLine, FHeight * FChannelCount);
|
|---|
| 244 | Stream.ReadBuffer(FLengthOfLine[0], 2 * Length(FLengthOfLine));
|
|---|
| 245 | Progress(FPimage.psRunning, 0, False, Rect(0,0,0,0), '', ContProgress);
|
|---|
| 246 | if not ContProgress then exit;
|
|---|
| 247 | if not (FHeader.Mode in [0, 2]) then
|
|---|
| 248 | LenOfLineFactor := FHeader.Depth div 8
|
|---|
| 249 | else
|
|---|
| 250 | LenOfLineFactor := 1;
|
|---|
| 251 | end else
|
|---|
| 252 | begin
|
|---|
| 253 | FLengthOfLine := nil;
|
|---|
| 254 | end;
|
|---|
| 255 |
|
|---|
| 256 | setlength(FInputLine, FHeight * FChannelCount);
|
|---|
| 257 | CurOffset := Stream.Position;
|
|---|
| 258 | H := 0;
|
|---|
| 259 | channel := 0;
|
|---|
| 260 | InputLineIndex:= 0;
|
|---|
| 261 | for LenOfLineIndex := 0 to FHeight * FChannelCount-1 do
|
|---|
| 262 | begin
|
|---|
| 263 | FInputLine[InputLineIndex].StreamOffset := CurOffset;
|
|---|
| 264 | if FLengthOfLine <> nil then
|
|---|
| 265 | FInputLine[InputLineIndex].Size := BEtoN(FLengthOfLine[LenOfLineIndex])*LenOfLineFactor else
|
|---|
| 266 | FInputLine[InputLineIndex].Size := FLineSize;
|
|---|
| 267 | inc(CurOffset, FInputLine[InputLineIndex].Size);
|
|---|
| 268 | inc(H);
|
|---|
| 269 | Inc(InputLineIndex, FChannelCount);
|
|---|
| 270 | if H = FHeight then
|
|---|
| 271 | begin
|
|---|
| 272 | H := 0;
|
|---|
| 273 | Inc(channel);
|
|---|
| 274 | InputLineIndex:= channel;
|
|---|
| 275 | end;
|
|---|
| 276 | end;
|
|---|
| 277 |
|
|---|
| 278 | InputLineIndex := 0;
|
|---|
| 279 | PrevOutputRow := -1;
|
|---|
| 280 | OutputRow := 0;
|
|---|
| 281 | OutputRowAdd := FOutputHeight div FHeight;
|
|---|
| 282 | OutputRowMod:= FHeight;
|
|---|
| 283 | OutputRowAccAdd := FOutputHeight mod FHeight;
|
|---|
| 284 | OutputRowAcc:= 0;
|
|---|
| 285 |
|
|---|
| 286 | For H := 0 to FHeight - 1 do
|
|---|
| 287 | begin
|
|---|
| 288 | if OutputRow > PrevOutputRow then
|
|---|
| 289 | begin
|
|---|
| 290 | for channel := 0 to FChannelCount-1 do
|
|---|
| 291 | begin
|
|---|
| 292 | Stream.Position := FInputLine[InputLineIndex].StreamOffset;
|
|---|
| 293 | ReadScanLine(Stream, FInputLine[InputLineIndex].Size, channel);
|
|---|
| 294 | Inc(InputLineIndex);
|
|---|
| 295 | end;
|
|---|
| 296 | For HOutput:= PrevOutputRow+1 to OutputRow do WriteScanLine(Img, HOutput);
|
|---|
| 297 | Progress(FPimage.psRunning, round((H+1)*99.0 / (FHeight * FChannelCount)), False, Rect(0,0,0,0), '', ContProgress);
|
|---|
| 298 | if not ContProgress then exit;
|
|---|
| 299 | end else inc(InputLineIndex, FChannelCount);
|
|---|
| 300 |
|
|---|
| 301 | PrevOutputRow:= OutputRow;
|
|---|
| 302 | Inc(OutputRow, OutputRowAdd);
|
|---|
| 303 | Inc(OutputRowAcc, OutputRowAccAdd);
|
|---|
| 304 | if OutputRowAcc> OutputRowMod then
|
|---|
| 305 | begin
|
|---|
| 306 | dec(OutputRowAcc, OutputRowMod);
|
|---|
| 307 | inc(OutputRow);
|
|---|
| 308 | end;
|
|---|
| 309 | end;
|
|---|
| 310 | Progress(FPimage.psRunning, 100, False, Rect(0,0,0,0), '', ContProgress);
|
|---|
| 311 | if not ContProgress then exit;
|
|---|
| 312 |
|
|---|
| 313 | {$ifdef FPC_Debug_Image}
|
|---|
| 314 | WriteLn('TBGRAReaderPSD.InternalRead AAA1 ',Stream.position,' ',Stream.size);
|
|---|
| 315 | {$endif}
|
|---|
| 316 | finally
|
|---|
| 317 | FreeAndNil(FPalette);
|
|---|
| 318 | for channel := 0 to FChannelCount-1 do
|
|---|
| 319 | ReAllocMem(FScanLines[channel],0);
|
|---|
| 320 | end;
|
|---|
| 321 | Progress(FPimage.psEnding, 100, false, Rect(0,0,FWidth,FHeight), '', ContProgress);
|
|---|
| 322 | end;
|
|---|
| 323 |
|
|---|
| 324 | function TBGRAReaderPSD.ReadScanLine(Stream: TStream; AInputSize: PtrInt;
|
|---|
| 325 | AChannel: integer): boolean;
|
|---|
| 326 | Var
|
|---|
| 327 | P : PByte;
|
|---|
| 328 | B : Byte;
|
|---|
| 329 | I, left : PtrInt;
|
|---|
| 330 | N : Shortint;
|
|---|
| 331 | Count:integer;
|
|---|
| 332 | buf, PBuf: PByte;
|
|---|
| 333 | begin
|
|---|
| 334 | Result:=false;
|
|---|
| 335 | If Not Compressed then
|
|---|
| 336 | Stream.ReadBuffer(FScanLines[AChannel]^,FLineSize)
|
|---|
| 337 | else
|
|---|
| 338 | begin
|
|---|
| 339 | getmem(buf, AInputSize);
|
|---|
| 340 | if stream.Read(buf^,AInputSize) <> AInputSize then
|
|---|
| 341 | begin
|
|---|
| 342 | freemem(buf);
|
|---|
| 343 | result := false;
|
|---|
| 344 | exit;
|
|---|
| 345 | end;
|
|---|
| 346 | P:=FScanLines[AChannel];
|
|---|
| 347 | left := FLineSize;
|
|---|
| 348 | i:=AInputSize;
|
|---|
| 349 | PBuf := buf;
|
|---|
| 350 | repeat
|
|---|
| 351 | Count:=0;
|
|---|
| 352 | N:= PShortInt(PBuf)^;
|
|---|
| 353 | inc(PBuf);
|
|---|
| 354 | dec(i);
|
|---|
| 355 | If N = -128 then
|
|---|
| 356 | else
|
|---|
| 357 | if N < 0 then
|
|---|
| 358 | begin
|
|---|
| 359 | Count:=-N+1;
|
|---|
| 360 | if Count > left then Count := left;
|
|---|
| 361 | dec(left,Count);
|
|---|
| 362 | B:= PBuf^;
|
|---|
| 363 | Inc(PBuf);
|
|---|
| 364 | dec(i);
|
|---|
| 365 | fillchar(p^,count,B);
|
|---|
| 366 | inc(p,count);
|
|---|
| 367 | end
|
|---|
| 368 | else
|
|---|
| 369 | begin
|
|---|
| 370 | Count:=N+1;
|
|---|
| 371 | if Count > left then Count := left;
|
|---|
| 372 | dec(left,Count);
|
|---|
| 373 | Move(PBuf^, P^, Count);
|
|---|
| 374 | Inc(PBuf, Count);
|
|---|
| 375 | inc(p, count);
|
|---|
| 376 | dec(i, count);
|
|---|
| 377 | end;
|
|---|
| 378 | until (i <= 0) or (left <= 0);
|
|---|
| 379 | freemem(buf);
|
|---|
| 380 | end;
|
|---|
| 381 | Result:=true;
|
|---|
| 382 | end;
|
|---|
| 383 |
|
|---|
| 384 | function Value32To16(p: PDWord; gamma: single): Word;
|
|---|
| 385 | var v: single;
|
|---|
| 386 | begin
|
|---|
| 387 | v := (BEtoN(P^) - 1024000000)/40960000;
|
|---|
| 388 | if v <= 0 then result := 0 else
|
|---|
| 389 | if v >= 1 then result := 65535 else
|
|---|
| 390 | result := round(exp(ln(v)*gamma)*65535);
|
|---|
| 391 | end;
|
|---|
| 392 |
|
|---|
| 393 | procedure TBGRAReaderPSD.WriteScanLine(Img: TFPCustomImage; Row: integer);
|
|---|
| 394 | Var
|
|---|
| 395 | Col : Integer;
|
|---|
| 396 | C : TFPColor;
|
|---|
| 397 | P, P1, P2, P3 : PByte;
|
|---|
| 398 | Lab : TLab;
|
|---|
| 399 | begin
|
|---|
| 400 | C.Alpha:=AlphaOpaque;
|
|---|
| 401 | P:=FScanLines[0];
|
|---|
| 402 | begin
|
|---|
| 403 | case FBytesPerPixel of
|
|---|
| 404 | 1 : begin
|
|---|
| 405 | for Col:=0 to Img.Width-1 do
|
|---|
| 406 | if (P[col div 8] and (128 shr (col mod 8))) <> 0 then
|
|---|
| 407 | Img.Colors[Col,Row]:=ThePalette[0]
|
|---|
| 408 | else
|
|---|
| 409 | Img.Colors[Col,Row]:=ThePalette[1];
|
|---|
| 410 | end;
|
|---|
| 411 | 8 : begin
|
|---|
| 412 | for Col:=0 to Img.Width-1 do
|
|---|
| 413 | begin
|
|---|
| 414 | Img.Colors[Col,Row]:=ThePalette[P[0]];
|
|---|
| 415 | inc(p);
|
|---|
| 416 | end;
|
|---|
| 417 | end;
|
|---|
| 418 | 16 : if (FHeader.Mode = 1) or (FHeader.Mode = 8) then
|
|---|
| 419 | begin
|
|---|
| 420 | if FChannelCount = 1 then
|
|---|
| 421 | for Col:=0 to Img.Width-1 do
|
|---|
| 422 | begin
|
|---|
| 423 | C.Red:=BEtoN(PWord(P)^);
|
|---|
| 424 | C.green:=C.Red;
|
|---|
| 425 | C.blue:=C.Red;
|
|---|
| 426 | C.alpha:=65535;
|
|---|
| 427 | Img[col, row] := C;
|
|---|
| 428 | Inc(P,2);
|
|---|
| 429 | end else
|
|---|
| 430 | if FChannelCount = 2 then
|
|---|
| 431 | begin
|
|---|
| 432 | P1:=FScanLines[1];
|
|---|
| 433 | for Col:=0 to Img.Width-1 do
|
|---|
| 434 | begin
|
|---|
| 435 | C.Red:=P^ shl 8 + P^;
|
|---|
| 436 | C.green:=C.Red;
|
|---|
| 437 | C.blue:=C.Red;
|
|---|
| 438 | C.alpha:=p1^ shl 8 + P1^;
|
|---|
| 439 | Img[col, row] := C;
|
|---|
| 440 | Inc(P);
|
|---|
| 441 | Inc(P1);
|
|---|
| 442 | end;
|
|---|
| 443 | end;
|
|---|
| 444 | end else
|
|---|
| 445 | begin
|
|---|
| 446 | for Col:=0 to Img.Width-1 do
|
|---|
| 447 | begin
|
|---|
| 448 | Img.Colors[Col,Row]:=ThePalette[BEtoN(PWord(P)^)];
|
|---|
| 449 | inc(p,2);
|
|---|
| 450 | end;
|
|---|
| 451 | end;
|
|---|
| 452 | 24 : if FChannelCount>=3 then
|
|---|
| 453 | begin
|
|---|
| 454 | P1:=FScanLines[1];
|
|---|
| 455 | P2:=FScanLines[2];
|
|---|
| 456 | for Col:=0 to Img.Width-1 do
|
|---|
| 457 | begin
|
|---|
| 458 | if (FHeader.Mode =9) then
|
|---|
| 459 | begin
|
|---|
| 460 | Lab.L:=P[0];
|
|---|
| 461 | Lab.a:=P1[0];
|
|---|
| 462 | Lab.b:=P2[0];
|
|---|
| 463 | C:=LabToRGB(Lab);
|
|---|
| 464 | end
|
|---|
| 465 | else
|
|---|
| 466 | With C do
|
|---|
| 467 | begin
|
|---|
| 468 | Red:=P[0] or (P[0] shl 8);
|
|---|
| 469 | green:=P1[0] or (P1[0] shl 8);
|
|---|
| 470 | blue:=P2[0] or (P2[0] shl 8);
|
|---|
| 471 | alpha:=alphaOpaque;
|
|---|
| 472 | end;
|
|---|
| 473 | Inc(P);
|
|---|
| 474 | Inc(P1);
|
|---|
| 475 | Inc(P2);
|
|---|
| 476 | Img[col, row] := C;
|
|---|
| 477 | end;
|
|---|
| 478 | end;
|
|---|
| 479 | 32 : if (FHeader.Mode = 1) or (FHeader.Mode = 8) then
|
|---|
| 480 | begin
|
|---|
| 481 | if FChannelCount = 1 then
|
|---|
| 482 | for Col:=0 to Img.Width-1 do
|
|---|
| 483 | begin
|
|---|
| 484 | C.Red:=Value32To16(PDWord(P),1.3);
|
|---|
| 485 | C.green:=C.Red;
|
|---|
| 486 | C.blue:=C.Red;
|
|---|
| 487 | C.alpha:=65535;
|
|---|
| 488 | Img[col, row] := C;
|
|---|
| 489 | Inc(P,4);
|
|---|
| 490 | end else
|
|---|
| 491 | if FChannelCount = 2 then
|
|---|
| 492 | begin
|
|---|
| 493 | P1:=FScanLines[1];
|
|---|
| 494 | for Col:=0 to Img.Width-1 do
|
|---|
| 495 | begin
|
|---|
| 496 | C.Red:=BEtoN(PWord(P)^);
|
|---|
| 497 | C.green:=C.Red;
|
|---|
| 498 | C.blue:=C.Red;
|
|---|
| 499 | C.alpha:=BEtoN(PWord(p1)^);
|
|---|
| 500 | Img[col, row] := C;
|
|---|
| 501 | Inc(P,2);
|
|---|
| 502 | Inc(P1,2);
|
|---|
| 503 | end;
|
|---|
| 504 | end;
|
|---|
| 505 | end else
|
|---|
| 506 | if FChannelCount >= 4 then
|
|---|
| 507 | begin
|
|---|
| 508 | P1:=FScanLines[1];
|
|---|
| 509 | P2:=FScanLines[2];
|
|---|
| 510 | P3:=FScanLines[3];
|
|---|
| 511 | for Col:=0 to Img.Width-1 do
|
|---|
| 512 | begin
|
|---|
| 513 | if (FHeader.Mode =4) then
|
|---|
| 514 | begin
|
|---|
| 515 | P^ := 255 - P^;
|
|---|
| 516 | P1^ := 255 - P1^;
|
|---|
| 517 | P2^ := 255 - P2^;
|
|---|
| 518 | P3^ := 255 - P3^;
|
|---|
| 519 | end;
|
|---|
| 520 | C.Red:=P[0] or (P[0] shl 8);
|
|---|
| 521 | C.green:=P1[0] or (P1[0] shl 8);
|
|---|
| 522 | C.blue:=P2[0] or (P2[0] shl 8);
|
|---|
| 523 | C.alpha:=P3[0] or (P3[0] shl 8);
|
|---|
| 524 | if (FHeader.Mode =4) then C:=CMYKtoRGB(C); // CMYK to RGB
|
|---|
| 525 | Img[col, row] := C;
|
|---|
| 526 | Inc(P);
|
|---|
| 527 | Inc(P1);
|
|---|
| 528 | Inc(P2);
|
|---|
| 529 | Inc(P3);
|
|---|
| 530 | end;
|
|---|
| 531 | end;
|
|---|
| 532 | 48 :if FChannelCount = 3 then
|
|---|
| 533 | begin
|
|---|
| 534 | P1:=FScanLines[1];
|
|---|
| 535 | P2:=FScanLines[2];
|
|---|
| 536 | C.alpha:=alphaOpaque;
|
|---|
| 537 | for Col:=0 to Img.Width-1 do
|
|---|
| 538 | begin
|
|---|
| 539 | if (FHeader.Mode =9) then
|
|---|
| 540 | C := LabToRGB(BEtoN(PWord(P)^)/65535, (BEtoN(PWord(P1)^)-32768)/32767, (BEtoN(PWord(P2)^)-32768)/32767)
|
|---|
| 541 | else
|
|---|
| 542 | With C do
|
|---|
| 543 | begin
|
|---|
| 544 | Red:=BEtoN(PWord(P)^);
|
|---|
| 545 | green:=BEtoN(PWord(P1)^);
|
|---|
| 546 | blue:=BEtoN(PWord(P2)^);
|
|---|
| 547 | end;
|
|---|
| 548 | Inc(P,2);
|
|---|
| 549 | Inc(P1,2);
|
|---|
| 550 | Inc(P2,2);
|
|---|
| 551 | Img[col, row] := C;
|
|---|
| 552 | end;
|
|---|
| 553 | end;
|
|---|
| 554 | 64 : if FChannelCount = 4 then
|
|---|
| 555 | begin
|
|---|
| 556 | P1:=FScanLines[1];
|
|---|
| 557 | P2:=FScanLines[2];
|
|---|
| 558 | P3:=FScanLines[3];
|
|---|
| 559 | for Col:=0 to Img.Width-1 do
|
|---|
| 560 | begin
|
|---|
| 561 | C.Red:=BEtoN(PWord(P)^);
|
|---|
| 562 | C.green:=BEtoN(PWord(P1)^);
|
|---|
| 563 | C.blue:=BEtoN(PWord(P2)^);
|
|---|
| 564 | C.alpha:=BEtoN(PWord(P3)^);
|
|---|
| 565 | if (FHeader.Mode =4) then
|
|---|
| 566 | begin
|
|---|
| 567 | C.red:=$ffff-C.red;
|
|---|
| 568 | C.green:=$ffff-C.green;
|
|---|
| 569 | C.blue:=$ffff-C.blue;
|
|---|
| 570 | C.alpha:=$ffff-C.alpha;
|
|---|
| 571 | end;
|
|---|
| 572 | if (FHeader.Mode =4) then C:=CMYKtoRGB(C); // CMYK to RGB
|
|---|
| 573 | Img[col, row] := C;
|
|---|
| 574 | Inc(P,2);
|
|---|
| 575 | Inc(P1,2);
|
|---|
| 576 | Inc(P2,2);
|
|---|
| 577 | Inc(P3,2);
|
|---|
| 578 | end;
|
|---|
| 579 | end;
|
|---|
| 580 | 96 :if FChannelCount = 3 then
|
|---|
| 581 | begin
|
|---|
| 582 | P1:=FScanLines[1];
|
|---|
| 583 | P2:=FScanLines[2];
|
|---|
| 584 | C.alpha:=alphaOpaque;
|
|---|
| 585 | for Col:=0 to Img.Width-1 do
|
|---|
| 586 | begin
|
|---|
| 587 | With C do
|
|---|
| 588 | begin
|
|---|
| 589 | Red:=Value32To16(PDWord(P),2.7);
|
|---|
| 590 | green:=Value32To16(PDWord(P1),2.7);
|
|---|
| 591 | blue:=Value32To16(PDWord(P2),2.7);
|
|---|
| 592 | end;
|
|---|
| 593 | Inc(P,4);
|
|---|
| 594 | Inc(P1,4);
|
|---|
| 595 | Inc(P2,4);
|
|---|
| 596 | Img[col, row] := C;
|
|---|
| 597 | end;
|
|---|
| 598 | end;
|
|---|
| 599 | end;
|
|---|
| 600 | end;
|
|---|
| 601 | end;
|
|---|
| 602 |
|
|---|
| 603 | function TBGRAReaderPSD.InternalCheck(Stream: TStream): boolean;
|
|---|
| 604 | var
|
|---|
| 605 | OldPos: Int64;
|
|---|
| 606 | begin
|
|---|
| 607 | try
|
|---|
| 608 | OldPos:=Stream.Position;
|
|---|
| 609 | Stream.Read(FHeader,SizeOf(FHeader));
|
|---|
| 610 | Result:=(FHeader.Signature = '8BPS');
|
|---|
| 611 | Stream.Position:=OldPos;
|
|---|
| 612 | except
|
|---|
| 613 | Result:=False;
|
|---|
| 614 | end;
|
|---|
| 615 | end;
|
|---|
| 616 |
|
|---|
| 617 | constructor TBGRAReaderPSD.Create;
|
|---|
| 618 | begin
|
|---|
| 619 | inherited Create;
|
|---|
| 620 | end;
|
|---|
| 621 |
|
|---|
| 622 | initialization
|
|---|
| 623 |
|
|---|
| 624 | DefaultBGRAImageReader[ifPsd] := TBGRAReaderPSD;
|
|---|
| 625 |
|
|---|
| 626 | end.
|
|---|