JPEG2PDF,JPEGtoPDF,JPG2PDF,JPGToPDF (Delphi SourceCode)


JPEG2PDF.PAS (7k)

// -----------------------------------------------------------------------------
// JPEG2PDF,JPEGtoPDF,JPG2PDF,JPGToPDF
//
//                                                                (C) 2003 PAPY
//                                             http://homepage1.nifty.com/MADIA/
// -----------------------------------------------------------------------------

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
     // Stream
     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;

     // Object
     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;  // Normal
 SOF2 : Word = $FFC2;  // Progressive
begin
   Result  := False;
   AStream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
   try
      // JFIF
      AStream.ReadBuffer(wrk,2); wrk:=SwapEndian(wrk);
      if wrk<>$FFD8 then Exit;

      While True do
      begin
         AStream.ReadBuffer(wrk,2); wrk:=SwapEndian(wrk);

         // JPEG Maker
         if (wrk= SOF0) or (wrk= SOF2)  then
         begin
             // Skip Segment Length 
             AStream.Position:= AStream.Position+2;
             // Skip Sample
             AStream.Position:= AStream.Position+1;
             // Height
             AStream.ReadBuffer(wrk,2); AHeight :=SwapEndian(wrk);
             // Width
             AStream.ReadBuffer(wrk,2); AWidth  :=SwapEndian(wrk);

             // ColorMode
             AStream.ReadBuffer(Sampling,1);
             case Sampling of
                3   : CMYK :=False;  // RGB
                4   : CMYK :=True    // CMYK
               else Break;           // ???
             end;

             Result :=True;
             Break;
         end
         else if (wrk=$FFFF) or (wrk=$FFD9) then
         begin
             Break;
         end;

         // Skip Segment@
         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          
     // PDF version
     TStringStream(AStream).WriteString('%PDF-1.2'#10);

     // Catalog
     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); // View Option (100%)       
          WriteString('>>'#10);
          WriteString('endobj'#10);
     end;
     Inc(ObjectIndex);
   
     // Parent Pages
     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);

     // Kids Page
     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);

     // XObject Resource
     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); // Photoshop CMYK (NOT BIT)
          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);

     // Contents Stream & Object
     ObjectPosArray[ObjectIndex] :=AStream.Position;
     With TStringStream(AStream) do
     begin
        Write_ContentsObject(AStream,ObjectIndex+1,W,H);
     end;
     Inc(ObjectIndex);

     // CrossReferenceTable
     ObjectPosArray[ObjectIndex] :=AStream.Position;
     Write_CrossReferenceTable(AStream,ObjectPosArray,ObjectIndex);

     // trailer
     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.