code sources
This commit is contained in:
+435
@@ -0,0 +1,435 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Drawing;
|
||||
using Imazen.WebP;
|
||||
using SharpCompress.Archives;
|
||||
using SharpCompress.Archives.Rar;
|
||||
using SharpCompress.Archives.Zip;
|
||||
using System.IO;
|
||||
using SharpCompress.Common;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using javax.swing.plaf;
|
||||
using SharpCompress.Readers;
|
||||
using SharpCompress.Writers;
|
||||
using SharpCompress.Compressors.Xz;
|
||||
|
||||
namespace ComicCompressor
|
||||
{
|
||||
public class Compressor
|
||||
{
|
||||
private long last_mem = 0;
|
||||
private Logger Logger { get; set; }
|
||||
|
||||
public int Quality { get; set; } = 75;
|
||||
|
||||
public Compressor(Logger logger)
|
||||
{
|
||||
Logger = logger;
|
||||
}
|
||||
|
||||
public void Compress(string filename, string outputFile = null)
|
||||
{
|
||||
Stopwatch sw = Stopwatch.StartNew();
|
||||
outputFile = Path.ChangeExtension(outputFile ?? filename, "cbz");
|
||||
|
||||
Process proc = Process.GetCurrentProcess();
|
||||
Logger.LogDebug($"M {proc.PrivateMemorySize64}", LogLevel.Verbose, col: Color.Green);
|
||||
last_mem = proc.PrivateMemorySize64;
|
||||
|
||||
//Logger.Log("Processing: " + filename, LogLevel.Verbose);
|
||||
|
||||
IArchive archive = null;
|
||||
//SharpCompress.Readers.ReaderOptions opt = new ReaderOptions()
|
||||
//{
|
||||
|
||||
//}
|
||||
|
||||
ArchiveType ArchiveType = ArchiveType.Zip;
|
||||
using (Stream stream = File.OpenRead(filename))
|
||||
{
|
||||
using (var reader = ReaderFactory.Open(stream))
|
||||
ArchiveType = reader.ArchiveType;
|
||||
|
||||
}
|
||||
|
||||
bool isSolid = false;
|
||||
//if (filename.EndsWith(".cbr"))
|
||||
if (ArchiveType == ArchiveType.Rar)
|
||||
{
|
||||
archive = RarArchive.Open(filename);
|
||||
//foreach (var entry in archive.Entries)
|
||||
//{
|
||||
// isSolid = isSolid || entry.IsSolid;
|
||||
//}
|
||||
isSolid = archive.IsSolid;
|
||||
}
|
||||
//else if (filename.EndsWith(".cbz"))
|
||||
else if (ArchiveType == ArchiveType.Zip)
|
||||
{
|
||||
archive = ZipArchive.Open(filename);
|
||||
}
|
||||
|
||||
//Logger.Log($"Processing[{archive.Entries.Count()}]: " + filename, LogLevel.Verbose);
|
||||
Logger.Log($"Processing[{archive.Entries.Count()}]: ", LogLevel.Verbose,false);
|
||||
Logger.Log( filename, LogLevel.Verbose,col:Color.Green);
|
||||
|
||||
double save = 0;
|
||||
int num_pages =0;
|
||||
if (isSolid)
|
||||
{
|
||||
using (Stream stream = File.OpenRead(filename))
|
||||
{
|
||||
using (var reader = ReaderFactory.Open(stream))
|
||||
{
|
||||
(save, num_pages) = ProcessReader(archive,reader, outputFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
(save, num_pages) = ProcessArchive(archive, outputFile);
|
||||
if (num_pages == 0) num_pages = 1;
|
||||
long elapsed = sw.ElapsedMilliseconds;
|
||||
Logger.Log($"\r\nFinished({save.ToString("0.##")}%) [{elapsed}][{elapsed/num_pages}]: " + filename, LogLevel.Verbose, col: Color.Green);
|
||||
}
|
||||
|
||||
private (double, int) ProcessReader(IArchive archive, IReader reader, string outputPath)
|
||||
{
|
||||
var encoder = new SimpleEncoder();
|
||||
|
||||
|
||||
bool cover = true;
|
||||
double save = 0.0;
|
||||
int nop = 0;
|
||||
using (var output = ZipArchive.Create())
|
||||
{
|
||||
var imageStreams = new List<Stream>();
|
||||
|
||||
while (reader.MoveToNextEntry())
|
||||
{
|
||||
if (!reader.Entry.IsDirectory)
|
||||
{
|
||||
//Console.WriteLine(reader.Entry.Key);
|
||||
|
||||
if (reader.Entry.Key.StartsWith("__MACOSX"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
using (var entryStream = reader.OpenEntryStream())
|
||||
{
|
||||
|
||||
string entry_key_lower = reader.Entry.Key.ToLower();
|
||||
if (!entry_key_lower.EndsWith(".jpg") &&
|
||||
!entry_key_lower.EndsWith(".png") &&
|
||||
!entry_key_lower.EndsWith(".bmp") &&
|
||||
!entry_key_lower.EndsWith(".gif") &&
|
||||
!entry_key_lower.EndsWith(".jpeg"))
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
imageStreams.Add(ms);
|
||||
entryStream.CopyTo(ms);
|
||||
output.AddEntry(reader.Entry.Key, ms);
|
||||
Logger.Log("o", LogLevel.Verbose, false, col: Color.PaleGreen);
|
||||
continue;
|
||||
}
|
||||
|
||||
nop++;
|
||||
|
||||
if (cover)
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
imageStreams.Add(ms);
|
||||
entryStream.CopyTo(ms);
|
||||
output.AddEntry(reader.Entry.Key, ms);
|
||||
Logger.Log("C", LogLevel.Verbose, false, col: Color.Green);
|
||||
cover = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
ProcessReaderEntry(reader, entryStream, imageStreams, output, encoder);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reader.Dispose();
|
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
|
||||
|
||||
output.SaveTo(outputPath, CompressionType.Deflate);
|
||||
|
||||
//output.SaveTo(outputPath, CompressionType.None);
|
||||
|
||||
imageStreams.ForEach(i => i.Dispose());
|
||||
}
|
||||
|
||||
long output_length = new System.IO.FileInfo(outputPath).Length;
|
||||
|
||||
save = 100 * (double)output_length / (double)archive.TotalSize;
|
||||
|
||||
return (save,nop);
|
||||
}
|
||||
public int GetPlace(int value, int place)
|
||||
{
|
||||
return ((value % (place * 10)) - (value % place)) / place;
|
||||
}
|
||||
private (double, int) ProcessArchive(IArchive archive, string outputPath)
|
||||
{
|
||||
//var fileEntries = archive.Entries.Where(e => !e.IsDirectory);
|
||||
var fileEntries = archive.Entries.Where(e => !e.IsDirectory).OrderBy(e => e.Key);
|
||||
|
||||
var encoder = new SimpleEncoder();
|
||||
|
||||
bool cover = true;
|
||||
double save = 0.0;
|
||||
int nop = 0;
|
||||
using (var output = ZipArchive.Create())
|
||||
{
|
||||
var imageStreams = new List<Stream>();
|
||||
int count = 0;
|
||||
foreach (var entry in fileEntries)
|
||||
{
|
||||
(bool res, bool skipped) = ProcessEntry(entry, imageStreams, output, encoder, cover);
|
||||
if (res)
|
||||
cover = false;
|
||||
count++;
|
||||
if (!skipped)
|
||||
nop++;
|
||||
if (count % 10 == 0)
|
||||
{
|
||||
string digit = GetPlace(count, 10).ToString();
|
||||
Logger.Log(digit, LogLevel.Verbose, false, col: Color.Green);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
archive.Dispose();
|
||||
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
|
||||
|
||||
output.SaveTo(outputPath, CompressionType.Deflate);
|
||||
|
||||
//output.SaveTo(outputPath, CompressionType.None);
|
||||
|
||||
imageStreams.ForEach(i => i.Dispose());
|
||||
|
||||
output.Dispose();
|
||||
}
|
||||
|
||||
long output_length = new System.IO.FileInfo(outputPath).Length;
|
||||
|
||||
save = 100 * (double)output_length / (double)archive.TotalSize;
|
||||
|
||||
return (save, nop);
|
||||
}
|
||||
|
||||
|
||||
private (bool, bool) ProcessEntry(IArchiveEntry entry, IList<Stream> imageStreams, ZipArchive output, SimpleEncoder encoder, bool cover)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (entry.IsEncrypted)
|
||||
{
|
||||
Logger.Log("X", LogLevel.Verbose, false, col: Color.Yellow);
|
||||
return (false,true);
|
||||
}
|
||||
|
||||
|
||||
using (var stream = entry.OpenEntryStream())
|
||||
{
|
||||
|
||||
if (entry.Key.StartsWith("__MACOSX"))
|
||||
{
|
||||
return (false,true);
|
||||
}
|
||||
|
||||
string entry_key_lower = entry.Key.ToLower();
|
||||
if (!entry_key_lower.EndsWith(".jpg") &&
|
||||
!entry_key_lower.EndsWith(".png") &&
|
||||
!entry_key_lower.EndsWith(".bmp") &&
|
||||
!entry_key_lower.EndsWith(".gif") &&
|
||||
!entry_key_lower.EndsWith(".jpeg"))
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
imageStreams.Add(ms);
|
||||
stream.CopyTo(ms);
|
||||
output.AddEntry(entry.Key, ms);
|
||||
Logger.Log("o", LogLevel.Verbose, false, col: Color.Green);
|
||||
return (false, true);
|
||||
}
|
||||
|
||||
if (cover)
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
imageStreams.Add(ms);
|
||||
stream.CopyTo(ms);
|
||||
output.AddEntry(entry.Key, ms);
|
||||
Logger.Log("C", LogLevel.Verbose, false,col:Color.Green);
|
||||
return (true, false);
|
||||
}
|
||||
|
||||
Bitmap bits;
|
||||
|
||||
var raw_ms = new MemoryStream();
|
||||
stream.CopyTo(raw_ms);
|
||||
try
|
||||
{
|
||||
bits = new Bitmap(raw_ms);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError("Error parsing bitmap: " + entry.Key, col: Color.Red);
|
||||
Logger.LogDebug(e, LogLevel.Error, col:Color.Red);
|
||||
return (false, true);
|
||||
}
|
||||
|
||||
if (bits.PixelFormat != System.Drawing.Imaging.PixelFormat.Format24bppRgb)
|
||||
{
|
||||
var newBits = ChangePixelFormat(bits);
|
||||
bits.Dispose();
|
||||
bits = newBits;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
encoder.Encode(bits, ms, Quality);
|
||||
if (ms.Length < entry.Size)
|
||||
{
|
||||
imageStreams.Add(ms);
|
||||
output.AddEntry(entry.Key + ".webp", ms);
|
||||
Logger.Log(".", LogLevel.Verbose, false, col: Color.PaleGreen);
|
||||
|
||||
// release not used stream
|
||||
raw_ms.Dispose();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
imageStreams.Add(raw_ms);
|
||||
|
||||
raw_ms.Seek(0, SeekOrigin.Begin);
|
||||
//stream.Seek(0,SeekOrigin.Begin);
|
||||
output.AddEntry(entry.Key, raw_ms);
|
||||
Logger.Log("=", LogLevel.Verbose, false, col: Color.Green);
|
||||
|
||||
// release not used stream
|
||||
ms.Dispose();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError("Error encoding entry: " + entry.Key, col: Color.Red);
|
||||
Logger.LogDebug(e, LogLevel.Error, col: Color.Red);
|
||||
}
|
||||
finally
|
||||
{
|
||||
bits.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError("Error Archive Extraction: " + entry.Key, col: Color.Red);
|
||||
Logger.LogDebug(e, LogLevel.Error, col: Color.Red);
|
||||
return (false, true);
|
||||
}
|
||||
|
||||
Process proc = Process.GetCurrentProcess();
|
||||
//Logger.LogDebug($"M {proc.PrivateMemorySize64} - D {proc.PrivateMemorySize64 - last_mem}", LogLevel.Verbose);
|
||||
//last_mem = proc.PrivateMemorySize64;
|
||||
return (false,false);
|
||||
}
|
||||
|
||||
private void ProcessReaderEntry(IReader reader,EntryStream entry, IList<Stream> imageStreams, ZipArchive output, SimpleEncoder encoder)
|
||||
{
|
||||
try
|
||||
{
|
||||
var stream = entry;
|
||||
// using (var stream = entry.OpenEntryStream())
|
||||
{
|
||||
|
||||
|
||||
Bitmap bits;
|
||||
|
||||
var raw_ms = new MemoryStream();
|
||||
imageStreams.Add(raw_ms);
|
||||
stream.CopyTo(raw_ms);
|
||||
try
|
||||
{
|
||||
bits = new Bitmap(raw_ms);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError("Error parsing bitmap: " + reader.Entry.Key, col: Color.Red);
|
||||
Logger.LogDebug(e, LogLevel.Error, col: Color.Red);
|
||||
return ;
|
||||
}
|
||||
|
||||
if (bits.PixelFormat != System.Drawing.Imaging.PixelFormat.Format24bppRgb)
|
||||
{
|
||||
var newBits = ChangePixelFormat(bits);
|
||||
bits.Dispose();
|
||||
bits = newBits;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
encoder.Encode(bits, ms, Quality);
|
||||
if (ms.Length < reader.Entry.Size)
|
||||
{
|
||||
imageStreams.Add(ms);
|
||||
output.AddEntry(reader.Entry.Key + ".webp", ms);
|
||||
Logger.Log("s", LogLevel.Verbose, false, col: Color.Green);
|
||||
}
|
||||
else
|
||||
{
|
||||
raw_ms.Seek(0, SeekOrigin.Begin);
|
||||
//stream.Seek(0,SeekOrigin.Begin);
|
||||
output.AddEntry(reader.Entry.Key, raw_ms);
|
||||
Logger.Log("=", LogLevel.Verbose, false, col: Color.Green);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError("Error encoding entry: " + reader.Entry.Key, col: Color.Red);
|
||||
Logger.LogDebug(e, LogLevel.Error, col: Color.Red);
|
||||
}
|
||||
finally
|
||||
{
|
||||
bits.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError("Error Archive Extraction: " + reader.Entry.Key, col: Color.Red);
|
||||
Logger.LogDebug(e, LogLevel.Error, col: Color.Red);
|
||||
return;
|
||||
}
|
||||
|
||||
return ;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
public void CompressPdf(string filename, string outputFile = null)
|
||||
{
|
||||
new ImageExtractor(Logger).ExtractImagesFromFile(filename, outputFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user