5152a87ffa
Moved functionalities to library iMGcompress-core
208 lines
7.5 KiB
C#
208 lines
7.5 KiB
C#
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 iMGcompress_core;
|
|
|
|
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
|
|
|
|
}
|
|
}
|
|
|