2011-12-05 4 views
7

Adobe에서 제공 한 this document의 정보를 기반으로 간단한 PDF 문서를 작성하는 루틴을 작성 중입니다. 텍스트와 도형에 대한 스트림을 만드는 것은 간단하지만 이미지를 삽입하는 데 어려움이 있습니다.이미지 파일을 PDF로 스트림 변환

누구나 파일 (gif, bmp, jpg 등의 이미지 형식은 괜찮을 것입니다)을 PDF 스트림으로 변환하는 방법에 대한 간단한 설명을 제공 할 수 있습니까? PDF 파일 전체를 생성하고 싶지는 않지만 파일 내의 스트림 만 만들려고합니다.

내가 사용할 수있는 앱을 사용하면 전체 스트림이 처음부터 끝까지 인코딩되기 때문에 다른 곳에서 수행되는 방식을 볼 수 없습니다. 해결 방법은이 인코딩 방법입니다.

전체를 PDF 파일 휠로 다시 만들고 싶지는 않지만이 특정 부분이 어떻게 작동하는지 이해하고 싶습니다. 따라서 라이브러리를 사용하지 않으려합니다 (따라서 언어를 언급하지 않은 이유 나는 사용하고있다).

답변

10

콘텐츠 스트림 내에서 Do 연산자를 사용해야합니다. 예 :

.... /Im1 Do ....... 

Im1

는 페이지의 리소스 사전 예컨대

에서 XObject에 자원을 지칭

In the page dictionary ... 
<< 

... 
/Contents 1 0 R 
/Resources << /XObject << /Im1 2 0 R >> >> 
... 
>> 

개체 2 화상 XObject에 것 0 R :

2 0 obj << /Type /XObject /Subtype /Image /Width 100 /Height 100 /ColorSpace /DeviceRGB /BitsPerComponent 8 /Length 10000 /Filter /DCTDecode >> 
stream 
JPEG DATA HERE 
endstream 
endobj 

몇 노트 : - 이미지 위치 지정 및 크기 조정 cm 연산자를 사용하여 현재 그래픽 행렬을 설정해야합니다. 예를 들어

150 0 0 150 100 100 cm 

(100,100)에 화상을 배치하고있는 이미지 폭 및 150150 높은 것.

  • 당신은 JPEG 파일로 제한하지 않는 - 당신이

  • 이 모든 것을 가지고있는 스펙의 섹션 (필터를 생략) JPEG2000s (사용/필터 =/JPXDecode) 또는 비트 맵 픽셀 데이터를 사용할 수 있습니다 내가 LZW 디코딩 실험을하지 않은 8.9

  • 입니다에 - 그 이미지를 표시 할 때 일반적으로 스택에 그래픽 상태를 밀어 GIF

  • 위해 일할 수있는 것 같아요. 예 :

    q a b c d e f cm /Im1 Do Q

Q 및 Q 작업자는 밀고 그래픽 상태 팝 (중대 cm 연산자!)

+0

대단히 고맙습니다. 당신은 스타입니다! 당신의 대답은 제가 필요한 것입니다. – blankabout

+0

probs 없음, 기꺼이 내가 도울 수 – Jimmy

+1

꽤 늦은 질문; 하지만 이미지에서 스트림 데이터 자체를 어떻게 얻습니까? 비트 맵 픽셀 데이터를 말할 때, 당신은 무엇을 의미합니까? – user1810737

5

간단한 C# 프로그램을 상기에 기초 JPG에서 PDF를 만들 여기에서 찾을 수 있습니다.

"stream"이라는 단어와 실제 jpg-stream을 \ n (또는 \ r \ n)으로 구분해야한다는 점에 유의하십시오 !!!

