📄 iepsd.pas
字号:
end;
// bypass extradata (should not be present)
Stream.Seek(ExtraDataSize, soFromCurrent);
// fill TIELayer data
layer:=TIELayer.Create(nil,nil,false);
layers.Add(layer);
layer.PosX:=LayersTemp[i].layerLeft;
layer.PosY:=LayersTemp[i].layerTop;
layer.Transparency:=LayersTemp[i].Opacity;
layer.Name:=LayersTemp[i].Name;
layer.Visible:=(LayersTemp[i].Flags and $2)=0;
layer.Cropped:=(LayersTemp[i].Clipping=0);
end;
k:=0; // index inside layers[] list
for i:=0 to layerscount-1 do
begin
// load layer image
for c:=0 to LayersTemp[i].numberChannels-1 do
begin
if LayersTemp[i].ChannelID[c]=-2 then
begin
// this is the layer mask
layer:=TIELayer.Create(nil,nil,false);
layers.Insert(k+1,layer);
layer.PosX:=LayersTemp[i].layermask_Left;
layer.PosY:=LayersTemp[i].layermask_Top;
layer.IsMask:=true;
layer.Visible:=false;
width:=LayersTemp[i].layermask_Right-LayersTemp[i].layermask_Left;
height:=LayersTemp[i].layermask_Bottom-LayersTemp[i].layermask_Top;
compression:=GetSmallint(Stream);
getmem(sizes,sizeof(word)*height);
if compression=1 then
Stream.Read(sizes^,sizeof(word)*height)
else
for j:=0 to height-1 do
sizes[j]:=IESwapWord(IEBitmapRowLen(width, header.Depth, 8));
cursize:=0;
ReadImageData(Stream,layer.Bitmap,width,height,8,1,nil,0,compression,sizes,cursize,0);
freemem(sizes);
end
else
begin
// this is a channel or alpha channel
if TIELayer(layers[k]).IsMask then
inc(k);
layer:=TIELayer(layers[k]);
width:=LayersTemp[i].layerRight-LayersTemp[i].layerLeft;
height:=LayersTemp[i].layerBottom-LayersTemp[i].layerTop;
compression:=GetSmallint(Stream);
getmem(sizes,sizeof(word)*height);
if compression=1 then
Stream.Read(sizes^,sizeof(word)*height)
else
for j:=0 to height-1 do
sizes[j]:=IESwapWord(IEBitmapRowLen(width, header.Depth, 8));
cursize:=0;
ReadImageData(Stream,layer.Bitmap,width,height,header.Depth,header.mode,colormap,transpindex,compression,sizes,cursize,LayersTemp[i].ChannelID[c]);
freemem(sizes);
end;
end;
inc(k);
if assigned(XProgress.fOnProgress) then
XProgress.fOnProgress(XProgress.Sender, trunc(i/layerscount*100));
end;
// free mem
for i:=0 to layerscount-1 do
begin
freemem(LayersTemp[i].ChannelID);
freemem(LayersTemp[i].ChannelLen);
for j:=0 to LayersTemp[i].adjustmentCount-1 do
freemem( LayersTemp[i].adjustment[j].data );
freemem( LayersTemp[i].adjustment );
end;
freemem(LayersTemp);
// go at global layer mask info
Stream.Position:=lpos1+layersinfolen+4;
globalmaskLength:=GetLongint(Stream);
if globalmaskLength>0 then
begin
(*globalmaskOverlayColorSpace:=*)GetSmallint(Stream);
for i:=0 to 3 do
globalmaskColorComponents[i]:=GetSmallint(Stream);
(*globalmaskOpacity:=*)GetSmallint(Stream);
(*globalmaskKind:=*)GetByte(Stream);
GetByte(Stream); // by pass
end;
// go to at end of layer and mask info
Stream.Position:=lpos1+layerslen;
end;
// remove zero size layers
if layers<>nil then
begin
i:=0;
while i<layers.Count do
if (TIELayer(layers[i]).Bitmap.Width=0) or (TIELayer(layers[i]).Bitmap.Height=0) then
begin
TIELayer(layers[i]).Free;
layers.Delete(i);
if (i<layers.Count-1) and TIELayer(layers[i]).IsMask then
begin
// remove also the layer mask
TIELayer(layers[i]).Free;
layers.Delete(i);
end;
end
else
inc(i);
end;
end;
end;
// blocksize: the size of block to read from Stream
// outbuf: output uncompressed buffer
procedure ReadRow(Stream:TStream; compression:word; outbuf:pbyte; sizes:pwordarray; var cursize:integer);
var
i:integer;
rp:byte;
tmprow:pbyte;
src:pbytearray;
dst:pbyte;
blocksize:integer;
begin
blocksize:=IESwapWord(sizes[cursize]);
case compression of
0: // RAW data
begin
Stream.Read(outbuf^,blocksize);
end;
1: // RLE
begin
getmem(tmprow,blocksize);
Stream.Read(tmprow^,blocksize);
src:=pbytearray(tmprow);
dst:=outbuf;
i:=0;
while i<blocksize do
begin
if (src[i] and $80)<>0 then
begin
// repeater
rp:=(not src[i])+2;
inc(i);
while rp>0 do
begin
dst^:=src[i];
inc(dst);
dec(rp);
end;
inc(i);
end
else
begin
// copy
rp:=src[i]+1;
inc(i);
while rp>0 do
begin
dst^:=src[i];
inc(dst);
inc(i);
dec(rp);
end;
end;
end;
freemem(tmprow);
end;
end;
{
according to Adobe specifiations row lengths should not be odd, but this seems contract with actual files
if (blocksize and $1)<>0 then
Stream.Seek(1,soFromCurrent);
}
inc(cursize);
end;
procedure CopyRow8(bitmap:TIEBitmap; row:integer; channel:integer; channelcount:integer; width:integer; inrow:pbyte);
var
pb1,pb2:pbyte;
i:integer;
begin
pb1:=Bitmap.Scanline[row]; inc(pb1,channel);
pb2:=inrow;
for i:=0 to width-1 do
begin
pb1^:=pb2^;
inc(pb1,channelcount);
inc(pb2);
end;
end;
procedure CopyRow16(bitmap:TIEBitmap; row:integer; channel:integer; channelcount:integer; width:integer; inrow:pbyte);
var
pw1,pw2:pword;
i:integer;
begin
pw1:=Bitmap.Scanline[row]; inc(pw1,channel);
pw2:=pword(inrow);
for i:=0 to width-1 do
begin
pw1^:=IESwapWord(pw2^);
inc(pw1,channelcount);
inc(pw2);
end;
end;
procedure CopyRow16to8(bitmap:TIEBitmap; row:integer; channel:integer; channelcount:integer; width:integer; inrow:pbyte);
var
pb1:pbyte;
pw2:pword;
i:integer;
begin
pb1:=Bitmap.Scanline[row]; inc(pb1,channel);
pw2:=pword(inrow);
for i:=0 to width-1 do
begin
pb1^:=pw2^ and $FF; // it is the same of "pb1^:=IESwapWord(pw2^) shr 8"
inc(pb1,channelcount);
inc(pw2);
end;
end;
procedure AdjustLab8(bitmap:TIEBitmap; row:integer; channel:integer; channelcount:integer; width:integer);
type
pshortint=^shortint;
var
p:pshortint;
i:integer;
begin
p:=Bitmap.Scanline[row]; inc(p,channel);
for i:=0 to width-1 do
begin
p^:=pbyte(p)^-128;
inc(p,channelcount);
end;
end;
procedure AdjustPaletteTransp(Bitmap:TIEBitmap; row:integer; transpindex:integer; width:integer);
var
i:integer;
p,a:pbyte;
begin
if transpindex>-1 then
begin
p:=Bitmap.Scanline[row];
a:=Bitmap.AlphaChannel.Scanline[row];
for i:=0 to width-1 do
begin
if p^=transpindex then
a^:=0
else
a^:=255;
inc(p);
inc(a);
end;
end;
end;
procedure LoadAlpha(Stream:TStream; AlphaBitmap:TIEBitmap;width,height,depth:integer; compression:integer; sizes:pwordarray; var cursize:integer; rowbuf:pbyte);
var
i:integer;
begin
for i:=0 to height-1 do
begin
ReadRow(Stream,compression,rowbuf,sizes,cursize);
case depth of
8: CopyRow8(AlphaBitmap,i,0,1,width,rowbuf);
16: CopyRow16to8(AlphaBitmap,i,0,1,width,rowbuf);
end;
end;
end;
// read image data section
procedure ReadImageData(Stream:TStream; Bitmap:TIEBitmap; width,height,depth,mode:integer; colormap:PColorMap; transpindex:integer; compression:smallint; sizes:pwordarray; var cursize:integer; channel:integer);
var
rowbuf:pbyte;
i:integer;
begin
getmem(rowbuf, IEBitmapRowLen(width, depth, 8));
case depth of
1: // depth=1
case mode of
0: // bitmap
begin
Bitmap.Allocate(width,height,ie1g);
if channel=0 then
for i:=0 to height-1 do
begin
ReadRow(Stream,compression,rowbuf,sizes,cursize);
CopyRow8(Bitmap,i,0,1,width div 8,rowbuf);
_NegativeBuffer(Bitmap.Scanline[i], width div 8);
end;
end;
end;
8: // depth=8
case mode of
1,8: // Gray Scale or duotone
begin
Bitmap.Allocate(width,height,ie8g);
if channel=0 then
for i:=0 to height-1 do
begin
ReadRow(Stream,compression,rowbuf,sizes,cursize);
CopyRow8(Bitmap,i,0,1,width,rowbuf);
end;
if (channel=1) or (channel=-1) then
LoadAlpha(Stream,Bitmap.AlphaChannel,width,height,depth,compression,sizes,cursize,rowbuf);
end;
2: // Indexed
begin
Bitmap.Allocate(width,height,ie8p);
if channel=0 then
begin
for i:=0 to 255 do
Bitmap.Palette[i]:=CreateRGB(colormap^[0][i],colormap^[1][i],colormap^[2][i]);
for i:=0 to height-1 do
begin
ReadRow(Stream,compression,rowbuf,sizes,cursize);
CopyRow8(Bitmap,i,0,1,width,rowbuf);
AdjustPaletteTransp(Bitmap,i,transpindex,width);
end;
end;
end;
3: // RGB
begin
Bitmap.Allocate(width,height,ie24RGB);
if (channel>=0) and (channel<3) then
for i:=0 to height-1 do
begin
ReadRow(Stream,compression,rowbuf,sizes,cursize);
CopyRow8(Bitmap,i,2-channel,3,width,rowbuf);
end;
if (channel=3) or (channel=-1) then
LoadAlpha(Stream,Bitmap.AlphaChannel,width,height,depth,compression,sizes,cursize,rowbuf);
end;
4: // CMYK
begin
Bitmap.Allocate(width,height,ieCMYK);
if (channel>=0) and (channel<4) then
for i:=0 to height-1 do
begin
ReadRow(Stream,compression,rowbuf,sizes,cursize);
CopyRow8(Bitmap,i,channel,4,width,rowbuf);
end;
if (channel=4) or (channel=-1) then
LoadAlpha(Stream,Bitmap.AlphaChannel,width,height,depth,compression,sizes,cursize,rowbuf);
end;
9: // Lab
begin
Bitmap.Allocate(width,height,ieCIELab);
if (channel>=0) and (channel<3) then
for i:=0 to height-1 do
begin
ReadRow(Stream,compression,rowbuf,sizes,cursize);
CopyRow8(Bitmap,i,channel,3,width,rowbuf);
if (channel=1) or (channel=2) then
AdjustLab8(Bitmap,i,channel,3,width);
end;
if (channel=3) or (channel=-1) then
LoadAlpha(Stream,Bitmap.AlphaChannel,width,height,depth,compression,sizes,cursize,rowbuf);
end;
end;
16: // depth=16
case mode of
1,8: // Gray Scale or duotone
begin
Bitmap.Allocate(width,height,ie16g);
if channel=0 then
for i:=0 to height-1 do
begin
ReadRow(Stream,compression,rowbuf,sizes,cursize);
CopyRow16(Bitmap,i,0,1,width,rowbuf);
end;
if (channel=1) or (channel=-1) then
LoadAlpha(Stream,Bitmap.AlphaChannel,width,height,depth,compression,sizes,cursize,rowbuf);
end;
3: // RGB
begin
Bitmap.Allocate(width,height,ie48RGB);
if (channel>=0) and (channel<3) then
for i:=0 to height-1 do
begin
ReadRow(Stream,compression,rowbuf,sizes,cursize);
CopyRow16(Bitmap,i,channel,3,width,rowbuf);
end;
if (channel=3) or (channel=-1) then
LoadAlpha(Stream,Bitmap.AlphaChannel,width,height,depth,compression,sizes,cursize,rowbuf);
end;
4: // CMYK
begin
Bitmap.Allocate(width,height,ieCMYK);
if (channel>=0) and (channel<4) then
for i:=0 to height-1 do
begin
ReadRow(Stream,compression,rowbuf,sizes,cursize);
CopyRow16to8(Bitmap,i,channel,4,width,rowbuf);
end;
if (channel=4) or (channel=-1) then
LoadAlpha(Stream,Bitmap.AlphaChannel,width,height,depth,compression,sizes,cursize,rowbuf);
end;
9: // Lab
begin
Bitmap.Allocate(width,height,ieCIELab);
if (channel>=0) and (channel<3) then
for i:=0 to height-1 do
begin
ReadRow(Stream,compression,rowbuf,sizes,cursize);
CopyRow16to8(Bitmap,i,channel,3,width,rowbuf);
if (channel=1) or (channel=2) then
AdjustLab8(Bitmap,i,channel,3,width);
end;
if (channel=3) or (channel=-1) then
LoadAlpha(Stream,Bitmap.AlphaChannel,width,height,depth,compression,sizes,cursize,rowbuf);
end;
end;
end;
freemem(rowbuf);
end;
// output is a list of TIELayer (output must be a created list)
// note: to do "Preview" set boths LoadLayers and LoadMergedImage to False
procedure IEReadPSD(Stream:TStream; MergedBitmap:TIEBitmap; var IOParams: TIOParamsVals; var Progress: TProgressRec; LoadLayers: boolean; layers:TList);
var
context:TPSDReaderContext;
compression:smallint;
cursize:integer;
sizes:pwordarray;
i:integer;
begin
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -