unit jpeg2pdf;
interface
uses
Windows,Classes, Graphics, SysUtils;
procedure JPGtoPDF(FileName,SaveName:String);
implementation
procedure Write_CrossReferenceTable(AStream: TStream;PosArray : array of Dword;Count:Integer);
Var
i :Integer;
begin
With TStringStream(AStream) do
begin
WriteString('xref'#10);
WriteString(Format('0 %d'#10,[Count+1]));
WriteString('0000000000 65535 f '#10);
for i:= 0 to Count-1 do
begin
WriteString(Format('%0.10d',[PosArray[i]])+' 00000 n '#10);
end;
end;
end;
procedure Write_ContentsObject(AStream: TStream;Index : Dword; Width,Height : Integer);
Var
MemoryStream : TMemoryStream;
begin
MemoryStream:=TMemoryStream.Create;
Try
With TStringStream(MemoryStream) do
begin
WriteString('q'#10);
WriteString(Format('%d 0 0 %d 0 0 cm'#10,[Width,Height]));
WriteString('/Im0 Do'#10);
WriteString('Q'#10);
end;
MemoryStream.Position:=0;
With TStringStream(AStream) do
begin
WriteString(Format('%d 0 obj'#10,[Index]));
WriteString(Format('<< /Length %d >>'#10,[MemoryStream.Size]));
WriteString('stream'#10);
AStream.CopyFrom(MemoryStream,MemoryStream.Size) ;
WriteString('endstream'#10);
WriteString('endobj'#10);
end;
finally
MemoryStream.Free;
end;
end;
function SwapEndian(S :word):word;
begin
Result :=(S and $00FF) shl 8 + (S and $FF00) shr 8 ;
end;
function GetJPEGSize(FileName:String;var AWidth,AHeight:Integer;var CMYK :Boolean):Boolean;
var
wrk : Word ;
Sampling : Byte;
AStream : TStream;
const
SOF0 : Word = $FFC0;
SOF2 : Word = $FFC2;
begin
Result := False;
AStream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
try
AStream.ReadBuffer(wrk,2); wrk:=SwapEndian(wrk);
if wrk<>$FFD8 then Exit;
While True do
begin
AStream.ReadBuffer(wrk,2); wrk:=SwapEndian(wrk);
if (wrk= SOF0) or (wrk= SOF2) then
begin
AStream.Position:= AStream.Position+2;
AStream.Position:= AStream.Position+1;
AStream.ReadBuffer(wrk,2); AHeight :=SwapEndian(wrk);
AStream.ReadBuffer(wrk,2); AWidth :=SwapEndian(wrk);
AStream.ReadBuffer(Sampling,1);
case Sampling of
3 : CMYK :=False;
4 : CMYK :=True
else Break;
end;
Result :=True;
Break;
end
else if (wrk=$FFFF) or (wrk=$FFD9) then
begin
Break;
end;
AStream.ReadBuffer(wrk,2); wrk:=SwapEndian(wrk);
AStream.Position:= AStream.Position+(wrk-2);
end;
finally
AStream.Free;
end;
end;
procedure JPGtoPDF(FileName,SaveName:String);
Var
CMYK : Boolean;
AStream,JPGStream : TStream;
ObjectIndex,W,H : Integer;
ObjectPosArray : array [0..10] of Dword;
begin
if FileName='' then
raise Exception.Create('FileName is nil');
if SaveName='' then
raise Exception.Create('SaveName is nil');
if not GetJPEGSize(FileName,W,H,CMYK) then Exit;
ObjectIndex :=0;
AStream :=TFileStream.Create(SaveName,fmCreate) ;
JPGStream :=TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
Try
TStringStream(AStream).WriteString('%PDF-1.2'#10);
ObjectPosArray[ObjectIndex] :=AStream.Position;
With TStringStream(AStream) do
begin
WriteString(Format('%d 0 obj'#10,[ObjectIndex+1]));
WriteString('<<'#10);
WriteString('/Type /Catalog'#10);
WriteString('/Pages 2 0 R'#10);
WriteString('/OpenAction [3 0 R /XYZ -32768 -32768 1 ]'#10);
WriteString('>>'#10);
WriteString('endobj'#10);
end;
Inc(ObjectIndex);
ObjectPosArray[ObjectIndex] :=AStream.Position;
With TStringStream(AStream) do
begin
WriteString(Format('%d 0 obj'#10,[ObjectIndex+1]));
WriteString('<<'#10);
WriteString('/Type /Pages'#10);
WriteString('/Kids [ 3 0 R ]'#10);
WriteString('/Count 1'#10);
WriteString('>>'#10);
WriteString('endobj'#10);
end;
Inc(ObjectIndex);
ObjectPosArray[ObjectIndex] :=AStream.Position;
With TStringStream(AStream) do
begin
WriteString(Format('%d 0 obj'#10,[ObjectIndex+1]));
WriteString('<<'#10);
WriteString('/Type /Page'#10);
WriteString('/Parent 2 0 R'#10);
WriteString('/Resources'#10);
WriteString('<<'#10);
WriteString('/XObject << /Im0 4 0 R >>'#10);
WriteString('/ProcSet [ /PDF /ImageC ]'#10);
WriteString('>>'#10);
WriteString(Format('/MediaBox [ 0 0 %d %d ]'#10, [W,H]));
WriteString('/Contents 5 0 R'#10);
WriteString('>>'#10);
WriteString('endobj'#10);
end;
Inc(ObjectIndex);
ObjectPosArray[ObjectIndex] :=AStream.Position;
With TStringStream(AStream) do
begin
WriteString(Format('%d 0 obj'#10,[ObjectIndex+1]));
WriteString('<<'#10);
WriteString('/Type /XObject'#10);
WriteString('/Subtype /Image'#10);
WriteString('/Name /Im0'#10);
WriteString(Format('/Width %d'#10,[W]));
WriteString(Format('/Height %d'#10,[H]));
WriteString('/BitsPerComponent 8'#10);
WriteString('/Filter [/DCTDecode]'#10);
if not CMYK then
WriteString('/ColorSpace /DeviceRGB'#10)
else
begin
WriteString('/ColorSpace /DeviceCMYK'#10);
WriteString('/Decode[1 0 1 0 1 0 1 0]'#10);
end;
WriteString(Format('/Length %d >>'#10,[JPGStream.Size]));
WriteString('stream'#10);
AStream.CopyFrom(JPGStream,JPGStream.Size);
WriteString('endstream'#10);
WriteString('endobj'#10);
end;
Inc(ObjectIndex);
ObjectPosArray[ObjectIndex] :=AStream.Position;
With TStringStream(AStream) do
begin
Write_ContentsObject(AStream,ObjectIndex+1,W,H);
end;
Inc(ObjectIndex);
ObjectPosArray[ObjectIndex] :=AStream.Position;
Write_CrossReferenceTable(AStream,ObjectPosArray,ObjectIndex);
With TStringStream(AStream) do
begin
WriteString('trailer'#10);
WriteString('<<'#10);
WriteString(Format('/Size %d'#10,[ObjectIndex+1]));
WriteString('/Root 1 0 R'#10);
WriteString('>>'#10);
WriteString('startxref'#10);
WriteString(Format('%d'#10,[ObjectPosArray[ObjectIndex]]));
WriteString('%%EOF');
end;
finally
AStream.Free;
JPGStream.Free;
end;
end;
end.
|