안부 Eske 란 (Rahn)

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.IO; 
using System.Drawing; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void WriStr(FileStream Out, string s) 
     { 
      Out.Write(System.Text.Encoding.ASCII.GetBytes(s), 0, s.Length); 
     } 
     static void Main(string[] args) 
     { 

      string InJpg = @"InFile.JPG"; 
      string OutPdf = @"OutFile.pdf"; 

      byte[] buffer = new byte[8192]; 
      var stream = File.OpenRead(InJpg); // The easiest way to get the metadata is to temporaryly load it as a BMP 
      Bitmap bmp = (Bitmap)Bitmap.FromStream(stream); 
      int w = bmp.Width; String wf = (w * 72/bmp.HorizontalResolution).ToString().Replace(",", "."); 
      int h = bmp.Height; ; string hf = (h * 72/bmp.VerticalResolution).ToString().Replace(",", "."); 
      stream.Close(); 

      FileStream Out = File.Create(OutPdf); 

      var lens = new List<long>(); 

      WriStr(Out, "%PDF-1.5\r\n"); 

      lens.Add(Out.Position); 
      WriStr(Out, lens.Count.ToString() + " 0 obj " + "<</Type /Catalog\r\n/Pages 2 0 R>>\r\nendobj\r\n"); 

      lens.Add(Out.Position); 
      WriStr(Out, lens.Count.ToString() + " 0 obj " + "<</Count 1/Kids [ <<\r\n" + 
         "/Type /Page\r\n" + 
         "/Parent 2 0 R\r\n" + 
         "/MediaBox [0 0 " + wf + " " + hf + "]\r\n" + 
         "/Resources<< /ProcSet [/PDF /ImageC]\r\n /XObject <</Im1 4 0 R >> >>\r\n" + 
         "/Contents 3 0 R\r\n" + 
         ">>\r\n ]\r\n" + 
         ">>\r\nendobj\r\n"); 

      string X = "\r\n" + 
       "q\r\n" + 
       "" + wf + " 0 0 " + hf + " 0 0 cm\r\n" + 
       "/Im1 Do\r\n" + 
       "Q\r\n"; 
      lens.Add(Out.Position); 
      WriStr(Out, lens.Count.ToString() + " 0 obj " + "<</Length " + X.Length.ToString() + ">>" + 
         "stream" + X + "endstream\r\n" + 
         "endobj\r\n"); 
      lens.Add(Out.Position); 
      WriStr(Out, lens.Count.ToString() + " 0 obj " + "<</Name /Im1" + 
         "/Type /XObject\r\n" + 
         "/Subtype /Image\r\n" + 
         "/Width " + w.ToString() + 
         "/Height " + h.ToString() + 
         "/Length 5 0 R\r\n" + 
         "/Filter /DCTDecode\r\n" + 
         "/ColorSpace /DeviceRGB\r\n" + 
         "/BitsPerComponent 8\r\n" + 
         ">> stream\r\n"); 
      long Siz = Out.Position; 
      var in1 = File.OpenRead(InJpg); 
      while (true) 
      { 
       var len = in1.Read(buffer, 0, buffer.Length); 
       if (len != 0) Out.Write(buffer, 0, len); else break; 
      } 
      in1.Close(); 
      Siz = Out.Position - Siz; 
      WriStr(Out, "\r\nendstream\r\n" + 
         "endobj\r\n"); 

      lens.Add(Out.Position); 
      WriStr(Out, lens.Count.ToString() + " 0 obj " + Siz.ToString() + " endobj\r\n"); 

      long startxref = Out.Position; 

      WriStr(Out, "xref\r\n" + 
         "0 " + (lens.Count + 1).ToString() + "\r\n" + 
         "0000000000 65535 f\r\n"); 
      foreach (var L in lens) 
       WriStr(Out, (10000000000 + L).ToString().Substring(1) + " 00000 n\r\n"); 
      WriStr(Out, "trailer\r\n" + 
         "<<\r\n" + 
         " /Size " + (lens.Count + 1).ToString() + "\r\n" + 
         " /Root 1 0 R\r\n" + 
         ">>\r\n" + 
         "startxref\r\n" + 
         startxref.ToString() + "\r\n%%EOF"); 
      Out.Close(); 
     } 
    } 
} 

2016년 4월 7일 ADD : 여기

스케일링 및 멀티 JPG 페이지와에 대한 최신 의견 버전, 지원입니다 전체 프로그램 주 래퍼 (추가 기능이 추가하기 쉽기 때문에 생략하지 않는 것이 유감 스럽습니다 ...)

using System; 
using System.Collections.Generic; 
//using System.Linq; 
using System.Text; 
using System.Drawing; 
using System.IO; 

namespace Jpg2Pdfdir 
{ 
    class Program 
    { 
     static void WriStr(FileStream Out, string s, params object[] args) 
     { 
      s = string.Format(s, args); 
      Out.Write(System.Text.Encoding.ASCII.GetBytes(s), 0, s.Length); 
     } 
     //Combined from http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/pdf/pdfs/PDF32000_2008.pdf 

