this slowpoke moves

Load PSD File to Image

type
  PRGB = ^TRGB;
  TRGB = packed record
   R, G, B: Byte;
  end;

  PCMYK = ^TCMYK;
  TCMYK = packed record
    C, M, Y, K: Byte;
  end;

  PCMYK16 = ^TCMYK16;
  TCMYK16 = packed record
    C, M, Y, K: Word;
  end;

  PBGR = ^TBGR;
  TBGR = packed record
   B, G, R: Byte;
  end;

  PRGBWord = ^TRGBWord;
  TRGBWord = record
   R, G, B: Word;
  end;

  TPSDHeader = packed record
    Signature: array[0..3] of Char;
    Version: Word;
    Reserved: array[0..5] of Byte;
    Channels: Word;
    Rows,
    Columns: Cardinal;
    Depth: Word;
    Mode: Word;
  end;

  TPSDGraphic = class(TBitmap)
  private
    FPalette: array[0..767] of Byte;
    procedure MakePalette(BPS: Byte; Mode: Integer);
  public
    procedure LoadFromStream(Stream: TStream); override;
  end;

  TPackbitsRLE = class
  public
    procedure Decode(var Source: Pointer; Dest: Pointer; PackedSize, UnpackedSize: Integer);
  end;
const
  PSD_BITMAP = 0;
  PSD_GRAYSCALE = 1;
  PSD_INDEXED = 2;
  PSD_RGB = 3;
  PSD_CMYK = 4;
  PSD_MULTICHANNEL = 7;
  PSD_DUOTONE = 8;
  PSD_LAB = 9;
  PSD_COMPRESSION_NONE = 0;
  PSD_COMPRESSION_RLE = 1;
procedure CIELAB2BGR(LSource, aSource, bSource: PByte; Target: Pointer; BitsPerSample: Byte; Count: Cardinal); overload;
var
 FinalR,FinalG, FinalB: Integer;
 l, a, b, X, Y, Z, T, YYn3: Double;
 TargetPtr: PByte;
 PixelCount: Cardinal;
begin
 TargetPtr := Target;
 PixelCount := Count div 3;

 while PixelCount > 0 do
  begin
   L := LSource^ / 2.55;
   Inc(LSource);
   a := ShortInt(aSource^);
   Inc(aSource);
   b := ShortInt(bSource^);
   Inc(bSource);

   YYn3 := (L + 16) / 116;
   if L < 7.9996 then
    begin
     Y := L / 903.3;
     X := a / 3893.5 + Y;
     Z := Y - b / 1557.4;
    end
   else
    begin
     T := YYn3 + a / 500;
     X := T * T * T;
     Y := YYn3 * YYn3 * YYn3;
     T := YYn3 - b / 200;
     Z := T * T * T;
    end;

   FinalR := Round(255 * ( 2.998 * X - 1.458 * Y - 0.541 * Z));
   FinalG := Round(255 * (-0.952 * X + 1.893 * Y + 0.059 * Z));
   FinalB := Round(255 * ( 0.099 * X - 0.198 * Y + 1.099 * Z));

   TargetPtr^ := Max(0, Min(255, FinalB));
   Inc(TargetPtr);
   TargetPtr^ := Max(0, Min(255, FinalG));
   Inc(TargetPtr);
   TargetPtr^ := Max(0, Min(255, FinalR));
   Inc(TargetPtr);

   Dec(PixelCount);
  end;
end;


procedure CMYK2BGR(C, M, Y, K, Target: Pointer; BitsPerSample: Byte; Count: Cardinal); overload;
var
 R, G, B: Integer;
 C8, M8, Y8, K8: PByte;
 C16, M16, Y16, K16: PWord;
 I: Integer;
 TargetPtr: PByte;
