2011-12-05 12 views
7

Tôi đang tạo một thường trình để viết một tài liệu PDF đơn giản dựa trên thông tin trong this document từ Adobe. Tạo luồng cho văn bản và hình dạng đã được chứng minh đơn giản nhưng tôi bị kẹt khi chèn hình ảnh.Tệp hình ảnh để chuyển đổi luồng PDF

Có ai có thể cung cấp giải thích đơn giản về cách chuyển đổi tệp (bất kỳ định dạng hình ảnh nào như gif, bmp, jpg, v.v.) sẽ ổn) thành luồng PDF không? Lưu ý rằng tôi không muốn tạo toàn bộ tệp PDF, chỉ là luồng trong tệp.

Với các ứng dụng tôi đã có, bạn không thể xem nó được thực hiện ở đâu khác vì toàn bộ luồng được mã hóa từ đầu đến cuối và đó là phương pháp mã hóa mà tôi đang cố gắng giải quyết.

Trong khi tôi không muốn phát minh lại toàn bộ việc tạo bánh xe tệp PDF, tôi muốn hiểu phần này hoạt động như thế nào vì vậy không muốn sử dụng thư viện (vì vậy lý do không đề cập đến ngôn ngữ Tôi đang dùng).

Trả lời

10

Bạn cần sử dụng toán tử Do trong luồng nội dung. Ví dụ.

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

Im1 đề cập đến một nguồn tài nguyên XObject trong từ điển tài nguyên của trang

Ví dụ,

In the page dictionary ... 
<< 

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

Object 2 0 R sẽ là một XObject ảnh:

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 

Một một số lưu ý: - để định vị và chia tỷ lệ hình ảnh bạn phải đặt ma trận đồ họa hiện tại bằng toán tử cm. Ví dụ

150 0 0 150 100 100 cm 

sẽ định vị hình ảnh tại (100,100) và làm cho hình ảnh 150 rộng và 150 cao.

  • Bạn đang không giới hạn hình ảnh JPEG - bạn có thể sử dụng JPEG2000s (sử dụng/Lọc =/JPXDecode) hoặc dữ liệu bitmap pixel (bỏ qua các bộ lọc)

  • Phần của spec có tất cả điều này trong là 8,9

  • tôi đã không thử nghiệm với LZW decode - tôi đoán rằng có thể làm việc cho GIF

  • bạn thường đẩy trạng thái đồ họa vào stack khi hiển thị một hình ảnh. ví dụ.

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

Các q và Q nhà khai thác đẩy và bật trạng thái đồ họa (quan trọng, các nhà điều hành cm!)

+0

Cảm ơn bạn rất nhiều, bạn là một ngôi sao! Câu trả lời của bạn chính xác là những gì tôi cần. – blankabout

+0

không có probs, vui mừng tôi có thể giúp – Jimmy

+1

Khá một câu hỏi muộn; nhưng làm cách nào để bạn tự lấy dữ liệu luồng từ một hình ảnh? Khi bạn nói dữ liệu bitmap pixel, ý của bạn là gì? – user1810737

5

Một đơn giản C# chương trình để tạo ra một pdf từ jpg dựa trên trên có thể tìm thấy ở đây.

Lưu ý chi tiết rằng từ "luồng" và luồng jpg thực tế PHẢI được phân tách bằng \ n (hoặc \ r \ n) !!!

Trân trọng 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(); 
     } 
    } 
} 

ADD 2016/04/07:

Đây là một phiên bản mới hơn với ý kiến, hỗ trợ để mở rộng và trang đa JPG và một đầy đủ chương trình wrapper chính (các chức năng bổ sung rất dễ dàng để thêm vào, nó sẽ là một điều đáng tiếc để bỏ qua ...)

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

Mã rất hữu ích! Nó sẽ là tốt đẹp nếu bạn cound bình luận các bước. – Indio

+0

Cảm ơn. Mã hữu ích. Có thể hữu ích khi khách truy cập giới thiệu họ đến bài viết này có thể được sử dụng để tạo mã tạo PDF phức tạp hơn: http://www.codeproject.com/Articles/18623/Add-Images-and-Textboxes-to- PDF –

+0

Liên kết tốt đẹp, cảm ơn! Tôi chỉ thực hiện ở trên để sử dụng hình ảnh làm nền cho một hóa đơn được thực hiện bởi một chương trình cổ, vì vậy chỉ cần chuyển đổi JPG sang PDF, vì vậy không bao giờ thực sự khái quát hóa - cũng như không đưa ra nhận xét giúp giải mã những gì tôi đang làm. .. * LOL * –