दिलचस्प पोस्ट
रूबी में सरणी टुकड़ा करना: अयोग्य व्यवहार के लिए स्पष्टीकरण (Rubykoans.com से लिया गया) PHP, MySQL त्रुटि: स्तंभ गिनती पंक्ति 1 पर मान गणना से मेल नहीं खाती अपने एपीआई का उपयोग करके एक मूल मेलचिप साइनअप फ़ॉर्म बनाएं कोको में XML को पार्स करना कैसे आप csproj के साथ एक .NET कोर कक्षा पुस्तकालय बहु-लक्ष्य कर सकते हैं? एंड्रॉइड चेकबॉक्स के साथ सूची दृश्य में आइटम की पहचान कैसे करें एंड्रॉइड काम नहीं करने के लिए दृश्य स्टूडियो (2015) एमुलेटर – XDE.exe – बाहर निकलें कोड 3 जावा क्रम में स्थिर / इंस्टेंस प्रारंभिक ब्लॉक किस क्रम में? जावा के "% n" के साथ printf में क्या हो रहा है? मैं जावा 5 में एक निष्पादक सेवा का उपयोग कर कार्य प्राथमिकता कैसे लागू करूं? माइक्रोसॉफ्ट बीओटी फ्रेमवर्क में संदेशों के प्रवाह को बदलना सी # में क्लिपबोर्ड पर डेटा कैसे कॉपी करें सी # SHA-1 बनाम PHP SHA-1 … अलग परिणाम? किसी पृष्ठ पर खर्च किए गए समय को मापने के लिए कैसे? आर में स्तंभ में प्रत्येक परिवर्तन के लिए 1 से वृद्धि

ITextSharp के साथ पीडीएफ संपीड़न

मैं वर्तमान में एक पीडीएफ पुनः संयोजित करने की कोशिश कर रहा हूं जो कि पहले से ही बनाया गया है, मैं फ़ाइल आकार को कम करने के लिए, दस्तावेज़ में मौजूद छवियों को पुनः संयोजित करने का एक तरीका ढूंढने की कोशिश कर रहा हूं।

मैं इसे डेटालागिक्स पीडीई और iTextSharp पुस्तकालयों के साथ करने की कोशिश कर रहा हूं, लेकिन मुझे आइटम्स की स्ट्रीम रीकंप्रेसन करने का कोई तरीका नहीं मिल सकता है

हालांकि मैं xobjects पर पाशन और चित्र प्राप्त कर रहा हूं और फिर डीपीआई को 96 तक नीचे ले जा रहा हूं या छवि की गुणवत्ता बदलने के लिए libzpeg C # इंफिमेंटेशन का उपयोग कर रहा हूं, लेकिन इसे पीडीएफ स्ट्रीम में वापस करना हमेशा समाप्त होता है, स्मृति भ्रष्टाचार के साथ या कुछ अन्य समस्या

किसी भी नमूने की सराहना की जाएगी।

धन्यवाद

वेब के समाधान से एकत्रित समाधान "ITextSharp के साथ पीडीएफ संपीड़न"

iText और iTextSharp में अप्रत्यक्ष वस्तुओं की जगह के लिए कुछ तरीके हैं I विशेष रूप से PdfReader.KillIndirect() जो यह कहता है और PdfWriter.AddDirectImageSimple(iTextSharp.text.Image, PRIndirectReference) जो आप फिर से बंद कर रहे हैं को बदलने के लिए उपयोग कर सकते हैं।

छद्म सी # कोड में आप क्या करेंगे:

 var oldImage = PdfReader.GetPdfObject(); var newImage = YourImageCompressionFunction(oldImage); PdfReader.KillIndirect(oldImage); yourPdfWriter.AddDirectImageSimple(newImage, (PRIndirectReference)oldImage); 

कच्चे बाइट्स को एक नेट छवि में परिवर्तित करना मुश्किल हो सकता है, मैं इसे आपके ऊपर छोड़ दूँगा या आप यहां खोज सकते हैं। मार्क का एक अच्छा विवरण यहाँ है इसके अलावा, तकनीकी रूप से पीडीएफ में डीपीआई की कोई अवधारणा नहीं है, जो कि ज्यादातर प्रिंटर के लिए है इसके बारे में अधिक जानने के लिए यहां उत्तर देखें