begin
 case BitsPerSample of
  8:
   begin
    C8 := C;
    M8 := M;
    Y8 := Y;
    K8 := K;
    TargetPtr := Target;
    Count := Count div 4;
    for I := 0 to Count - 1 do
     begin
      R := 255 - (C8^ - MulDiv(C8^, K8^, 255) + K8^);
      G := 255 - (M8^ - MulDiv(M8^, K8^, 255) + K8^);
      B := 255 - (Y8^ - MulDiv(Y8^, K8^, 255) + K8^);
      TargetPtr^ := Max(0, Min(255, B));
      Inc(TargetPtr);
      TargetPtr^ := Max(0, Min(255, G));
      Inc(TargetPtr);
      TargetPtr^ := Max(0, Min(255, R));
      Inc(TargetPtr);
      Inc(C8);
      Inc(M8);
      Inc(Y8);
      Inc(K8);
     end;
   end;
  16:
   begin
    C16 := C;
    M16 := M;
    Y16 := Y;
    K16 := K;
    TargetPtr := Target;
    Count := Count div 4;
    for I := 0 to Count - 1 do
     begin
      R := 255 - (C16^ - MulDiv(C16^, K16^, 65535) + K16^) shr 8;
      G := 255 - (M16^ - MulDiv(M16^, K16^, 65535) + K16^) shr 8;
      B := 255 - (Y16^ - MulDiv(Y16^, K16^, 65535) + K16^) shr 8;
      TargetPtr^ := Max(0, Min(255, B));
      Inc(TargetPtr);
      TargetPtr^ := Max(0, Min(255, G));
      Inc(TargetPtr);
      TargetPtr^ := Max(0, Min(255, R));
      Inc(TargetPtr);
      Inc(C16);
      Inc(M16);
      Inc(Y16);
      Inc(K16);
     end;
   end;
 end;
end;

procedure RGB2BGR(R, G, B, Target: Pointer; BitsPerSample: Byte; Count: Cardinal); overload;
var
 R8, G8, B8: PByte;
 R16, G16, B16: PWord;
 TargetRun: PByte;
begin
 Count := Count div 3;
 case BitsPerSample of
  8:
   begin
    R8 := R;
    G8 := G;
    B8 := B;
    TargetRun := Target;
    while Count > 0 do
     begin
      TargetRun^ := B8^;
      Inc(B8);
      Inc(TargetRun);
      TargetRun^ := G8^;
      Inc(G8);
      Inc(TargetRun);
      TargetRun^ := R8^;
      Inc(R8);
      Inc(TargetRun);
      Dec(Count);
     end;
   end;
  16:
   begin
    R16 := R;
    G16 := G;
    B16 := B;
    TargetRun := Target;
    while Count > 0 do
     begin
      TargetRun^ := B16^ shr 8;
      Inc(B16);
      Inc(TargetRun);
      TargetRun^ := G16^ shr 8;
      Inc(G16);
      Inc(TargetRun);
      TargetRun^ := R16^ shr 8;
      Inc(R16);
      Inc(TargetRun);
      Dec(Count);
     end;
   end;
  end;
end;

procedure SwapShort(P: PWord; Count: Cardinal);
asm
 @@Loop:
  MOV CX, [EAX]
  XCHG CH, CL
  MOV [EAX], CX
  ADD EAX, 2
  DEC EDX
  JNZ @@Loop
end;

procedure SwapLong(P: PInteger; Count: Cardinal); overload;
asm
 @@Loop:
  MOV ECX, [EAX]
  BSWAP ECX
  MOV [EAX], ECX
  ADD EAX, 4
  DEC EDX
  JNZ @@Loop
end;

function SwapLong(Value: Cardinal): Cardinal; overload;
asm
 BSWAP EAX
end;

procedure TPackbitsRLE.Decode(var Source: Pointer; Dest: Pointer; PackedSize, UnpackedSize: Integer);
var
 SourcePtr,TargetPtr: PByte;
 N: SmallInt;
begin
 TargetPtr := Dest;
 SourcePtr := Source;
 while PackedSize > 0 do
  begin
   N := ShortInt(SourcePtr^);
   Inc(SourcePtr);
   Dec(PackedSize);
   if N < 0 then
    begin
     if N = -128 then Continue;
     N := -N + 1;
     FillChar(TargetPtr^, N, SourcePtr^);
     Inc(SourcePtr);
     Inc(TargetPtr, N);
     Dec(PackedSize);
    end
   else
    begin
     Move(SourcePtr^, TargetPtr^, N + 1);
     Inc(TargetPtr, N + 1);
     Inc(SourcePtr, N + 1);
     Dec(PackedSize, N + 1);
    end;
  end;
end;

procedure TPSDGraphic.MakePalette(BPS: Byte; Mode: Integer);
var
 Pal: TMaxLogPalette;
 hpal: HPALETTE;
 I: Integer;
 EntryCount: Word;
