using System; using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.IO; using System.Runtime.ConstrainedExecution; using ikvm.extensions; using Imazen.WebP; using iTextSharp.text.pdf; using iTextSharp.text.pdf.parser; using SharpCompress.Archives; using SharpCompress.Archives.Zip; using SharpCompress.Common; using Path = System.IO.Path; namespace ComicCompressor { /// /// Helper lass to dump all images from a PDF into separate files /// public class ImageExtractor : IRenderListener { int _currentPage = 1; int _imageCount = 0; readonly string _outputFilePrefix = ""; //readonly string _outputFolder; //readonly bool _overwriteExistingFiles; private bool Cover = true; private Logger Logger { get; set; } SimpleEncoder encoder = new SimpleEncoder(); public int Quality { get; set; } = 75; private List imageStreams = null; public ZipArchive output = null; public ImageExtractor(Logger logger) { Logger = logger; //_outputFilePrefix = outputFilePrefix; //_outputFolder = outputFolder; //_overwriteExistingFiles = overwriteExistingFiles; } public int GetPlace(int value, int place) { return ((value % (place * 10)) - (value % place)) / place; } /// /// Extract all images from a PDF file /// /// Full path and file name of PDF file /// Basic name of exported files. If null then uses same name as PDF file. /// Where to save images. If null or empty then uses same folder as PDF file. /// True to overwrite existing image files, false to skip past them /// Count of number of images extracted. public int ExtractImagesFromFile(string pdfPath, string outputFolder, int quality = 75) { // Handle setting of any default values //outputFilePrefix = outputFilePrefix ?? Path.GetFileNameWithoutExtension(pdfPath); //outputFolder = String.IsNullOrEmpty(outputFolder) ? Path.GetDirectoryName(pdfPath) : outputFolder; quality = quality; Stopwatch sw = Stopwatch.StartNew(); using (var pdfReader = new PdfReader(pdfPath)) { Logger.Log($"Processing[{pdfReader.NumberOfPages}]: " + pdfPath, LogLevel.Verbose); if (pdfReader.IsEncrypted()) throw new ApplicationException(pdfPath + " is encrypted."); var pdfParser = new PdfReaderContentParser(pdfReader); output = ZipArchive.Create(); { imageStreams = new List(); int count = 0; Cover = true; while (_currentPage <= pdfReader.NumberOfPages) { pdfParser.ProcessContent(_currentPage, this); _currentPage++; count++; if (count % 10 == 0) { string digit = GetPlace(count, 10).ToString(); Logger.Log(digit, LogLevel.Verbose, false); } } Directory.CreateDirectory(Path.GetDirectoryName(outputFolder)); output.SaveTo(outputFolder, CompressionType.Deflate); //output.SaveTo(outputPath, CompressionType.None); imageStreams.ForEach(i => i.Dispose()); } output.Dispose(); int nop = pdfReader.NumberOfPages; if (nop == 0) nop = 1; long elapsed = sw.ElapsedMilliseconds; //Logger.Log($"\r\nFinished({save.ToString("0.##")}): " + pdfPath, LogLevel.Verbose); Logger.Log($"\r\nFinished({0.ToString("0.##")} [{elapsed}][{elapsed / nop}]): " + pdfPath, LogLevel.Verbose); } return _imageCount; } private Bitmap ChangePixelFormat(Bitmap orig, System.Drawing.Imaging.PixelFormat format = System.Drawing.Imaging.PixelFormat.Format24bppRgb) { Bitmap clone = new Bitmap(orig.Width, orig.Height, format); using (Graphics gr = Graphics.FromImage(clone)) { gr.DrawImage(orig, new Rectangle(0, 0, clone.Width, clone.Height)); } return clone; } #region Implementation of IRenderListener public void BeginTextBlock() { } public void EndTextBlock() { } public void RenderText(TextRenderInfo renderInfo) { var text = renderInfo.GetText(); } public void RenderImage(ImageRenderInfo renderInfo) { try { var type = renderInfo.GetType(); var str = renderInfo.toString(); //var ftype = renderInfo.GetFileType(); var imageObject = renderInfo.GetImage(); //var imageFileName = String.Format("{0}_{1}_{2}.{3}", _outputFilePrefix, _currentPage, _imageCount, // imageObject.GetFileType()); var imageFileName = String.Format($"{_imageCount.ToString("0000")}"); //var imagePath = Path.Combine(_outputFolder, imageFileName); //if (_overwriteExistingFiles || !File.Exists(imagePath)) { var imageRawBytes = imageObject.GetImageAsBytes(); var image = imageObject.GetDrawingImage(); //File.WriteAllBytes(imagePath, imageRawBytes); if (image.Width < 512 || image.Height < 512) return; if (image.PixelFormat != System.Drawing.Imaging.PixelFormat.Format24bppRgb) { var newBits = ChangePixelFormat((Bitmap)image); image.Dispose(); image = newBits; } var ms = new MemoryStream(); encoder.Encode((Bitmap)image, ms, Quality); if (!Cover && ms.Length < imageRawBytes.Length) { imageStreams.Add(ms); output.AddEntry(imageFileName + ".webp", ms); Logger.Log(".", LogLevel.Verbose, false); } else { var mso = new MemoryStream(); mso.Write(imageRawBytes); output.AddEntry(imageFileName + imageObject.GetFileType(), mso); Logger.Log(Cover ? "C" : "=", LogLevel.Verbose, false); Cover = false; } } // Subtle: Always increment even if file is not written. This ensures consistency should only some // of a PDF file's images actually exist. _imageCount++; } catch (Exception e) { Console.WriteLine(e); throw; } } #endregion // Implementation of IRenderListener } }