अपने संपीड़न एल्गोरिथ्म के ऊपर विधि का प्रयोग वास्तव में दो चीजों को कर सकता है, शारीरिक रूप से छवि को छोटा और साथ ही साथ जेपीईजी संपीड़न लागू करें जब आप शारीरिक रूप से छवि को सिकुड़ते हैं और इसे वापस जोड़ते हैं तो यह मूल छवि के रूप में एक ही स्थान की जगह पर कब्जा कर लेगा, लेकिन कम पिक्सेल के साथ काम करने के लिए। यह आपको मिलेगा जो आपको डीपीआई कम करने का विचार है। जेपीईजी संपीड़न खुद के लिए बोलती है

नीचे एक पूर्ण काम कर रहे सी # 2010 विनफॉर्म ऐप को iTextSharp 5.1.1.0 लक्षित कर रहा है। इसे "LargeImage.jpg" नामक आपके डेस्कटॉप पर एक मौजूदा जेपीईजी लेता है और इससे एक नया पीडीएफ बनाता है फिर पीडीएफ को खोलता है, छवि को निकालता है, भौतिक रूप से इसे मूल आकार के 90% तक घटाता है, 85% जेपीईजी संपीड़न लागू करता है और इसे पीडीएफ में वापस लिखता है। अधिक स्पष्टीकरण के लिए कोड में टिप्पणियां देखें कोड की बहुत अधिक रिक्त / त्रुटि जांच की आवश्यकता है इसके अलावा NOTE टिप्पणियों के लिए जहां आपको अन्य परिस्थितियों को संभालने के लिए विस्तार की आवश्यकता होगी।

 using System; using System.Drawing; using System.Drawing.Imaging; using System.Drawing.Drawing2D; using System.Windows.Forms; using System.IO; using iTextSharp.text; using iTextSharp.text.pdf; namespace WindowsFormsApplication1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { //Our working folder string workingFolder = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); //Large image to add to sample PDF string largeImage = Path.Combine(workingFolder, "LargeImage.jpg"); //Name of large PDF to create string largePDF = Path.Combine(workingFolder, "Large.pdf"); //Name of compressed PDF to create string smallPDF = Path.Combine(workingFolder, "Small.pdf"); //Create a sample PDF containing our large image, for demo purposes only, nothing special here using (FileStream fs = new FileStream(largePDF, FileMode.Create, FileAccess.Write, FileShare.None)) { using (Document doc = new Document()) { using (PdfWriter writer = PdfWriter.GetInstance(doc, fs)) { doc.Open(); iTextSharp.text.Image importImage = iTextSharp.text.Image.GetInstance(largeImage); doc.SetPageSize(new iTextSharp.text.Rectangle(0, 0, importImage.Width, importImage.Height)); doc.SetMargins(0, 0, 0, 0); doc.NewPage(); doc.Add(importImage); doc.Close(); } } } //Now we're going to open the above PDF and compress things //Bind a reader to our large PDF PdfReader reader = new PdfReader(largePDF); //Create our output PDF using (FileStream fs = new FileStream(smallPDF, FileMode.Create, FileAccess.Write, FileShare.None)) { //Bind a stamper to the file and our reader using (PdfStamper stamper = new PdfStamper(reader, fs)) { //NOTE: This code only deals with page 1, you'd want to loop more for your code //Get page 1 PdfDictionary page = reader.GetPageN(1); //Get the xobject structure PdfDictionary resources = (PdfDictionary)PdfReader.GetPdfObject(page.Get(PdfName.RESOURCES)); PdfDictionary xobject = (PdfDictionary)PdfReader.GetPdfObject(resources.Get(PdfName.XOBJECT)); if (xobject != null) { PdfObject obj; //Loop through each key foreach (PdfName name in xobject.Keys) { obj = xobject.Get(name); if (obj.IsIndirect()) { //Get the current key as a PDF object PdfDictionary imgObject = (PdfDictionary)PdfReader.GetPdfObject(obj); //See if its an image if (imgObject.Get(PdfName.SUBTYPE).Equals(PdfName.IMAGE)) { //NOTE: There's a bunch of different types of filters, I'm only handing the simplest one here which is basically raw JPG, you'll have to research others if (imgObject.Get(PdfName.FILTER).Equals(PdfName.DCTDECODE)) { //Get the raw bytes of the current image byte[] oldBytes = PdfReader.GetStreamBytesRaw((PRStream)imgObject); //Will hold bytes of the compressed image later byte[] newBytes; //Wrap a stream around our original image using (MemoryStream sourceMS = new MemoryStream(oldBytes)) { //Convert the bytes into a .Net image using (System.Drawing.Image oldImage = Bitmap.FromStream(sourceMS)) { //Shrink the image to 90% of the original using (System.Drawing.Image newImage = ShrinkImage(oldImage, 0.9f)) { //Convert the image to bytes using JPG at 85% newBytes = ConvertImageToBytes(newImage, 85); } } } //Create a new iTextSharp image from our bytes iTextSharp.text.Image compressedImage = iTextSharp.text.Image.GetInstance(newBytes); //Kill off the old image PdfReader.KillIndirect(obj); //Add our image in its place stamper.Writer.AddDirectImageSimple(compressedImage, (PRIndirectReference)obj); } } } } } } } this.Close(); } //Standard image save code from MSDN, returns a byte array private static byte[] ConvertImageToBytes(System.Drawing.Image image, long compressionLevel) { if (compressionLevel < 0) { compressionLevel = 0; } else if (compressionLevel > 100) { compressionLevel = 100; } ImageCodecInfo jgpEncoder = GetEncoder(ImageFormat.Jpeg); System.Drawing.Imaging.Encoder myEncoder = System.Drawing.Imaging.Encoder.Quality; EncoderParameters myEncoderParameters = new EncoderParameters(1); EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder, compressionLevel); myEncoderParameters.Param[0] = myEncoderParameter; using (MemoryStream ms = new MemoryStream()) { image.Save(ms, jgpEncoder, myEncoderParameters); return ms.ToArray(); } } //standard code from MSDN private static ImageCodecInfo GetEncoder(ImageFormat format) { ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders(); foreach (ImageCodecInfo codec in codecs) { if (codec.FormatID == format.Guid) { return codec; } } return null; } //Standard high quality thumbnail generation from http://weblogs.asp.net/gunnarpeipman/archive/2009/04/02/resizing-images-without-loss-of-quality.aspx private static System.Drawing.Image ShrinkImage(System.Drawing.Image sourceImage, float scaleFactor) { int newWidth = Convert.ToInt32(sourceImage.Width * scaleFactor); int newHeight = Convert.ToInt32(sourceImage.Height * scaleFactor); var thumbnailBitmap = new Bitmap(newWidth, newHeight); using (Graphics g = Graphics.FromImage(thumbnailBitmap)) { g.CompositingQuality = CompositingQuality.HighQuality; g.SmoothingMode = SmoothingMode.HighQuality; g.InterpolationMode = InterpolationMode.HighQualityBicubic; System.Drawing.Rectangle imageRectangle = new System.Drawing.Rectangle(0, 0, newWidth, newHeight); g.DrawImage(sourceImage, imageRectangle); } return thumbnailBitmap; } } } 

मैं iTextSharp के बारे में नहीं जानता, लेकिन यदि कुछ बदल गया है, तो आपको एक पीडीएफ फाइल को फिर से लिखना होगा, क्योंकि इसमें प्रत्येक ऑब्जेक्ट की सटीक फाइल स्थिति के साथ एक xref टेबल (इंडेक्स) है। इसका मतलब है कि अगर एक बाइट भी जोड़ा या हटा दिया जाता है, तो पीडीएफ भ्रष्ट हो जाता है

छवियों को दोबारा संरेखित करने के लिए आपकी सर्वश्रेष्ठ शर्त JBIG2 है अगर वे बी एंड डब्ल्यू या जेपीईजी 2000 अन्यथा हैं, जिसके लिए जेस्पर लाइब्रेरी पीडीएफ फाइल में प्लेसमेंट के लिए जेपीजी 2000 सीडीएस्ट्रीम की एन्कोड करेगा ताकि आपको जो भी गुणवत्ता चाहिए,

अगर यह मेरे थे तो मैं पीडीएफ पुस्तकालयों के बिना कोड से यह सब करना चाहता हूं। बस JPXDecode (जेपीईजी 2000), JBIG2Decode 2 JBIG2Decode ( JBIG2Decode 2) या DCTDecode (जेपीईजी) के endstream बाद सभी छवियों ( stream और endstream बीच कुछ भी) को खींचें, इसे जैस्पर के साथ DCTDecode कर DCTDecode , फिर इसे फिर से DCTDecode और DCTDecode टेबल अपडेट करें

Xref तालिका अपडेट करने के लिए, प्रत्येक ऑब्जेक्ट की पदों को ढूंढें ( 00001 0 obj शुरू करें) और बस एक्सरेफ टेबल में नई स्थिति अपडेट करें। यह बहुत ज्यादा काम नहीं है, यह ध्वनि की तुलना में कम है आप सभी ऑफ़सेट को एक नियमित अभिव्यक्ति (मैं सी # प्रोग्रामर नहीं हूं, लेकिन PHP में) प्राप्त कर सकता है, यह यह आसान होगा।)

फिर अंत में startxref टेबल की शुरुआत के ऑफसेट के साथ trailer में startxref टैग के मूल्य को अपडेट करें (जहां यह फ़ाइल में xref कहता है)

अन्यथा आप संपूर्ण पीडीएफ को डीकोड करना और इसे पुन: लिखना होगा, जो धीमे हो जाएगा, और आप रास्ते में कुछ खो सकते हैं।

IText के निर्माता द्वारा किसी मौजूदा पीडीएफ में छवियों को कैसे ढूंढ और प्रतिस्थापित करने का एक उदाहरण है यह वास्तव में अपनी पुस्तक से एक छोटा सा अंश है चूंकि यह जावा में है, यहाँ एक सरल प्रतिस्थापन है:

 public void ReduceResolution(PdfReader reader, long quality) { int n = reader.XrefSize; for (int i = 0; i < n; i++) { PdfObject obj = reader.GetPdfObject(i); if (obj == null || !obj.IsStream()) {continue;} PdfDictionary dict = (PdfDictionary)PdfReader.GetPdfObject(obj); PdfName subType = (PdfName)PdfReader.GetPdfObject( dict.Get(PdfName.SUBTYPE) ); if (!PdfName.IMAGE.Equals(subType)) {continue;} PRStream stream = (PRStream )obj; try { PdfImageObject image = new PdfImageObject(stream); PdfName filter = (PdfName) image.Get(PdfName.FILTER); if ( PdfName.JBIG2DECODE.Equals(filter) || PdfName.JPXDECODE.Equals(filter) || PdfName.CCITTFAXDECODE.Equals(filter) || PdfName.FLATEDECODE.Equals(filter) ) continue; System.Drawing.Image img = image.GetDrawingImage(); if (img == null) continue; var ll = image.GetImageBytesType(); int width = img.Width; int height = img.Height; using (System.Drawing.Bitmap dotnetImg = new System.Drawing.Bitmap(img)) { // set codec to jpeg type => jpeg index codec is "1" System.Drawing.Imaging.ImageCodecInfo codec = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders()[1]; // set parameters for image quality System.Drawing.Imaging.EncoderParameters eParams = new System.Drawing.Imaging.EncoderParameters(1); eParams.Param[0] = new System.Drawing.Imaging.EncoderParameter( System.Drawing.Imaging.Encoder.Quality, quality ); using (MemoryStream msImg = new MemoryStream()) { dotnetImg.Save(msImg, codec, eParams); msImg.Position = 0; stream.SetData(msImg.ToArray()); stream.SetData( msImg.ToArray(), false, PRStream.BEST_COMPRESSION ); stream.Put(PdfName.TYPE, PdfName.XOBJECT); stream.Put(PdfName.SUBTYPE, PdfName.IMAGE); stream.Put(PdfName.FILTER, filter); stream.Put(PdfName.FILTER, PdfName.DCTDECODE); stream.Put(PdfName.WIDTH, new PdfNumber(width)); stream.Put(PdfName.HEIGHT, new PdfNumber(height)); stream.Put(PdfName.BITSPERCOMPONENT, new PdfNumber(8)); stream.Put(PdfName.COLORSPACE, PdfName.DEVICERGB); } } } catch { // throw; // iText[Sharp] can't handle all image types... } finally { // may or may not help reader.RemoveUnusedObjects(); } } } 

आप देखेंगे कि यह केवल जेपीईजी से निपटने वाला है। तर्क उलट (केवल DCTDECODE / जेपीईजी को स्पष्ट रूप से संभालने के बजाय) उलट किया जाता है, ताकि आप उपेक्षित कोड में से कुछ को अनदेखा कर सकते हैं और उपरोक्त कोड में PdfImageObject साथ प्रयोग कर सकते हैं। विशेष रूप से, अधिकांश FLATEDECODE छवियों (.bmp, .png, और .gif) को पीएनजी ( DecodeImageBytes PdfImageObject स्रोत कोड के PdfImageObject DecodeImageBytes विधि में पुष्टि) के रूप में प्रस्तुत किया गया है। जहाँ तक मुझे पता है, .नेट पीएनजी एन्कोडिंग का समर्थन नहीं करता है। यहां और यहां यह समर्थन करने के लिए कुछ संदर्भ हैं । आप एक अकेले पीएनजी अनुकूलन निष्पादन योग्य की कोशिश कर सकते हैं, लेकिन आपको PdfName.BITSPERCOMPONENT और PdfName.COLORSPACE को सेट PRStream

पूर्णता के लिए, क्योंकि आपका प्रश्न विशेष रूप से पीडीएफ संपीड़न के बारे में पूछता है, यहां बताया गया है कि कैसे आप iTextSharp के साथ पीडीएफ को संक्षिप्त करते हैं:

 PdfStamper stamper = new PdfStamper( reader, YOUR-STREAM, PdfWriter.VERSION_1_5 ); stamper.Writer.CompressionLevel = 9; int total = reader.NumberOfPages + 1; for (int i = 1; i < total; i++) { reader.SetPageContent(i, reader.GetPageContent(i)); } stamper.SetFullCompression(); stamper.Close(); 

आप फ़ाइल का आकार नीचे लाने के लिए पीडीएफएसएमआरटीसीपी के माध्यम से भी पीडीएफ को चलाने का प्रयास कर सकते हैं। यह अनावश्यक संसाधनों को निकालता है, लेकिन finally ब्लॉक में RemoveUnusedObjects() जाने वाले RemoveUnusedObjects() के कॉल की तरह, यह संभवतः मदद नहीं कर सकता या हो सकता है यह पीडीएफ कैसे बनाया गया था पर निर्भर करेगा।

JBIG2DECODE [शार्प] JBIG2DECODE साथ अच्छा व्यवहार नहीं करता है, इसलिए @ JBIG2DECODE का सुझाव अच्छा दिखता है – यदि आप जैस्पर लाइब्रेरी सीखने का समय लेना चाहते हैं और ब्रूट-फोर्स दृष्टिकोण का उपयोग करना चाहते हैं

सौभाग्य।

संपादित करें – 2012-08-17 , @ क्रेग द्वारा टिप्पणी:

ऊपर ReduceResolution() विधि का उपयोग करते हुए jpegs को संपीड़ित करने के बाद पीडीएफ को बचाने के लिए:

ए। एक PdfReader ऑब्जेक्ट PdfReader :

 PdfReader reader = new PdfReader(pdf); 

ख। ऊपर ReduceResolution() विधि में ReduceResolution() PdfReader पास करें

सी। परिवर्तित PdfReader को PdfReader से पास करें MemoryStream का उपयोग करने वाला यह एक तरीका है:

 // Save altered PDF. then you can pass the btye array to a database, etc using (MemoryStream ms = new MemoryStream()) { using (PdfStamper stamper = new PdfStamper(reader, ms)) { } return ms.ToArray(); } 

या आप किसी भी अन्य Stream उपयोग कर सकते हैं अगर आपको स्मृति में पीडीएफ रखने की आवश्यकता नहीं है उदाहरण के लिए एक FileStream उपयोग करें और सीधे डिस्क पर सहेजें।

मैंने ऐसा करने के लिए एक पुस्तकालय लिखा है यह पीडीएफ को टेसेरैक्ट या क्यूनिफेयर के जरिए ओसीआर करेगा और खोज, संकुचित पीडीएफ फाइलों को भी बना देगा। यह एक लाइब्रेरी है जो कार्य को पूरा करने के लिए कई ओपन सोर्स प्रोजेक्ट्स (आईटेक्सटशप, जेबीआईजी 2 एन्कोडर, आफॉफ़, एमयूपीडीएफ #) का उपयोग करता है। आप इसे यहां देख सकते हैं http://hocrtopdf.codeplex.com/

मुझे यकीन नहीं है कि आप अन्य पुस्तकालयों पर विचार कर रहे हैं, लेकिन आप डॉकोटिक.पीडीएफ लाइब्रेरी (अस्वीकरण: मैं कंपनी के लिए काम कर रहा हूँ) का उपयोग करके मौजूदा छवियों को आसानी से पुन : सम्मिलित कर सकता हूं।

यहां कुछ नमूना कोड है:

 static void RecompressExistingImages(string fileName, string outputName) { using (PdfDocument doc = new PdfDocument(fileName)) { foreach (PdfImage image in doc.Images) image.RecompressWithGroup4Fax(); doc.Save(outputName); } } 

RecompressWithFlate भी हैं, RecompressWithGroup3Fax , RecompressWithJpeg और Uncompress तरीकों।

यदि आवश्यक हो तो लाइब्रेरी रंगीन छवियों को बिलीज़ वाले में बदल देगी आप डीफ़्लेट संपीड़न स्तर, जेपीईजी गुणवत्ता आदि निर्दिष्ट कर सकते हैं।

@ अलास्देयर द्वारा सुझाए गए दृष्टिकोण का उपयोग करने से पहले मैं आपको दो बार सोचने के लिए भी कहूंगा यदि आप पीडीएफ फाइलों से निपटने जा रहे हैं जो आपके द्वारा नहीं बनाए गए थे काम की तुलना में कहीं अधिक जटिल है जो शायद यह लग सकता है

शुरू करने के लिए, JPXDecode , JBIG2Decode या DCTDecode अलावा अन्य कोडेक द्वारा संकुचित छवियों का एक बड़ा सौदा है। और पीडीएफ में इनलाइन छवियां भी हो सकती हैं

पीडीएफ फाइलें मानक (1.5 या नए) के नए संस्करणों के माध्यम से सहेजी गई हैं, जिसमें क्रॉस-रेफरेंस स्ट्रीम शामिल हो सकते हैं। इसका अर्थ है कि ऐसी फाइलों को पढ़ना और अपडेट करने से फ़ाइल के अंत में कुछ संख्याओं को खोजने / अपडेट करने से अधिक जटिल होता है।

तो, कृपया, एक पीडीएफ पुस्तकालय का उपयोग करें।

पीडीएफ को संपीड़ित करने का एक सरल तरीका gsdll32.dll (घोस्टस्क्रिप्ट) और साइटोके.होस्टस्क्रिप्ट डीएलएल (आवरण) का उपयोग कर रहा है:

 public static void CompressPDF(string sInFile, string sOutFile, int iResolution) { string[] arg = new string[] { "-sDEVICE=pdfwrite", "-dNOPAUSE", "-dSAFER", "-dBATCH", "-dCompatibilityLevel=1.5", "-dDownsampleColorImages=true", "-dDownsampleGrayImages=true", "-dDownsampleMonoImages=true", "-sPAPERSIZE=a4", "-dPDFFitPage", "-dDOINTERPOLATE", "-dColorImageDownsampleThreshold=1.0", "-dGrayImageDownsampleThreshold=1.0", "-dMonoImageDownsampleThreshold=1.0", "-dColorImageResolution=" + iResolution.ToString(), "-dGrayImageResolution=" + iResolution.ToString(), "-dMonoImageResolution=" + iResolution.ToString(), "-sOutputFile=" + sOutFile, sInFile }; using(GhostScriptAPI api = new GhostScriptAPI()) { api.Execute(arg); } }