2024-03-01 16:05:06 +01:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.IO;
|
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using McMaster.Extensions.CommandLineUtils;
|
|
|
|
|
|
using System.ComponentModel.DataAnnotations;
|
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
|
using System.Threading;
|
|
|
|
|
|
using System.Drawing.Imaging;
|
|
|
|
|
|
using System.Drawing;
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
|
|
|
2025-12-12 15:53:19 +01:00
|
|
|
|
//using GroupDocs.Parser;
|
|
|
|
|
|
//using GroupDocs.Parser.Data;
|
|
|
|
|
|
//using iText.Kernel.Pdf;
|
2024-03-01 16:05:06 +01:00
|
|
|
|
|
|
|
|
|
|
using Imazen.WebP;
|
|
|
|
|
|
|
2024-08-27 09:56:45 +02:00
|
|
|
|
using Xabe.FFmpeg;
|
|
|
|
|
|
|
2024-03-01 16:05:06 +01:00
|
|
|
|
using SharpCompress.Archives;
|
|
|
|
|
|
using SharpCompress.Archives.Zip;
|
|
|
|
|
|
using SharpCompress.Common;
|
2025-01-23 12:53:22 +01:00
|
|
|
|
//using itext.pdfimage.Extensions;
|
2024-03-01 16:05:06 +01:00
|
|
|
|
using org.omg.PortableInterceptor;
|
|
|
|
|
|
using org.apache.pdfbox.util.@operator;
|
|
|
|
|
|
using java.nio;
|
|
|
|
|
|
using ImageMagick;
|
2024-04-20 13:14:52 +02:00
|
|
|
|
using javax.xml.transform;
|
|
|
|
|
|
using System.Collections.Concurrent;
|
|
|
|
|
|
using iText.Barcodes.Dmcode;
|
2024-08-27 09:56:45 +02:00
|
|
|
|
using Xabe.FFmpeg.Downloader;
|
|
|
|
|
|
using System.Reflection;
|
|
|
|
|
|
using Microsoft.VisualBasic;
|
|
|
|
|
|
using BinaryKits.Zpl.Viewer;
|
2025-03-27 19:01:22 +01:00
|
|
|
|
using iMGcompress_core;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-03-01 16:05:06 +01:00
|
|
|
|
|
2025-01-23 12:53:22 +01:00
|
|
|
|
using iMGcompress_core;
|
|
|
|
|
|
using Compressor = iMGcompress_core.Compressor;
|
|
|
|
|
|
|
2024-03-01 16:05:06 +01:00
|
|
|
|
namespace ComicCompressor
|
|
|
|
|
|
{
|
|
|
|
|
|
public class Program
|
|
|
|
|
|
{
|
2024-08-27 09:56:45 +02:00
|
|
|
|
|
2025-01-23 12:53:22 +01:00
|
|
|
|
// string progVersion = "Version 2.0.0 - (04/07/2024)";
|
2024-08-27 09:56:45 +02:00
|
|
|
|
|
|
|
|
|
|
// Added copy of non image files with same name
|
|
|
|
|
|
//string progVersion = "Version 2.0.1 - (12/08/2024)";
|
|
|
|
|
|
|
|
|
|
|
|
// Added support for ZEBRA PRN files, generate image and base64 for prn and image.
|
2024-08-28 23:33:52 +02:00
|
|
|
|
//string progVersion = "Version 2.0.2 - (27/08/2024)";
|
|
|
|
|
|
|
|
|
|
|
|
// Completed support for ZEBRA PRN files, generate image and base64 for prn and image. Using URI format for base64 files
|
2025-01-23 12:53:22 +01:00
|
|
|
|
//string progVersion = "Version 2.1.0 - (28/08/2024)";
|
2024-08-27 09:56:45 +02:00
|
|
|
|
|
2025-01-23 12:53:22 +01:00
|
|
|
|
// Moved functionalities to library iMGcompress-core
|
|
|
|
|
|
//string progVersion = "Version 3.0.0 - (21/11/2024)";
|
|
|
|
|
|
|
|
|
|
|
|
// In core changed color of percent save to white
|
2026-06-28 00:48:54 +02:00
|
|
|
|
//string progVersion = "Version 3.0.1 - (23/01/2025)";
|
|
|
|
|
|
|
2026-06-28 01:04:07 +02:00
|
|
|
|
// Updated NuGet packages (SharpCompress 0.49, Magick.NET 14.14, System.Drawing.Common 10.0,
|
|
|
|
|
|
// itext 9.6, Imazen.WebP 11.0, McMaster 5.1). SharpCompress 0.49 API migration.
|
|
|
|
|
|
// Pre-sized MemoryStream allocations with entry.Size (reduced GC pressure).
|
|
|
|
|
|
// Fixed missing OnExecuteAsync (CLI was throwing InvalidOperationException on launch).
|
|
|
|
|
|
// Added -w|--new-webp flag (Imageflow encoder; benchmarked slower than Imazen.WebP).
|
|
|
|
|
|
// Added -x|--par-archive: parallel image compression within archive (~4-5x speedup).
|
|
|
|
|
|
// Batched 3-phase: sequential read → Parallel.For (ProcessorCount/2) → sequential write.
|
|
|
|
|
|
// GUI: added Par.Archive checkbox (default ON for COMIX/COMIX+PDF modes).
|
2026-06-28 00:48:54 +02:00
|
|
|
|
string progVersion = "Version 3.1.0 - (27/06/2027)";
|
2024-03-01 16:05:06 +01:00
|
|
|
|
public static int Main(string[] args) => CommandLineApplication.Execute<Program>(args);
|
|
|
|
|
|
|
2024-04-20 13:14:52 +02:00
|
|
|
|
#region INPUT_FLAGS
|
2024-03-01 16:05:06 +01:00
|
|
|
|
[FileOrDirectoryExists]
|
|
|
|
|
|
[Option("-i|--input <FOLDER/FIlE>", Description = "The file or folder to convert")]
|
|
|
|
|
|
[Required]
|
|
|
|
|
|
public string Input { get; }
|
|
|
|
|
|
|
|
|
|
|
|
[Option("-o|--output <FOLDER>",
|
|
|
|
|
|
Description =
|
|
|
|
|
|
"Base path of the output (will be in output/subfolders if the recursive option is enabled), default: converted_comics")]
|
|
|
|
|
|
public string OutputFolder { get; } = "converted_comics";
|
|
|
|
|
|
|
|
|
|
|
|
[Option("-r|--recursive", Description = "Recursively traverse the input folder (include all subfolders)")]
|
|
|
|
|
|
public bool Recursive { get; } = false;
|
|
|
|
|
|
|
|
|
|
|
|
[Option("-s|--skip", Description = "Skip processing file if it already exists in the output folder")]
|
|
|
|
|
|
public bool Skip { get; } = false;
|
|
|
|
|
|
|
|
|
|
|
|
[Option("-q|--quality", Description = "Quality to use for the webp files (default: 75)")]
|
|
|
|
|
|
public int Quality { get; } = 75;
|
|
|
|
|
|
|
|
|
|
|
|
[Option("-p|--parallel", Description = "Run in parallel, utilizing all computing resources")]
|
|
|
|
|
|
public bool IsParallel { get; } = false;
|
|
|
|
|
|
|
2024-08-28 23:39:20 +02:00
|
|
|
|
[Option("-c|--cpu", Description = "Run in parallel, use given number of CPUs")]
|
2024-03-01 16:05:06 +01:00
|
|
|
|
public int NumOfCpu { get; } = Environment.ProcessorCount;
|
|
|
|
|
|
|
2024-08-28 23:39:20 +02:00
|
|
|
|
[Option("-d|--pdf", Description = "Process pdf only")]
|
2024-03-01 16:05:06 +01:00
|
|
|
|
public bool DoPdf { get; } = false;
|
|
|
|
|
|
|
2024-08-28 23:39:20 +02:00
|
|
|
|
[Option("-j|--image", Description = "Process images only")]
|
2024-03-01 16:05:06 +01:00
|
|
|
|
public bool DoImage { get; } = false;
|
2024-05-16 17:53:27 +02:00
|
|
|
|
|
2024-08-28 23:33:52 +02:00
|
|
|
|
[Option("-n|--prn", Description = "Process Zebra PRN files, generate png and webp from jpeg in base64 URI format")]
|
2024-08-27 09:56:45 +02:00
|
|
|
|
public bool DoPrn { get; } = false;
|
2024-08-28 23:39:20 +02:00
|
|
|
|
[Option("-a|--copyall", Description = "Copy all unprocessed files")]
|
2024-05-16 17:53:27 +02:00
|
|
|
|
public bool DoCopyAll { get; } = false;
|
|
|
|
|
|
|
2026-06-28 00:48:54 +02:00
|
|
|
|
[Option("-w|--new-webp", Description = "Use Imageflow encoder (faster JPEG→WebP transcoding, no full pixel decode)")]
|
|
|
|
|
|
public bool NewWebp { get; } = false;
|
|
|
|
|
|
|
2026-06-28 01:04:07 +02:00
|
|
|
|
[Option("-x|--par-archive", Description = "Parallel image compression within each archive (~4-5x faster, uses half the CPUs)")]
|
2026-06-28 00:48:54 +02:00
|
|
|
|
public bool ParArchive { get; } = false;
|
|
|
|
|
|
|
2024-04-20 13:14:52 +02:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region STATISTICS
|
|
|
|
|
|
|
|
|
|
|
|
static Dictionary <string, file_stat> file_statistics = new Dictionary<string, file_stat>();
|
|
|
|
|
|
public static Dictionary<string, file_stat> File_statistics { get => file_statistics; set => file_statistics = value; }
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
2024-03-01 16:05:06 +01:00
|
|
|
|
|
|
|
|
|
|
private Logger Logger { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
SimpleEncoder encoder = new SimpleEncoder();
|
|
|
|
|
|
private List<Stream> imageStreams = null;
|
|
|
|
|
|
public ZipArchive output = null;
|
2024-04-20 13:14:52 +02:00
|
|
|
|
|
|
|
|
|
|
static Random randomGen = new Random();
|
|
|
|
|
|
static KnownColor[] names = (KnownColor[])Enum.GetValues(typeof(KnownColor));
|
|
|
|
|
|
// static KnownColor randomColorName = names[randomGen.Next(names.Length)];
|
|
|
|
|
|
// static Color randomColor = Color.FromKnownColor(randomColorName);
|
|
|
|
|
|
|
|
|
|
|
|
public Color[] myColors = null;
|
2025-03-27 19:01:22 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//static void TestPar2()
|
|
|
|
|
|
//{
|
|
|
|
|
|
// var items = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
|
|
|
|
|
|
|
|
|
|
|
|
// // Create a SingleItemPartitioner from the collection
|
|
|
|
|
|
// var partitioner = new Partitioner<int>(items);
|
|
|
|
|
|
|
|
|
|
|
|
// // Use Parallel.ForEach to process items in parallel
|
|
|
|
|
|
// Parallel.ForEach(partitioner, item =>
|
|
|
|
|
|
// {
|
|
|
|
|
|
// Console.WriteLine($"Processing item: {item}");
|
|
|
|
|
|
// });
|
|
|
|
|
|
//}
|
|
|
|
|
|
|
2025-12-12 15:53:19 +01:00
|
|
|
|
|
|
|
|
|
|
FileProcessor.ProcessorFlags flags = new FileProcessor.ProcessorFlags(null, null,
|
|
|
|
|
|
recursive: false,
|
|
|
|
|
|
skip: false,
|
|
|
|
|
|
parallel: false,
|
|
|
|
|
|
pdf_only: false,
|
|
|
|
|
|
image_only: false,
|
|
|
|
|
|
zebra: false,
|
|
|
|
|
|
copy_all: false,
|
|
|
|
|
|
new_webp: false
|
|
|
|
|
|
);
|
|
|
|
|
|
|
2026-06-28 00:48:54 +02:00
|
|
|
|
private async Task OnExecuteAsync()
|
2024-03-01 16:05:06 +01:00
|
|
|
|
{
|
2024-04-20 13:14:52 +02:00
|
|
|
|
File_statistics.Clear();
|
2026-06-28 00:48:54 +02:00
|
|
|
|
flags.New_webp = NewWebp;
|
|
|
|
|
|
flags.Par_archive = ParArchive;
|
2024-04-20 13:14:52 +02:00
|
|
|
|
|
|
|
|
|
|
myColors = new Color[names.Count()];
|
2026-06-28 00:48:54 +02:00
|
|
|
|
for (int i = 0; i < myColors.Length; i++)
|
2024-04-20 13:14:52 +02:00
|
|
|
|
{
|
|
|
|
|
|
KnownColor randomColorName = names[randomGen.Next(names.Length)];
|
2026-06-28 00:48:54 +02:00
|
|
|
|
myColors[i] = Color.FromKnownColor(randomColorName);
|
2024-04-20 13:14:52 +02:00
|
|
|
|
}
|
2024-03-01 16:05:06 +01:00
|
|
|
|
|
|
|
|
|
|
Stopwatch sw = Stopwatch.StartNew();
|
|
|
|
|
|
|
|
|
|
|
|
Logger = new Logger();
|
2025-03-27 19:01:22 +01:00
|
|
|
|
Logger.DebugOn = true;
|
2024-03-01 16:05:06 +01:00
|
|
|
|
Logger.LoggingLevel = LogLevel.Verbose;
|
|
|
|
|
|
|
2024-08-27 09:56:45 +02:00
|
|
|
|
Logger.Log(progVersion, LogLevel.Verbose, true);
|
|
|
|
|
|
|
2024-03-01 16:05:06 +01:00
|
|
|
|
IList<string> files = new FileParser().ListAllFiles(Input, Recursive);
|
|
|
|
|
|
|
2026-06-28 00:48:54 +02:00
|
|
|
|
await Process(files);
|
2024-03-01 16:05:06 +01:00
|
|
|
|
|
|
|
|
|
|
long time_query = sw.ElapsedMilliseconds;
|
|
|
|
|
|
Logger.Log($"ElapsedTime {time_query} ms", LogLevel.Verbose, true);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-28 00:48:54 +02:00
|
|
|
|
private async Task Process(IList<string> files)
|
2024-03-01 16:05:06 +01:00
|
|
|
|
{
|
|
|
|
|
|
Compressor compressor = new Compressor(Logger);
|
|
|
|
|
|
compressor.Quality = Quality;
|
|
|
|
|
|
int filename_len = 0;
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var file in files)
|
|
|
|
|
|
{
|
2024-04-20 13:14:52 +02:00
|
|
|
|
File_statistics.Add(file, new file_stat(file));
|
2024-03-01 16:05:06 +01:00
|
|
|
|
if(file.Length > filename_len)
|
|
|
|
|
|
filename_len = file.Length;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!IsParallel)
|
|
|
|
|
|
{
|
|
|
|
|
|
int n = 1;
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var file in files)
|
|
|
|
|
|
{
|
|
|
|
|
|
Logger.Log($"{n,3}/{files.Count,3} - ", LogLevel.Verbose, false);
|
2024-08-27 09:56:45 +02:00
|
|
|
|
await CompressTask(compressor, file, filename_len);
|
2024-03-01 16:05:06 +01:00
|
|
|
|
n++;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-04-20 13:14:52 +02:00
|
|
|
|
long tot_uncomp = 0;
|
|
|
|
|
|
long tot_comp = 0;
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var file in file_statistics)
|
|
|
|
|
|
{
|
|
|
|
|
|
long uncomp = file.Value.Uncompressed_file_len;
|
|
|
|
|
|
long comp = file.Value.Compressed_file_len;
|
|
|
|
|
|
if (uncomp != 0 && comp != 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
Logger.Log($"{file.Value.Filename} U[{uncomp}] C[{comp}]", LogLevel.Verbose, true, Color.Pink);
|
|
|
|
|
|
tot_uncomp += uncomp;
|
|
|
|
|
|
tot_comp += comp;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (tot_uncomp != 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
double save = 100 * (double)tot_comp / (double)tot_uncomp;
|
|
|
|
|
|
Logger.Log($"TU[{tot_uncomp}] TC[{tot_comp}] R%[{save,5:##.00}] S[{(tot_uncomp-tot_comp)/1024.0/1024.0,5:##.00} MB]", LogLevel.Verbose, true, Color.Pink);
|
|
|
|
|
|
}
|
2024-03-01 16:05:06 +01:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ParallelOptions options = new ParallelOptions
|
|
|
|
|
|
{
|
|
|
|
|
|
MaxDegreeOfParallelism = (NumOfCpu > Environment.ProcessorCount) ? Environment.ProcessorCount : NumOfCpu
|
|
|
|
|
|
};
|
2024-04-20 13:14:52 +02:00
|
|
|
|
#if true
|
|
|
|
|
|
ParallelQuery<string> source = Partitioner.Create(files)
|
|
|
|
|
|
.AsParallel()
|
|
|
|
|
|
.AsOrdered();
|
2024-03-01 16:05:06 +01:00
|
|
|
|
|
2024-04-20 13:14:52 +02:00
|
|
|
|
Parallel.ForEach(source, options, (file, state, index) => CompressTask(compressor, file, filename_len, true, state, index, files.Count));
|
|
|
|
|
|
#else
|
|
|
|
|
|
Parallel.ForEach(files, options, (file, state, index) => CompressTask(compressor, file, filename_len, true, state, index+1, files.Count));
|
|
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var file in file_statistics)
|
|
|
|
|
|
{
|
|
|
|
|
|
Logger.Log($"{file.Value.Filename} U[{file.Value.Uncompressed_file_len}] C[{file.Value.Compressed_file_len}]", LogLevel.Verbose, true, Color.Pink);
|
|
|
|
|
|
}
|
2024-03-01 16:05:06 +01:00
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-08-27 09:56:45 +02:00
|
|
|
|
private async Task CompressTask(Compressor compressor, string filename, int max_name_len = -1, Boolean isPar = false, ParallelLoopState state = null, long index = 0, long total = 0)
|
2024-03-01 16:05:06 +01:00
|
|
|
|
{
|
|
|
|
|
|
var relativePath = Path.GetRelativePath(Input, filename);
|
|
|
|
|
|
var outputPath = Path.Join(OutputFolder, Path.ChangeExtension(relativePath, "cbz"));
|
|
|
|
|
|
var outputPath_webp = Path.Join(OutputFolder, Path.ChangeExtension(relativePath, "webp"));
|
2024-08-27 09:56:45 +02:00
|
|
|
|
var outputPath_webm = Path.Join(OutputFolder, Path.ChangeExtension(relativePath, "webm"));
|
2024-05-16 17:53:27 +02:00
|
|
|
|
var outputPath_same = Path.Join(OutputFolder, relativePath);
|
2024-04-20 13:14:52 +02:00
|
|
|
|
int digits = 1+(int)Math.Floor(Math.Log((Double)total) / Math.Log(10.0));
|
|
|
|
|
|
|
2024-08-27 09:56:45 +02:00
|
|
|
|
|
|
|
|
|
|
bool isImage = filename.ToLower().EndsWith("jpg") ||
|
|
|
|
|
|
filename.ToLower().EndsWith("jpeg") ||
|
|
|
|
|
|
filename.ToLower().EndsWith("tif") ||
|
|
|
|
|
|
filename.ToLower().EndsWith("bmp") ||
|
|
|
|
|
|
filename.ToLower().EndsWith("png");
|
|
|
|
|
|
|
2024-04-20 13:14:52 +02:00
|
|
|
|
string print_line_header = "";
|
|
|
|
|
|
switch (digits)
|
|
|
|
|
|
{
|
|
|
|
|
|
case 1:
|
|
|
|
|
|
print_line_header = $"{index,1}/{total,1} - ";
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 2:
|
|
|
|
|
|
print_line_header = $"{index,2}/{total,2} - ";
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 3:
|
|
|
|
|
|
print_line_header = $"{index,3}/{total,3} - ";
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 4:
|
|
|
|
|
|
print_line_header = $"{index,4}/{total,4} - ";
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 5:
|
|
|
|
|
|
print_line_header = $"{index,5}/{total,5} - ";
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
2024-03-01 16:05:06 +01:00
|
|
|
|
|
|
|
|
|
|
if (File.Exists(outputPath) && Skip)
|
|
|
|
|
|
{
|
2024-04-20 13:14:52 +02:00
|
|
|
|
long lengthin = new System.IO.FileInfo(filename).Length;
|
|
|
|
|
|
long lengthout = new System.IO.FileInfo(outputPath).Length;
|
2025-01-23 12:53:22 +01:00
|
|
|
|
file_stat fs = null;
|
2024-04-20 13:14:52 +02:00
|
|
|
|
Program.File_statistics.TryGetValue(filename, out fs);
|
|
|
|
|
|
if (fs != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
fs.Uncompressed_file_len = lengthin;
|
|
|
|
|
|
fs.Compressed_file_len = lengthout;
|
|
|
|
|
|
Program.File_statistics.TryAdd(filename, fs);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2024-03-01 16:05:06 +01:00
|
|
|
|
Logger.Log(outputPath, LogLevel.Verbose, true, Color.Yellow);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2024-08-27 09:56:45 +02:00
|
|
|
|
if (DoImage && Skip && isImage && File.Exists(outputPath_webp))
|
2024-03-01 16:05:06 +01:00
|
|
|
|
{
|
2024-04-20 13:14:52 +02:00
|
|
|
|
long lengthin = new System.IO.FileInfo(filename).Length;
|
2024-08-27 09:56:45 +02:00
|
|
|
|
long lengthout = new System.IO.FileInfo(outputPath_webp).Length;
|
2025-01-23 12:53:22 +01:00
|
|
|
|
file_stat fs = null;
|
2024-04-20 13:14:52 +02:00
|
|
|
|
Program.File_statistics.TryGetValue(filename, out fs);
|
|
|
|
|
|
if (fs != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
fs.Uncompressed_file_len = lengthin;
|
|
|
|
|
|
fs.Compressed_file_len = lengthout;
|
|
|
|
|
|
Program.File_statistics.TryAdd(filename, fs);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-03-01 16:05:06 +01:00
|
|
|
|
Logger.Log(outputPath_webp, LogLevel.Verbose, true, Color.Yellow);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (DoPdf && filename.ToLower().EndsWith(".pdf"))
|
|
|
|
|
|
{
|
2024-04-20 13:14:52 +02:00
|
|
|
|
|
|
|
|
|
|
ExtractImageFromPDF(compressor,filename, outputPath);
|
|
|
|
|
|
|
|
|
|
|
|
long lengthin = new System.IO.FileInfo(filename).Length;
|
|
|
|
|
|
long lengthout = new System.IO.FileInfo(outputPath).Length;
|
2025-01-23 12:53:22 +01:00
|
|
|
|
file_stat fs = null;
|
2024-04-20 13:14:52 +02:00
|
|
|
|
Program.File_statistics.TryGetValue(filename, out fs);
|
|
|
|
|
|
if (fs != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
fs.Uncompressed_file_len = lengthin;
|
|
|
|
|
|
fs.Compressed_file_len = lengthout;
|
|
|
|
|
|
Program.File_statistics.TryAdd(filename, fs);
|
|
|
|
|
|
}
|
2024-03-01 16:05:06 +01:00
|
|
|
|
//compressor.CompressPdf(filename, outputPath);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-08-27 09:56:45 +02:00
|
|
|
|
// COMPRESS video to webm
|
|
|
|
|
|
if(filename.ToLower().EndsWith("mp4"))
|
|
|
|
|
|
{
|
|
|
|
|
|
Logger.Log(outputPath_webm, LogLevel.Verbose, true, Color.LightBlue);
|
|
|
|
|
|
|
|
|
|
|
|
IMediaInfo mediaInfo = await FFmpeg.GetMediaInfo(filename);
|
|
|
|
|
|
IStream videoStream = mediaInfo.VideoStreams.FirstOrDefault()
|
|
|
|
|
|
?.SetCodec(VideoCodec.vp8);
|
|
|
|
|
|
IStream audioStream = mediaInfo.AudioStreams.FirstOrDefault();
|
|
|
|
|
|
|
|
|
|
|
|
var conversion = FFmpeg.Conversions.New()
|
|
|
|
|
|
.AddStream(audioStream, videoStream)
|
|
|
|
|
|
.SetOutput(outputPath_webm);
|
|
|
|
|
|
conversion.UseHardwareAcceleration(HardwareAccelerator.cuvid,VideoCodec.h264,VideoCodec.hevc);
|
|
|
|
|
|
|
|
|
|
|
|
// var snippet = await FFmpeg.Conversions.FromSnippet.ToWebM(filename, outputPath_webm);
|
|
|
|
|
|
conversion.OnProgress += (sender, args) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
var percent = (int)(Math.Round(args.Duration.TotalSeconds / args.TotalLength.TotalSeconds, 2) * 100);
|
|
|
|
|
|
Logger.Log($"[{args.Duration} / {args.TotalLength}] {percent}%", LogLevel.Verbose, true, Color.LightBlue);
|
|
|
|
|
|
};
|
|
|
|
|
|
conversion.OnDataReceived += (sender, args) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
Logger.Log($"{args.Data}{Environment.NewLine}", LogLevel.Verbose, true, Color.LightBlue);
|
|
|
|
|
|
};
|
|
|
|
|
|
IConversionResult result = await conversion.Start();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if(DoImage && DoPrn && filename.ToLower().EndsWith("prn"))
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
string[] lines = System.IO.File.ReadAllLines(filename);
|
|
|
|
|
|
lines = lines.Skip(2).ToArray();
|
|
|
|
|
|
string template_prn = string.Join("\r\n",lines);
|
|
|
|
|
|
template_prn = template_prn.Replace(">;", "");
|
|
|
|
|
|
// BinaryKits
|
|
|
|
|
|
IPrinterStorage printerStorage = new PrinterStorage();
|
|
|
|
|
|
var drawer = new ZplElementDrawer(printerStorage);
|
|
|
|
|
|
|
|
|
|
|
|
var analyzer = new ZplAnalyzer(printerStorage);
|
|
|
|
|
|
var analyzeInfo = analyzer.Analyze(template_prn);
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var labelInfo in analyzeInfo.LabelInfos)
|
|
|
|
|
|
{
|
|
|
|
|
|
byte[] img = drawer.Draw(labelInfo.ZplElements);
|
|
|
|
|
|
outputPath = Path.Join(OutputFolder, Path.ChangeExtension(relativePath, ".prn.png"));
|
2024-08-28 19:11:09 +02:00
|
|
|
|
Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
|
2024-08-27 09:56:45 +02:00
|
|
|
|
File.WriteAllBytes(outputPath, img);
|
|
|
|
|
|
//imageData is bytes of png image
|
|
|
|
|
|
string base64String = Convert.ToBase64String(img);
|
2024-08-28 19:11:09 +02:00
|
|
|
|
base64String = "data:image/png;base64," + base64String;
|
2024-08-27 09:56:45 +02:00
|
|
|
|
File.WriteAllText(outputPath + ".base64", base64String);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
Logger.LogError(ex);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-03-01 16:05:06 +01:00
|
|
|
|
|
|
|
|
|
|
if (DoImage &&
|
|
|
|
|
|
filename.ToLower().EndsWith("jpg") ||
|
|
|
|
|
|
filename.ToLower().EndsWith("jpeg") ||
|
2024-03-10 01:20:22 +01:00
|
|
|
|
filename.ToLower().EndsWith("tif") ||
|
2024-05-16 17:53:27 +02:00
|
|
|
|
filename.ToLower().EndsWith("bmp") ||
|
2024-03-01 16:05:06 +01:00
|
|
|
|
filename.ToLower().EndsWith("png"))
|
|
|
|
|
|
{
|
|
|
|
|
|
outputPath = Path.Join(OutputFolder, Path.ChangeExtension(relativePath, "webp"));
|
2024-04-20 13:14:52 +02:00
|
|
|
|
CompressImage(filename, outputPath, max_name_len,isPar, print_line_header);
|
|
|
|
|
|
|
|
|
|
|
|
long lengthin = new System.IO.FileInfo(filename).Length;
|
|
|
|
|
|
long lengthout = new System.IO.FileInfo(outputPath).Length;
|
2025-01-23 12:53:22 +01:00
|
|
|
|
file_stat fs = null;
|
2024-04-20 13:14:52 +02:00
|
|
|
|
Program.File_statistics.TryGetValue(filename, out fs);
|
|
|
|
|
|
if (fs != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
fs.Uncompressed_file_len = lengthin;
|
|
|
|
|
|
fs.Compressed_file_len = lengthout;
|
|
|
|
|
|
Program.File_statistics.TryAdd(filename, fs);
|
|
|
|
|
|
}
|
2024-03-01 16:05:06 +01:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//if (DoImage &&
|
|
|
|
|
|
// filename.ToLower().EndsWith("psd"))
|
|
|
|
|
|
//{
|
|
|
|
|
|
// outputPath = Path.Join(OutputFolder, Path.ChangeExtension(relativePath, "webp"));
|
|
|
|
|
|
// CompressImagePSD(filename, outputPath);
|
|
|
|
|
|
// return;
|
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
|
|
if (!filename.ToLower().EndsWith(".cbr") && !filename.ToLower().EndsWith(".cbz"))
|
|
|
|
|
|
{
|
2024-05-16 17:53:27 +02:00
|
|
|
|
// COPY FILE
|
|
|
|
|
|
if(DoCopyAll)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
Directory.CreateDirectory(Path.GetDirectoryName(outputPath_same));
|
|
|
|
|
|
|
|
|
|
|
|
if (File.Exists(outputPath_same))
|
|
|
|
|
|
Logger.Log(outputPath_same, LogLevel.Verbose, true, Color.LightYellow);
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
File.Copy(filename, outputPath_same, true);
|
|
|
|
|
|
Logger.Log(outputPath_same, LogLevel.Verbose, true, Color.Orange);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
Logger.Log(outputPath_same, LogLevel.Verbose, true, Color.LightYellow);
|
2024-03-01 16:05:06 +01:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
2025-12-12 15:53:19 +01:00
|
|
|
|
compressor.Compress(filename, outputPath, flags:flags);
|
2024-03-01 16:05:06 +01:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
|
{
|
|
|
|
|
|
Logger.Log("Error processing file: " + filename, LogLevel.Error, Color.Red);
|
|
|
|
|
|
Logger.LogDebug(e, LogLevel.Error, col:Color.Red);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#region COMPRESS_PDF
|
|
|
|
|
|
|
|
|
|
|
|
#if false
|
|
|
|
|
|
public static string ExtractImageFromPDF(string sourcePdf)
|
|
|
|
|
|
{
|
|
|
|
|
|
iText.Kernel.Pdf.PdfReader reader = new iText.Kernel.Pdf.PdfReader(sourcePdf);
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
iText.Kernel.Pdf.PdfDocument document = new iText.Kernel.Pdf.PdfDocument(reader);
|
|
|
|
|
|
|
2024-05-07 17:37:57 +02:00
|
|
|
|
for (int pageNumber = 1; pageNumber <= document.GetNumberOfPages(); pageNumber++)
|
2024-03-01 16:05:06 +01:00
|
|
|
|
{
|
2024-05-07 17:37:57 +02:00
|
|
|
|
iText.Kernel.Pdf.PdfDictionary obj = (iText.Kernel.Pdf.PdfDictionary)document.GetPdfObject(pageNumber);
|
2024-03-01 16:05:06 +01:00
|
|
|
|
|
|
|
|
|
|
if (obj != null && obj.IsStream())
|
|
|
|
|
|
{
|
2024-05-07 17:37:57 +02:00
|
|
|
|
iText.Kernel.Pdf.PdfDictionary pd = (iText.Kernel.Pdf.PdfDictionary)obj;
|
2024-03-01 16:05:06 +01:00
|
|
|
|
if (pd.ContainsKey(iText.Kernel.Pdf.PdfName.Subtype) && pd.Get(iText.Kernel.Pdf.PdfName.Subtype).ToString() == "/Image")
|
|
|
|
|
|
{
|
2024-05-07 17:37:57 +02:00
|
|
|
|
string filter = pd.Get(iText.Kernel.Pdf.PdfName.Filter).ToString();
|
|
|
|
|
|
string width = pd.Get(iText.Kernel.Pdf.PdfName.Width).ToString();
|
|
|
|
|
|
string height = pd.Get(iText.Kernel.Pdf.PdfName.Height).ToString();
|
|
|
|
|
|
string bpp = pd.Get(iText.Kernel.Pdf.PdfName.BitsPerComponent).ToString();
|
|
|
|
|
|
string extent = ".";
|
|
|
|
|
|
byte[] img = pd.Get(iText.Kernel.Pdf.PdfName.Image);
|
2024-03-01 16:05:06 +01:00
|
|
|
|
Debug.WriteLine(filter);
|
|
|
|
|
|
continue;
|
|
|
|
|
|
switch (filter)
|
|
|
|
|
|
{
|
|
|
|
|
|
case "/FlateDecode":
|
2024-05-07 17:37:57 +02:00
|
|
|
|
byte[] arr = FlateDecodeFilter.FlateDecode(img, true);
|
|
|
|
|
|
Bitmap bmp = new Bitmap(Int32.Parse(width), Int32.Parse(height), PixelFormat.Format24bppRgb);
|
|
|
|
|
|
BitmapData bmd = bmp.LockBits(new Rectangle(0, 0, Int32.Parse(width), Int32.Parse(height)), ImageLockMode.WriteOnly,
|
2024-03-01 16:05:06 +01:00
|
|
|
|
PixelFormat.Format24bppRgb);
|
|
|
|
|
|
Marshal.Copy(arr, 0, bmd.Scan0, arr.Length);
|
|
|
|
|
|
bmp.UnlockBits(bmd);
|
|
|
|
|
|
bmp.Save("d:\\pdf\\bmp1.png", ImageFormat.Png);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "/CCITTFaxDecode":
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch
|
|
|
|
|
|
{
|
|
|
|
|
|
throw;
|
|
|
|
|
|
}
|
|
|
|
|
|
return "";
|
|
|
|
|
|
}
|
|
|
|
|
|
#elif false
|
|
|
|
|
|
public static string ExtractImageFromPDF(string sourcePdf)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Create an instance of Parser class
|
|
|
|
|
|
using (Parser parser = new Parser(sourcePdf))
|
|
|
|
|
|
{
|
|
|
|
|
|
// Extract images
|
|
|
|
|
|
var di = parser.GetDocumentInfo();
|
|
|
|
|
|
|
|
|
|
|
|
for (int p = 0; p < di.PageCount; p++)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
IEnumerable<PageImageArea> images = parser.GetImages(p);
|
|
|
|
|
|
//IEnumerable<PageImageArea> images = parser.GetImages();
|
|
|
|
|
|
// Check if image extraction is supported
|
|
|
|
|
|
if (images == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Console.WriteLine("Images extraction isn’t supported");
|
|
|
|
|
|
return "";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int counter = 1;
|
|
|
|
|
|
// Iterate over images
|
|
|
|
|
|
foreach (PageImageArea image in images)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Save each image
|
|
|
|
|
|
Image.FromStream(image.GetImageStream())
|
|
|
|
|
|
.Save(string.Format($"{p.ToString("0000")}_{counter++.ToString("0000")}.jpg"), ImageFormat.Jpeg);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return "";
|
|
|
|
|
|
}
|
2024-04-20 13:14:52 +02:00
|
|
|
|
#elif false
|
2024-03-01 16:05:06 +01:00
|
|
|
|
public int GetPlace(int value, int place)
|
|
|
|
|
|
{
|
|
|
|
|
|
return ((value % (place * 10)) - (value % place)) / place;
|
|
|
|
|
|
}
|
|
|
|
|
|
private bool Cover = true;
|
|
|
|
|
|
int _currentPage = 1;
|
|
|
|
|
|
int _imageCount = 0;
|
|
|
|
|
|
public void ExtractImageFromPDF(string sourcePdf, string outputFolder)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
long input_length = new System.IO.FileInfo(sourcePdf).Length;
|
|
|
|
|
|
var pdf = File.Open(sourcePdf, FileMode.Open);
|
|
|
|
|
|
|
|
|
|
|
|
var reader = new PdfReader(pdf);
|
|
|
|
|
|
var pdfDocument = new PdfDocument(reader);
|
|
|
|
|
|
int numOfPages = pdfDocument.GetNumberOfPages();
|
|
|
|
|
|
//var bitmaps = pdfDocument.ConvertToBitmaps();
|
|
|
|
|
|
|
|
|
|
|
|
Logger.Log($"Processing[{numOfPages}]: " + outputFolder, LogLevel.Verbose);
|
|
|
|
|
|
|
|
|
|
|
|
output = ZipArchive.Create();
|
|
|
|
|
|
imageStreams = new List<Stream>();
|
|
|
|
|
|
int count = 0;
|
|
|
|
|
|
Cover = true;
|
|
|
|
|
|
Stopwatch sw = Stopwatch.StartNew();
|
|
|
|
|
|
for (int p = 1; p <= numOfPages; p++)
|
|
|
|
|
|
{
|
|
|
|
|
|
PdfPage page = pdfDocument.GetPage(p);
|
|
|
|
|
|
//var bitmap = page.ConvertPageToBitmap();
|
|
|
|
|
|
MemoryStream jpg = (MemoryStream)page.ConvertPageToJpg();
|
|
|
|
|
|
|
|
|
|
|
|
//bitmap.Save(Path.Combine($"wave-{DateTime.Now.Ticks}.png"), ImageFormat.Png);
|
|
|
|
|
|
ProcessPdfImage(jpg);
|
|
|
|
|
|
//jpg.Dispose();
|
|
|
|
|
|
//page.Flush();
|
|
|
|
|
|
|
|
|
|
|
|
_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();
|
|
|
|
|
|
|
|
|
|
|
|
long output_length = new System.IO.FileInfo(outputFolder).Length;
|
|
|
|
|
|
|
|
|
|
|
|
double save = 100 * (double)output_length / (double)input_length;
|
|
|
|
|
|
if (numOfPages == 0) numOfPages = 1;
|
|
|
|
|
|
long elapsed = sw.ElapsedMilliseconds;
|
|
|
|
|
|
Logger.Log($"\r\nFinished({save.ToString("0.##")}) [{elapsed}][{elapsed / numOfPages}]: " + outputFolder, LogLevel.Verbose);
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
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 System.Drawing.Rectangle(0, 0, clone.Width, clone.Height));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return clone;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static byte[] ImageToByte(Image img)
|
|
|
|
|
|
{
|
|
|
|
|
|
ImageConverter converter = new ImageConverter();
|
|
|
|
|
|
return (byte[])converter.ConvertTo(img, typeof(byte[]));
|
|
|
|
|
|
}
|
|
|
|
|
|
public void ProcessPdfImage(MemoryStream jpg)
|
|
|
|
|
|
{
|
|
|
|
|
|
Stopwatch sw = Stopwatch.StartNew();
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
var image = new Bitmap(jpg);
|
|
|
|
|
|
//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))
|
|
|
|
|
|
{
|
|
|
|
|
|
//Logger.Log($"0 [{image.Width}][{image.Height}]" + sw.ElapsedMilliseconds.ToString(), LogLevel.Verbose);
|
|
|
|
|
|
|
|
|
|
|
|
//var imageRawBytes = ImageToByte(image);
|
|
|
|
|
|
//var image = imageObject.GetDrawingImage();
|
|
|
|
|
|
|
|
|
|
|
|
//Logger.Log("1 "+sw.ElapsedMilliseconds.ToString(), LogLevel.Verbose);
|
|
|
|
|
|
|
|
|
|
|
|
//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;
|
|
|
|
|
|
}
|
|
|
|
|
|
//Logger.Log("2 " + sw.ElapsedMilliseconds.ToString(), LogLevel.Verbose);
|
|
|
|
|
|
|
|
|
|
|
|
var ms = new MemoryStream();
|
|
|
|
|
|
encoder.Encode((Bitmap)image, ms, Quality);
|
|
|
|
|
|
//Logger.Log("3 " + sw.ElapsedMilliseconds.ToString(), LogLevel.Verbose);
|
|
|
|
|
|
|
|
|
|
|
|
if (!Cover && ms.Length < jpg.Length)
|
|
|
|
|
|
{
|
|
|
|
|
|
imageStreams.Add(ms);
|
|
|
|
|
|
output.AddEntry(imageFileName + ".webp", ms);
|
|
|
|
|
|
Logger.Log(".", LogLevel.Verbose, false);
|
|
|
|
|
|
//Logger.Log("4 " + sw.ElapsedMilliseconds.ToString(), LogLevel.Verbose);
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
//var mso = new MemoryStream();
|
|
|
|
|
|
//mso.Write(imageRawBytes);
|
|
|
|
|
|
// output.AddEntry(imageFileName + imageObject.GetFileType(), mso);
|
|
|
|
|
|
imageStreams.Add(ms);
|
|
|
|
|
|
output.AddEntry(imageFileName + ".jpg", jpg);
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//Logger.Log(sw.ElapsedMilliseconds.ToString(), LogLevel.Verbose);
|
|
|
|
|
|
}
|
2024-04-20 13:14:52 +02:00
|
|
|
|
#else
|
|
|
|
|
|
public void ExtractImageFromPDF(Compressor compressor, string sourcePdf, string outputFolder)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
//pdfimages.exe -j "Dragon Ball Full Color [Volume 1].pdf" "Dragon Ball Full Color [Volume 1]\img"
|
|
|
|
|
|
//7za a -r -mx0 -tzip "Dragon Ball Full Color [Volume 1]" "Dragon Ball Full Color [Volume 1]\*"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
string subfolder = Path.GetFileNameWithoutExtension(sourcePdf);
|
|
|
|
|
|
string folder = Path.GetDirectoryName(sourcePdf);
|
|
|
|
|
|
string tempfolder = folder + "\\" + subfolder;
|
|
|
|
|
|
Directory.CreateDirectory(tempfolder);
|
|
|
|
|
|
|
|
|
|
|
|
Logger.Log(sourcePdf, LogLevel.Verbose, true, Color.Green);
|
|
|
|
|
|
|
|
|
|
|
|
ProcessStartInfo startInfo_pdfimages = new ProcessStartInfo("pdfimages.exe");
|
|
|
|
|
|
startInfo_pdfimages.Arguments = $@" -j ""{sourcePdf}"" ""{tempfolder}\img""";
|
|
|
|
|
|
startInfo_pdfimages.UseShellExecute = false;
|
|
|
|
|
|
Process pdfimages = System.Diagnostics.Process.Start(startInfo_pdfimages);
|
|
|
|
|
|
pdfimages.WaitForExit();
|
|
|
|
|
|
|
|
|
|
|
|
string zipFile = tempfolder + ".zip";
|
|
|
|
|
|
ProcessStartInfo startInfo_7za = new ProcessStartInfo("7za.exe");
|
|
|
|
|
|
startInfo_7za.Arguments = $@" a -r -mx0 -tzip -sdel ""{zipFile}"" ""{tempfolder}\*"" > $null 2>&1";
|
|
|
|
|
|
startInfo_7za.UseShellExecute = false;
|
|
|
|
|
|
startInfo_7za.RedirectStandardOutput = true;
|
|
|
|
|
|
Process zip7za = System.Diagnostics.Process.Start(startInfo_7za);
|
|
|
|
|
|
zip7za.WaitForExit();
|
|
|
|
|
|
Directory.Delete(tempfolder);
|
|
|
|
|
|
|
|
|
|
|
|
if (File.Exists(outputFolder) && Skip)
|
|
|
|
|
|
{
|
|
|
|
|
|
Logger.Log(outputFolder, LogLevel.Verbose, true, Color.Yellow);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
compressor.Compress(zipFile, outputFolder);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
|
{
|
|
|
|
|
|
Logger.Log("Error processing file: " + zipFile, LogLevel.Error, Color.Red);
|
|
|
|
|
|
Logger.LogDebug(e, LogLevel.Error, col: Color.Red);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-03-01 16:05:06 +01:00
|
|
|
|
#endif
|
|
|
|
|
|
|
2024-04-20 13:14:52 +02:00
|
|
|
|
#endregion
|
2024-03-01 16:05:06 +01:00
|
|
|
|
|
|
|
|
|
|
#region COMPRESS_IMAGE
|
2024-08-28 19:11:09 +02:00
|
|
|
|
|
|
|
|
|
|
|
2024-04-20 13:14:52 +02:00
|
|
|
|
public void CompressImage(string imagefile, string outputFolder, int max_name_len = -1, Boolean isPar = false, string print_line_header = "")
|
2024-03-01 16:05:06 +01:00
|
|
|
|
{
|
|
|
|
|
|
string name_print = imagefile;
|
|
|
|
|
|
if(max_name_len > 0)
|
|
|
|
|
|
name_print = imagefile.PadRight(max_name_len);
|
|
|
|
|
|
if(!isPar)
|
2024-04-20 13:14:52 +02:00
|
|
|
|
Logger.Log(print_line_header+name_print, LogLevel.Verbose, false, col:Color.LightBlue);
|
2024-03-01 16:05:06 +01:00
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
Directory.CreateDirectory(Path.GetDirectoryName(outputFolder));
|
|
|
|
|
|
|
|
|
|
|
|
var encoder = new SimpleEncoder();
|
|
|
|
|
|
|
|
|
|
|
|
Bitmap mBitmap;
|
|
|
|
|
|
long length_in = 0;
|
|
|
|
|
|
FileStream outStream = new FileStream(outputFolder, FileMode.Create);
|
|
|
|
|
|
using (Stream BitmapStream = System.IO.File.Open(imagefile, System.IO.FileMode.Open))
|
|
|
|
|
|
{
|
2024-08-28 23:33:52 +02:00
|
|
|
|
// Write Webp
|
2024-03-01 16:05:06 +01:00
|
|
|
|
length_in = BitmapStream.Length;
|
|
|
|
|
|
Image img = Image.FromStream(BitmapStream);
|
2024-08-28 23:33:52 +02:00
|
|
|
|
|
|
|
|
|
|
//Encode webp
|
2024-03-01 16:05:06 +01:00
|
|
|
|
mBitmap = new Bitmap(img);
|
|
|
|
|
|
|
|
|
|
|
|
IntPtr result;
|
|
|
|
|
|
long length = 0;
|
|
|
|
|
|
encoder.Encode(mBitmap, outStream, 70);
|
|
|
|
|
|
|
|
|
|
|
|
outStream.Flush();
|
|
|
|
|
|
outStream.Close();
|
2024-08-27 09:56:45 +02:00
|
|
|
|
|
2024-08-28 23:33:52 +02:00
|
|
|
|
// Process images for PRN integration in Pin4ProdCrtl
|
2024-08-27 09:56:45 +02:00
|
|
|
|
if (DoPrn)
|
|
|
|
|
|
{
|
2024-08-28 19:11:09 +02:00
|
|
|
|
var image = Image.FromStream(BitmapStream);
|
|
|
|
|
|
|
|
|
|
|
|
using (EncoderParameters encParams = new EncoderParameters(1))
|
|
|
|
|
|
{
|
|
|
|
|
|
using (EncoderParameter encoderParameter = new EncoderParameter(Encoder.Quality, 33L))
|
|
|
|
|
|
{
|
2024-08-28 23:33:52 +02:00
|
|
|
|
// Write JPEG
|
2024-08-28 19:11:09 +02:00
|
|
|
|
encParams.Param[0] = encoderParameter;
|
|
|
|
|
|
var encoderJpeg = ImageCodecInfo.GetImageEncoders()
|
|
|
|
|
|
.First(c => c.FormatID == ImageFormat.Jpeg.Guid);
|
|
|
|
|
|
|
|
|
|
|
|
var stream = new MemoryStream();
|
|
|
|
|
|
// image.Save(stream, ImageFormat.Jpeg);
|
|
|
|
|
|
image.Save(stream, encoderJpeg, encParams);
|
|
|
|
|
|
|
|
|
|
|
|
byte[] imageBytes = stream.ToArray();
|
|
|
|
|
|
string base64String = Convert.ToBase64String(imageBytes);
|
|
|
|
|
|
base64String = "data:image/jpeg;base64," + base64String;
|
|
|
|
|
|
|
|
|
|
|
|
string outjpeg = outputFolder.Replace("webp", "jpeg");
|
|
|
|
|
|
|
2024-08-28 23:33:52 +02:00
|
|
|
|
// Write base64 jpeg
|
2024-08-28 19:11:09 +02:00
|
|
|
|
File.WriteAllText(outjpeg + ".base64", base64String);
|
|
|
|
|
|
|
|
|
|
|
|
FileStream outStreamjpeg = new FileStream(outjpeg, FileMode.Create);
|
|
|
|
|
|
stream.Position = 0;
|
|
|
|
|
|
stream.CopyTo(outStreamjpeg);
|
|
|
|
|
|
outStreamjpeg.Flush();
|
|
|
|
|
|
outStreamjpeg.Close();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-12 15:59:41 +01:00
|
|
|
|
image.Dispose();
|
2024-08-28 19:11:09 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if true
|
2024-08-27 09:56:45 +02:00
|
|
|
|
using (MemoryStream m = new MemoryStream())
|
|
|
|
|
|
{
|
2024-08-28 23:33:52 +02:00
|
|
|
|
// Write base64 webp
|
2024-08-27 09:56:45 +02:00
|
|
|
|
encoder.Encode(mBitmap, m, 70);
|
|
|
|
|
|
byte[] imageBytes = m.ToArray();
|
|
|
|
|
|
string base64String = Convert.ToBase64String(imageBytes);
|
2024-08-28 19:11:09 +02:00
|
|
|
|
base64String = "data:image/webp;base64," + base64String;
|
2024-08-27 09:56:45 +02:00
|
|
|
|
File.WriteAllText(outputFolder + ".base64", base64String);
|
|
|
|
|
|
|
2024-08-28 23:33:52 +02:00
|
|
|
|
// regen image from base64 as debug
|
2024-08-28 19:11:09 +02:00
|
|
|
|
//byte[] imageBytes_o = Convert.FromBase64String(base64String);
|
|
|
|
|
|
//using (MemoryStream ms = new MemoryStream(imageBytes_o))
|
|
|
|
|
|
//{
|
|
|
|
|
|
// // Create image from memory stream
|
|
|
|
|
|
// using (FileStream file = new FileStream(outputFolder + ".base64.webp", FileMode.Create, System.IO.FileAccess.Write))
|
|
|
|
|
|
// {
|
|
|
|
|
|
// ms.WriteTo(file);
|
|
|
|
|
|
// }
|
|
|
|
|
|
//}
|
2024-08-27 09:56:45 +02:00
|
|
|
|
}
|
2024-08-28 19:11:09 +02:00
|
|
|
|
#endif
|
2024-08-27 09:56:45 +02:00
|
|
|
|
}
|
2024-03-01 16:05:06 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
FileInfo finfo = new FileInfo(outputFolder);
|
|
|
|
|
|
long length_out = finfo.Length;
|
|
|
|
|
|
if (isPar)
|
2024-04-20 13:14:52 +02:00
|
|
|
|
{
|
|
|
|
|
|
#if false
|
|
|
|
|
|
Logger.Log($"{print_line_header}[{Environment.CurrentManagedThreadId}]{name_print} - IN[{length_in,10}] OUT[{length_out,10}] %[{(100.0 * length_out / (double)length_in),5:##.00}]", LogLevel.Verbose, true, col: Color.Green);
|
|
|
|
|
|
#else
|
|
|
|
|
|
lock (Logger)
|
|
|
|
|
|
{
|
|
|
|
|
|
Logger.Log($"{print_line_header}[{Environment.CurrentManagedThreadId,2}] ", LogLevel.Verbose, false, col: myColors[Environment.CurrentManagedThreadId]);
|
|
|
|
|
|
Logger.Log($"{name_print} - IN[{length_in,10}] OUT[{length_out,10}] %[{(100.0 * length_out / (double)length_in),5:##.00}]", LogLevel.Verbose, true, col: Color.Green);
|
|
|
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
}
|
2024-03-01 16:05:06 +01:00
|
|
|
|
else
|
2024-04-20 13:14:52 +02:00
|
|
|
|
Logger.Log($" - IN[{length_in,10}] OUT[{length_out,10}] %[{(100.0 * length_out / (double)length_in),5:##.00}]", LogLevel.Verbose, true, col: Color.LightBlue);
|
2024-03-01 16:05:06 +01:00
|
|
|
|
}
|
|
|
|
|
|
catch(Exception e)
|
|
|
|
|
|
{
|
2024-04-20 13:14:52 +02:00
|
|
|
|
lock (Logger)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (isPar)
|
|
|
|
|
|
{
|
|
|
|
|
|
Logger.Log($"{print_line_header}[{Environment.CurrentManagedThreadId}]{name_print} ERROR", LogLevel.Verbose, true, col: Color.Red);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
Logger.Log($" ERROR", LogLevel.Verbose, true, col: Color.Red);
|
|
|
|
|
|
}
|
|
|
|
|
|
Logger.LogError(e, col: Color.Red);
|
|
|
|
|
|
}
|
2024-03-01 16:05:06 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void CompressImagePSD(string imagefile, string outputFolder)
|
|
|
|
|
|
{
|
|
|
|
|
|
Logger.Log(imagefile, LogLevel.Verbose, false);
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
Directory.CreateDirectory(Path.GetDirectoryName(outputFolder));
|
|
|
|
|
|
|
|
|
|
|
|
var encoder = new SimpleEncoder();
|
|
|
|
|
|
|
|
|
|
|
|
Bitmap mBitmap;
|
|
|
|
|
|
long length_in = 0;
|
|
|
|
|
|
FileStream outStream = new FileStream(outputFolder, FileMode.Create);
|
|
|
|
|
|
using (Stream BitmapStream = System.IO.File.Open(imagefile, System.IO.FileMode.Open))
|
|
|
|
|
|
{
|
|
|
|
|
|
length_in = BitmapStream.Length;
|
|
|
|
|
|
|
|
|
|
|
|
//using var imageFromFile = new MagickImage(BitmapStream);
|
|
|
|
|
|
using (MagickImageCollection magickImages = new MagickImageCollection(BitmapStream))
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var image in magickImages)
|
|
|
|
|
|
{
|
|
|
|
|
|
Image img = image.ToBitmap();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//Image img = Image.FromStream(BitmapStream);
|
|
|
|
|
|
//Image img = imageFromFile.ToBitmap();
|
|
|
|
|
|
mBitmap = new Bitmap(img);
|
|
|
|
|
|
|
|
|
|
|
|
IntPtr result;
|
|
|
|
|
|
long length = 0;
|
|
|
|
|
|
encoder.Encode(mBitmap, outStream, 70);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
outStream.Flush();
|
|
|
|
|
|
outStream.Close();
|
|
|
|
|
|
//encoder.Encode(mBitmap, 70, out result, out length);
|
|
|
|
|
|
//UnmanagedMemoryStream ustream = new UnmanagedMemoryStream((byte*)result, length);
|
|
|
|
|
|
//ustream.CopyTo(outStream);
|
|
|
|
|
|
//ustream.Close();
|
|
|
|
|
|
//outStrea.Close();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
FileInfo finfo = new FileInfo(outputFolder);
|
|
|
|
|
|
long length_out = finfo.Length;
|
|
|
|
|
|
Logger.Log($" - IN[{length_in}] OUT[{length_out}] %[{100.0 * length_out / (double)length_in}]", LogLevel.Verbose, true);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
|
{
|
|
|
|
|
|
Logger.LogError(e);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
2024-04-20 13:14:52 +02:00
|
|
|
|
#endregion
|
2024-03-01 16:05:06 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|