     /// <summary> 
     /// Create a pdf from a list of jpgs, optionally stretching&compressing them. (Note the scaling is a display&print thing only, the jpg_stream itself is included unchanged) 
     /// </summary> 
     /// <param name="InJpgs">List of Jpg (full)names</param> 
     /// <param name="OutPdf">Name of the pdf to create</param> 
     /// <param name="StretchWs">For each jpg the width-scaling factor, fall back to the last given, and if none to 1.0</param> 
     /// <param name="StretchHs">For each jpg the height scalling, none positive or missing value is replaced with the width scale value (to keep aspect ratio)</param> 
     static void JpgToPdf(List<string> InJpgs, string OutPdf, List<Double> StretchWs, List<Double> StretchHs) 
     { 
      if (StretchWs==null || StretchWs.Count==0)StretchWs=new List<double>{1.0}; //default to unchanged 
      if (StretchHs==null)StretchHs=new List<double>{}; //Default to all with same aspect ratio 

      byte[] buffer = new byte[8192]; 
      int[] ws = new int[InJpgs.Count]; 
      int[] hs = new int[InJpgs.Count]; 
      string[] wfs = new string[InJpgs.Count]; 
      string[] hfs = new string[InJpgs.Count]; 
      for (int i=0;i<InJpgs.Count;i++) { 
       double StretchW=i<StretchWs.Count?StretchWs[i]:StretchWs[StretchWs.Count-1]; // Fall back to the last 
       double StretchH=i<StretchHs.Count && 0<StretchHs[i]?StretchHs[i]:StretchW; //Fall back to same X-Y scale. 
       System.IO.FileStream stream = File.OpenRead(InJpgs[i]); 
       // The easiest way to get the metadata is to temporaryly load the file, ignoring the ImageData! 
       using (Image Img = Image.FromStream(stream,false, false)) { //Last parameter: vaildateImageData=FALSE 
        ws[i] = Img.Width ; wfs[i] = (ws[i] * StretchW * 72/Img.HorizontalResolution).ToString(System.Globalization.CultureInfo.InvariantCulture); 
        hs[i] = Img.Height; hfs[i] = (hs[i] * StretchH * 72/Img.VerticalResolution ).ToString(System.Globalization.CultureInfo.InvariantCulture); 
       } 
       stream.Close(); 
      } 

      FileStream Out = File.Create(OutPdf); 

      //Holds the object-positions (Or lengths before) 
      var lens = new List<long>(); 

      //Must have header 
      WriStr(Out, "%PDF-1.5\r\n"); 

      //Obj 1 The catalog, pointing to the pages in object 2 
      lens.Add(Out.Position); 
      WriStr(Out, "{0} 0 obj " + "<</Type /Catalog\r\n/Pages 2 0 R>>\r\nendobj\r\n", lens.Count); 

      //Obj 2 The pageS, with inline object for the Kids object of type Page 
      //Note the size in the MediaBox, The resource for the image in object 4 (Streams can not be inline objects) 
      //And the Contents in object 3, and that the Parent of the Page points back to object 2 self. 
      lens.Add(Out.Position); 
      String Pages = ""; 
      for (int i = 0; i < InJpgs.Count; i++) { 
       Pages+= "<<\r\n"+ 
         "/Type /Page\r\n" + 
         "/Parent 2 0 R\r\n" + 
         "/MediaBox [0 0 " + wfs[i] + " " + hfs[i] + "]\r\n" + 
         "/Resources << /XObject <</Im"+(1+i).ToString()+" "+(4+3*i).ToString()+" 0 R >> >>\r\n" + 
         "/Contents "+(3+3*i).ToString()+" 0 R\r\n" + 
         ">>\r\n"; 
      } 
      WriStr(Out, "{0} 0 obj <</Type /Pages /Count {1} /Kids [{2}]\r\n" + 
         ">>\r\nendobj\r\n", lens.Count, InJpgs.Count, Pages); 

      for (int i = 0; i < InJpgs.Count; i++) { 

       // Obj 3+3i. The command stream to do the image Im# in a string, so the length can be evaluated. Note this is WITHOUT the leading and trailing CRLF 
       string X = 
        "q\r\n" + 
        "" + wfs[i] + " 0 0 " + hfs[i] + " 0 0 cm\r\n" + 
        "/Im"+(1+i).ToString()+" Do\r\n" + 
        "Q"; 
       lens.Add(Out.Position); 
       WriStr(Out, lens.Count.ToString() + " 0 obj <</Length {0}>> stream\r\n" + 
          "{1}\r\n" + 
          "endstream\r\n" + 
          "endobj\r\n", X.Length, X); 

       // Obj 4+3i of type XObject containing the jpg-stream, and with a reference to the length that will be stored in object 5 when known 
       lens.Add(Out.Position); 
       WriStr(Out, "{0} 0 obj <</Name /Im{1}" + 
          "/Type /XObject\r\n" + 
          "/Subtype /Image\r\n" + 
          "/Width {2}"+ 
          "/Height {3}"+ 
          "/Length {4} 0 R\r\n" + 
          "/Filter /DCTDecode\r\n" + 
          "/ColorSpace /DeviceRGB\r\n" + 
          "/BitsPerComponent 8\r\n" + 
          ">> stream\r\n", lens.Count, 1+i, ws[i], hs[i], 5+3*i); 
       long Siz = Out.Position; 
       var in1 = File.OpenRead(InJpgs[i]); 
       while (true) 
       { 
        var len = in1.Read(buffer, 0, buffer.Length); 
        if (len != 0) Out.Write(buffer, 0, len); else break; 
       } 
       in1.Close(); 
       Siz = Out.Position - Siz; // The difference is the stream-length 
       WriStr(Out, "\r\nendstream\r\n" + 
          "endobj\r\n"); 

       // Obj 5+3i the stream length (not known at the time of the begining of object 4 
       lens.Add(Out.Position); 
       WriStr(Out, "{0} 0 obj {1} endobj\r\n",lens.Count ,Siz); 

      } 
      //Pointer for XREF-table saved 
      long startxref = Out.Position; 

      //The XREF table, note the zero'th object, it is the free-object-list not used here 
      WriStr(Out, "xref\r\n" + 
         "0 {0}\r\n" + 
         "0000000000 65535 f\r\n", lens.Count+1); 
      //Position of each object saved entered in the XREF 
      foreach (var L in lens) 
       WriStr(Out, (10000000000 + L).ToString().Substring(1) + " 00000 n\r\n"); 
      //The trailer, pointing to object 1 as the Root 
      //and the saved startxref last, judt before the %%EOF marker 
      WriStr(Out, "trailer\r\n" + 
         "<<\r\n" + 
         " /Size {0}\r\n" + 
         " /Root 1 0 R\r\n" + 
         ">>\r\n" + 
         "startxref\r\n", lens.Count+1); 
      WriStr(Out, startxref.ToString() + "\r\n" + 
         "%%EOF"); 
      Out.Close(); 
     } 