begin
 case BPS of
  1:
   EntryCount := 1;
  4:
   EntryCount := 15;
  else
   EntryCount := 255;
 end;

 Pal.palVersion := $300;
 Pal.palNumEntries := 1 + EntryCount;
 case BPS of
  1:
   begin
    Pal.palPalEntry[0].peRed := 255;
    Pal.palPalEntry[0].peGreen  := 255;
    Pal.palPalEntry[0].peBlue := 255;
    Pal.palPalEntry[0].peFlags := 0;
    Pal.palPalEntry[1].peRed := 0;
    Pal.palPalEntry[1].peGreen  := 0;
    Pal.palPalEntry[1].peBlue := 0;
    Pal.palPalEntry[1].peFlags := 0;
   end;
  else
   case Mode  of
    PSD_DUOTONE,
    PSD_GRAYSCALE:
     for I :=  0 to EntryCount do
      begin
       Pal.palPalEntry[I].peRed := I;
       Pal.palPalEntry[I].peGreen := I;
       Pal.palPalEntry[I].peBlue := I;
       Pal.palPalEntry[I].peFlags := 0;
      end;
    else
     for I := 0 to EntryCount do
      begin
       Pal.palPalEntry[I].peRed := FPalette[0 * 256 + I];
       Pal.palPalEntry[I].peGreen := FPalette[1 * 256 + I];
       Pal.palPalEntry[I].peBlue := FPalette[2 * 256 + I];
       Pal.palPalEntry[I].peFlags := 0;
      end;
   end;
  end;
 hpal := CreatePalette(PLogPalette(@Pal)^);
 if hpal <> 0 then Palette := hpal;
end;

procedure TPSDGraphic.LoadFromStream(Stream: TStream);
var
  Header: TPSDHeader;
  Count: Integer;
  Compression: Word;
  Decoder: TPackbitsRLE;
  RLELength: array of Word;

  Y: Integer;
  BPS: Integer;
  ChannelSize: Integer;
  RawBuffer, Buffer: Pointer;
  Run1, Run2, Run3, Run4: PByte;
