code sources
This commit is contained in:
@@ -0,0 +1,205 @@
|
||||
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
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper lass to dump all images from a PDF into separate files
|
||||
/// </summary>
|
||||
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<Stream> 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;
|
||||
}
|
||||
/// <summary>
|
||||
/// Extract all images from a PDF file
|
||||
/// </summary>
|
||||
/// <param name="pdfPath">Full path and file name of PDF file</param>
|
||||
/// <param name="outputFilePrefix">Basic name of exported files. If null then uses same name as PDF file.</param>
|
||||
/// <param name="outputFolder">Where to save images. If null or empty then uses same folder as PDF file.</param>
|
||||
/// <param name="overwriteExistingFiles">True to overwrite existing image files, false to skip past them</param>
|
||||
/// <returns>Count of number of images extracted.</returns>
|
||||
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<Stream>();
|
||||
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
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user