     static void Main(string[] args) 
     { 
      if (0==args.Length) { 
       Console.WriteLine("Call with {JpgName [ScaleXY | ScaleW ScaleH] } [OutputName] , OutputName defaults to first .jpg -> .pdf"); 
       return; 
      } 
      List<string> basejpgs = new List<string>(); 
      double WrkDouble; 
      List<double> ScaFacWs = new List<double>(); 
      List<double> ScaFacHs = new List<double>(); 
      int i = 0; 
      while(i<args.Length && System.IO.File.Exists(args[i]) && System.IO.Path.GetExtension(args[i]).ToLower()==".jpg") { 
       basejpgs.Add(args[i]); 
       i++; 
       if (i<args.Length && Double.TryParse(args[i], out WrkDouble)) { 
        i++; 
       } else { 
        WrkDouble=1.0; //Default to 1x 
       } 
       ScaFacWs.Add(WrkDouble); 
       if (i < args.Length && Double.TryParse(args[i], out WrkDouble)) 
       { 
        i++; 
       } else { 
        WrkDouble=-1; //Default to same x-y scale 
       } 
       ScaFacHs.Add(WrkDouble); 
      } 
      //if (basejpgs.Count==0) basejpgs.Add("Red16x16.jPg"); //####DEBUG#### 
      string destpdf = basejpgs[0]; 
      if (i<args.Length && (System.IO.Path.GetExtension(args[i]).ToLower()==".pdf" || System.IO.Path.GetExtension(args[i])=="")) { 
       destpdf=args[i]; 
       i++; 
      } 
      if (i<args.Length) { 
       Console.WriteLine("Too many arguments, or could not decode???"); 
      } 
      destpdf = System.IO.Path.ChangeExtension(destpdf, ".PDF"); 
      JpgToPdf(basejpgs, destpdf, ScaFacWs, ScaFacHs); 
     } 
    } 
} 
+2

매우 유용한 코드! 계단에 주석을 달아 주면 좋을 것입니다. – Indio

+0

감사합니다. 유용한 코드. 방문자가이 기사를 참조하여보다 복잡한 PDF 생성 코드를 만드는 데 유용 할 수 있습니다. http://www.codeproject.com/Articles/18623/Add-Images-and-Textboxes-to- PDF –

+0

좋은 링크, 고마워! 나는 고대의 프로그램에 의해 만들어진 송장의 배경으로 이미지를 사용하기 때문에, JPG를 PDF로 변환하기 만하면된다. 그렇게해서는 결코 일반화되지 않았고, 내가 한 일을 해독하는 데 도움이되는 주석도 만들지 않았다. .. * LOL * –