begin
 with Stream do
  begin
   ReadBuffer(Header, SizeOf(Header));
   if Header.Signature <> '8BPS' then raise Exception.Create('Íåâåðíûé ôàéë');
   with Header do
    begin
     Channels := Swap(Channels);
     Rows := SwapLong(Rows);
     Columns := SwapLong(Columns);
     Depth := Swap(Depth);
     Mode := Swap(Mode);
    end;

   case Header.Mode of
    PSD_BITMAP: PixelFormat := pf1Bit;
    PSD_DUOTONE, PSD_GRAYSCALE, PSD_INDEXED: PixelFormat := pf8Bit;
    PSD_RGB: PixelFormat := pf24Bit;
    PSD_CMYK: PixelFormat := pf24Bit;
    PSD_MULTICHANNEL: ;
    PSD_LAB: PixelFormat := pf24Bit;
   end;
  ReadBuffer(Count, SizeOf(Count));
  Count := SwapLong(Count);

  if Header.Mode in [PSD_BITMAP, PSD_GRAYSCALE, PSD_INDEXED] then
   begin
    if Header.Mode = PSD_INDEXED then ReadBuffer(FPalette, Count);
    MakePalette(Header.Depth, Header.Mode);
   end;

  Width := Header.Columns;
  Height := Header.Rows;

  ReadBuffer(Count, SizeOf(Count));
  Count := SwapLong(Count);
  Seek(Count, soFromCurrent);
  ReadBuffer(Count, SizeOf(Count));
  Count := SwapLong(Count);
  Seek(Count, soFromCurrent);

  RawBuffer := nil;

  ReadBuffer(Compression, SizeOf(Compression));
  Compression := Swap(Compression);
  if Compression = 1 then
   begin
    Decoder := TPackbitsRLE.Create;
    SetLength(RLELength, Header.Rows * Header.Channels);
    ReadBuffer(RLELength[0], 2 * Length(RLELength));
    SwapShort(@RLELength[0], Header.Rows * Header.Channels);
   end
  else
   Decoder := nil;

  try
   case Header.Mode of
    PSD_BITMAP,PSD_DUOTONE,PSD_GRAYSCALE,PSD_INDEXED:
     begin
      if Assigned(Decoder) then
       begin
        Count := 0;
        for Y := 0 to Height - 1 do Inc(Count, RLELength[Y]);
         GetMem(RawBuffer, Count);
        ReadBuffer(RawBuffer^, Count);
        Run1 := RawBuffer;
        for Y := 0 to Height - 1 do
         begin
          Count := RLELength[Y];
          Decoder.Decode(Pointer(Run1), ScanLine[Y], Count, Width);
          Inc(Run1, Count);
         end;
        FreeMem(RawBuffer);
       end
      else 
       for Y := 0 to Height - 1 do
        ReadBuffer(ScanLine[Y]^, Width);
     end;
    PSD_RGB,PSD_CMYK,PSD_LAB:
     begin
      BPS := Header.Depth div 8;
      ChannelSize := BPS * Width * Height;

      GetMem(Buffer, Header.Channels * ChannelSize);

      if Assigned(Decoder) then
       begin
        Count := 0;
        for Y := 0 to High(RLELength) do
         Inc(Count, RLELength[Y]);
        Count := Count * BPS;
        GetMem(RawBuffer, Count);
        Run1 := RawBuffer;
        ReadBuffer(RawBuffer^, Count);
        Decoder.Decode(RawBuffer, Buffer, Count, Header.Channels * ChannelSize);
        FreeMem(RawBuffer);
       end
      else
       begin
        ReadBuffer(Buffer^, Header.Channels * ChannelSize);
        if BPS = 2 then
         SwapShort(Buffer, Header.Channels * ChannelSize div 2);
       end;

      case Header.Mode of
       PSD_RGB:
        begin
         Run1 := Buffer;
         Run2 := Run1; Inc(Run2, ChannelSize);
         Run3 := Run2; Inc(Run3, ChannelSize);
         for Y := 0 to Height - 1 do
          begin
           RGB2BGR(Run1, Run2, Run3, Scanline[Y], Header.Depth, 3 * Width);
           Inc(Run1, BPS * Width);
           Inc(Run2, BPS * Width);
           Inc(Run3, BPS * Width);
          end;
        end;
       PSD_CMYK:
        begin
         Run1 := Buffer;
         for Y := 1 to 4 * ChannelSize do
          begin
           Run1^ := 255 - Run1^;
           Inc(Run1);
          end;

         Run1 := Buffer;
         Run2 := Run1; Inc(Run2, ChannelSize);
         Run3 := Run2; Inc(Run3, ChannelSize);
         Run4 := Run3; Inc(Run4, ChannelSize);
         for Y := 0 to Height - 1 do
          begin
           CMYK2BGR(Run1, Run2, Run3, Run4, ScanLine[Y], Header.Depth, 4 * Width);
           Inc(Run1, BPS * Width);
           Inc(Run2, BPS * Width);
           Inc(Run3, BPS * Width);
           Inc(Run4, BPS * Width);
          end;
        end;
       PSD_LAB:
        begin
         Run1 := Buffer; Inc(Run1, ChannelSize);
         for Y := 1 to 2 * ChannelSize do
          begin
           Run1^ := Run1^ - 128;
           Inc(Run1);
          end;
         Run1 := Buffer;
         Run2 := Run1; Inc(Run2, ChannelSize);
         Run3 := Run2; Inc(Run3, ChannelSize);
         for Y := 0 to Height - 1 do
          begin
           CIELAB2BGR(Run1, Run2, Run3, ScanLine[Y], Header.Depth, 3 * Width);
           Inc(Run1, BPS * Width);
           Inc(Run2, BPS * Width);
           Inc(Run3, BPS * Width);
          end;
        end;
      end;
     end;
   end;
  finally
   Decoder.Free;
  end;
 end;
end;
Beispiel :
procedure TForm1.Button1Click(Sender: TObject);
var
 r:TPSDGraphic;
begin
 if OpenDialog1.Execute then
  begin
   r:=TPSDGraphic.Create;
   r.LoadFromFile(OpenDialog1.FileName);
   Image1.Picture.Bitmap.Assign(r);
   r.Free;
  end;
end;

Keine Kommentare:

Kommentar veröffentlichen

Beliebte Posts

Translate