Added Compression statistics report in every run
QqAdded support for reading PPM PixelMap image files.
This commit is contained in:
@@ -4,7 +4,7 @@
|
|||||||
<DebuggerFlavor>ProjectDebugger</DebuggerFlavor>
|
<DebuggerFlavor>ProjectDebugger</DebuggerFlavor>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<ActiveDebugProfile>ComicCompress PDF</ActiveDebugProfile>
|
<ActiveDebugProfile>ComicCompress</ActiveDebugProfile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
<DebuggerFlavor>ProjectDebugger</DebuggerFlavor>
|
<DebuggerFlavor>ProjectDebugger</DebuggerFlavor>
|
||||||
|
|||||||
+30
-6
@@ -88,7 +88,7 @@ namespace ComicCompressor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
(save, num_pages) = ProcessArchive(archive, outputFile);
|
(save, num_pages) = ProcessArchive(archive, outputFile, filename);
|
||||||
if (num_pages == 0) num_pages = 1;
|
if (num_pages == 0) num_pages = 1;
|
||||||
long elapsed = sw.ElapsedMilliseconds;
|
long elapsed = sw.ElapsedMilliseconds;
|
||||||
Logger.Log($"\r\nFinished({save.ToString("0.##")}%) [{elapsed}][{elapsed/num_pages}]: " + filename, LogLevel.Verbose, col: Color.Green);
|
Logger.Log($"\r\nFinished({save.ToString("0.##")}%) [{elapsed}][{elapsed/num_pages}]: " + filename, LogLevel.Verbose, col: Color.Green);
|
||||||
@@ -124,6 +124,7 @@ namespace ComicCompressor
|
|||||||
if (!entry_key_lower.EndsWith(".jpg") &&
|
if (!entry_key_lower.EndsWith(".jpg") &&
|
||||||
!entry_key_lower.EndsWith(".png") &&
|
!entry_key_lower.EndsWith(".png") &&
|
||||||
!entry_key_lower.EndsWith(".bmp") &&
|
!entry_key_lower.EndsWith(".bmp") &&
|
||||||
|
!entry_key_lower.EndsWith(".ppm") &&
|
||||||
!entry_key_lower.EndsWith(".gif") &&
|
!entry_key_lower.EndsWith(".gif") &&
|
||||||
!entry_key_lower.EndsWith(".jpeg"))
|
!entry_key_lower.EndsWith(".jpeg"))
|
||||||
{
|
{
|
||||||
@@ -149,7 +150,6 @@ namespace ComicCompressor
|
|||||||
}
|
}
|
||||||
|
|
||||||
ProcessReaderEntry(reader, entryStream, imageStreams, output, encoder);
|
ProcessReaderEntry(reader, entryStream, imageStreams, output, encoder);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -175,7 +175,7 @@ namespace ComicCompressor
|
|||||||
{
|
{
|
||||||
return ((value % (place * 10)) - (value % place)) / place;
|
return ((value % (place * 10)) - (value % place)) / place;
|
||||||
}
|
}
|
||||||
private (double, int) ProcessArchive(IArchive archive, string outputPath)
|
private (double, int) ProcessArchive(IArchive archive, string outputPath, string inputPath)
|
||||||
{
|
{
|
||||||
//var fileEntries = archive.Entries.Where(e => !e.IsDirectory);
|
//var fileEntries = archive.Entries.Where(e => !e.IsDirectory);
|
||||||
var fileEntries = archive.Entries.Where(e => !e.IsDirectory).OrderBy(e => e.Key);
|
var fileEntries = archive.Entries.Where(e => !e.IsDirectory).OrderBy(e => e.Key);
|
||||||
@@ -222,6 +222,17 @@ namespace ComicCompressor
|
|||||||
|
|
||||||
save = 100 * (double)output_length / (double)archive.TotalSize;
|
save = 100 * (double)output_length / (double)archive.TotalSize;
|
||||||
|
|
||||||
|
Program.file_stat fs = null;
|
||||||
|
Program.File_statistics.TryGetValue(inputPath,out fs);
|
||||||
|
if(fs != null)
|
||||||
|
{
|
||||||
|
fs.Uncompressed_file_len = archive.TotalSize;
|
||||||
|
fs.Compressed_file_len = output_length;
|
||||||
|
Program.File_statistics.TryAdd(inputPath, fs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (save, nop);
|
return (save, nop);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,11 +255,13 @@ namespace ComicCompressor
|
|||||||
{
|
{
|
||||||
return (false,true);
|
return (false,true);
|
||||||
}
|
}
|
||||||
|
|
||||||
string entry_key_lower = entry.Key.ToLower();
|
string entry_key_lower = entry.Key.ToLower();
|
||||||
|
bool isPPM = entry_key_lower.EndsWith(".ppm");
|
||||||
|
|
||||||
if (!entry_key_lower.EndsWith(".jpg") &&
|
if (!entry_key_lower.EndsWith(".jpg") &&
|
||||||
!entry_key_lower.EndsWith(".png") &&
|
!entry_key_lower.EndsWith(".png") &&
|
||||||
!entry_key_lower.EndsWith(".bmp") &&
|
!entry_key_lower.EndsWith(".bmp") &&
|
||||||
|
!entry_key_lower.EndsWith(".ppm") &&
|
||||||
!entry_key_lower.EndsWith(".gif") &&
|
!entry_key_lower.EndsWith(".gif") &&
|
||||||
!entry_key_lower.EndsWith(".jpeg"))
|
!entry_key_lower.EndsWith(".jpeg"))
|
||||||
{
|
{
|
||||||
@@ -260,7 +273,7 @@ namespace ComicCompressor
|
|||||||
return (false, true);
|
return (false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cover)
|
if (cover && !isPPM)
|
||||||
{
|
{
|
||||||
var ms = new MemoryStream();
|
var ms = new MemoryStream();
|
||||||
imageStreams.Add(ms);
|
imageStreams.Add(ms);
|
||||||
@@ -276,7 +289,18 @@ namespace ComicCompressor
|
|||||||
stream.CopyTo(raw_ms);
|
stream.CopyTo(raw_ms);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
bits = new Bitmap(raw_ms);
|
if(isPPM)
|
||||||
|
{
|
||||||
|
Logger.Log("P", LogLevel.Verbose, false, col: Color.PaleGreen);
|
||||||
|
PixelMap ppm = new PixelMap(raw_ms);
|
||||||
|
//bits = ppm.Bitmap;
|
||||||
|
bits = ppm.BitMap;
|
||||||
|
Logger.Log("\b", LogLevel.Verbose, false, col: Color.PaleGreen);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bits = new Bitmap(raw_ms);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|||||||
+536
@@ -0,0 +1,536 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Drawing.Imaging;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
//using Microsoft.Xna.Framework;
|
||||||
|
//using Microsoft.Xna.Framework.Graphics;
|
||||||
|
|
||||||
|
//using XnaColor = Microsoft.Xna.Framework.Graphics.Color;
|
||||||
|
//using XnaRectangle = Microsoft.Xna.Framework.Rectangle;
|
||||||
|
using SysColor = System.Drawing.Color;
|
||||||
|
using SysRectangle = System.Drawing.Rectangle;
|
||||||
|
|
||||||
|
namespace ComicCompressor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This class provides a managed C# abstraction for Portable Bit Map (.pbm), Portable Grey Map (.pgm) and
|
||||||
|
/// Portable Pixel Map (.ppm)images. The class is able to handle P1 (ASCII .pbm), P2 (ASCII .pgm) P3 (ASCII .ppm),
|
||||||
|
/// P5 (binary .pgm), and P6 (binary .ppm) files and streams. P4 (binary .pbm) is not supported. The class can
|
||||||
|
/// process normal images, which have widths that are multiples of 4 pixels wide, and can also handle "off-size"
|
||||||
|
/// images using a less efficient algorithm. It presents .pbm and .pgm images using the 8bppIndexed pixel format,
|
||||||
|
/// and presents .ppm images using the 24bppRGB pixel format. It can convert these images into a visually pleasing
|
||||||
|
/// greyscale bitmap image (in a less efficient 24bppRGB pixel format), which is accessible using the GreyMap
|
||||||
|
/// property.
|
||||||
|
///
|
||||||
|
/// To use this class:
|
||||||
|
/// 1. Copy the PixelMap.cs file into your own project.
|
||||||
|
/// 2. Change the namespace of the class (above this summary) from "PixelMap" to the namespace of your project.
|
||||||
|
/// 3. Compile.
|
||||||
|
///
|
||||||
|
/// This class is used by the PixelMapViewer application.
|
||||||
|
/// </summary>
|
||||||
|
public class PixelMap
|
||||||
|
{
|
||||||
|
private PixelMapHeader header;
|
||||||
|
/// <summary>
|
||||||
|
/// The header portion of the PixelMap.
|
||||||
|
/// </summary>
|
||||||
|
public PixelMapHeader Header
|
||||||
|
{
|
||||||
|
get { return header; }
|
||||||
|
set { header = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] imageData;
|
||||||
|
/// <summary>
|
||||||
|
/// The data portion of the PixelMap.
|
||||||
|
/// </summary>
|
||||||
|
public byte[] ImageData
|
||||||
|
{
|
||||||
|
get { return imageData; }
|
||||||
|
set { imageData = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private PixelFormat pixelFormat;
|
||||||
|
/// <summary>
|
||||||
|
/// The pixel format used by the BitMap generated by this PixelMap.
|
||||||
|
/// </summary>
|
||||||
|
public PixelFormat PixelFormat
|
||||||
|
{
|
||||||
|
get { return pixelFormat; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private int bytesPerPixel;
|
||||||
|
/// <summary>
|
||||||
|
/// The number of bytes per pixel.
|
||||||
|
/// </summary>
|
||||||
|
public int BytesPerPixel
|
||||||
|
{
|
||||||
|
get { return bytesPerPixel; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private int stride;
|
||||||
|
/// <summary>
|
||||||
|
/// The stride of the scan across the image. Typically this is width * bytesPerPixel, and is a multiple of 4.
|
||||||
|
/// </summary>
|
||||||
|
public int Stride
|
||||||
|
{
|
||||||
|
get { return stride; }
|
||||||
|
set { stride = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private Bitmap bitmap;
|
||||||
|
/// <summary>
|
||||||
|
/// The Bitmap created from the PixelMap.
|
||||||
|
/// </summary>
|
||||||
|
public Bitmap BitMap
|
||||||
|
{
|
||||||
|
get { return bitmap; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A 24bpp Grey map (really only 8bpp of information, since R,G,B bytes are identical) created from the PixelMap.
|
||||||
|
/// </summary>
|
||||||
|
public Bitmap GreyMap
|
||||||
|
{
|
||||||
|
get { return CreateGreyMap(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// File-based constructor.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filename">The name of the .pbm, .pbm, or .ppm file.</param>
|
||||||
|
public PixelMap(string filename)
|
||||||
|
{
|
||||||
|
if (File.Exists(filename))
|
||||||
|
{
|
||||||
|
FileStream stream = new FileStream(filename, FileMode.Open);
|
||||||
|
this.FromStream(stream);
|
||||||
|
stream.Close();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new FileNotFoundException("The file " + filename + " does not exist", filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stream-based constructor. Typically, the stream will be a FileStream, but it may also be a MemoryStream
|
||||||
|
/// or other object derived from the Stream class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">A stream containing the header and data portions of the .pbm, .pgm, or .ppm image.</param>
|
||||||
|
public PixelMap(Stream stream)
|
||||||
|
{
|
||||||
|
this.FromStream(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FromStream(Stream stream)
|
||||||
|
{
|
||||||
|
int index;
|
||||||
|
this.header = new PixelMapHeader();
|
||||||
|
int headerItemCount = 0;
|
||||||
|
stream.Position = 0;
|
||||||
|
BinaryReader binReader = new BinaryReader(stream, Encoding.ASCII);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//1. Read the Header.
|
||||||
|
while (headerItemCount < 4)
|
||||||
|
{
|
||||||
|
char nextChar = (char)binReader.PeekChar();
|
||||||
|
if (nextChar == '#') // comment
|
||||||
|
{
|
||||||
|
while (binReader.ReadChar() != '\n') ; // ignore the rest of the line.
|
||||||
|
}
|
||||||
|
else if (Char.IsWhiteSpace(nextChar)) // whitespace
|
||||||
|
{
|
||||||
|
binReader.ReadChar(); // ignore whitespace
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (headerItemCount)
|
||||||
|
{
|
||||||
|
case 0: // next item is Magic Number
|
||||||
|
// Read the first 2 characters and determine the type of pixelmap.
|
||||||
|
char[] chars = binReader.ReadChars(2);
|
||||||
|
this.header.MagicNumber = chars[0].ToString() + chars[1].ToString();
|
||||||
|
headerItemCount++;
|
||||||
|
break;
|
||||||
|
case 1: // next item is the width.
|
||||||
|
this.header.Width = ReadValue(binReader);
|
||||||
|
headerItemCount++;
|
||||||
|
break;
|
||||||
|
case 2: // next item is the height.
|
||||||
|
this.header.Height = ReadValue(binReader);
|
||||||
|
headerItemCount++;
|
||||||
|
break;
|
||||||
|
case 3: // next item is the depth.
|
||||||
|
if (this.header.MagicNumber == "P1" | this.header.MagicNumber == "P4")
|
||||||
|
{
|
||||||
|
// no depth value for PBM type.
|
||||||
|
headerItemCount++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.header.Depth = ReadValue(binReader);
|
||||||
|
headerItemCount++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception("Error parsing the file header.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Read the image data.
|
||||||
|
// 2.1 Size the imageData array to hold the image bytes.
|
||||||
|
switch (this.header.MagicNumber)
|
||||||
|
{
|
||||||
|
case "P1": // 1 byte per pixel
|
||||||
|
this.pixelFormat = PixelFormat.Format8bppIndexed;
|
||||||
|
this.bytesPerPixel = 1;
|
||||||
|
break;
|
||||||
|
case "P2": // 1 byte per pixel
|
||||||
|
this.pixelFormat = PixelFormat.Format8bppIndexed;
|
||||||
|
this.bytesPerPixel = 1;
|
||||||
|
break;
|
||||||
|
case "P3": // 3 bytes per pixel
|
||||||
|
this.pixelFormat = PixelFormat.Format24bppRgb;
|
||||||
|
this.bytesPerPixel = 3;
|
||||||
|
break;
|
||||||
|
case "P4":
|
||||||
|
throw new Exception("Binary .pbm (Magic Number P4) is not supported at this time.");
|
||||||
|
case "P5": // 1 byte per pixel
|
||||||
|
this.pixelFormat = PixelFormat.Format8bppIndexed;
|
||||||
|
this.bytesPerPixel = 1;
|
||||||
|
break;
|
||||||
|
case "P6": // 3 bytes per pixel
|
||||||
|
this.pixelFormat = PixelFormat.Format24bppRgb;
|
||||||
|
this.bytesPerPixel = 3;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception("Unknown Magic Number: " + this.header.MagicNumber);
|
||||||
|
}
|
||||||
|
this.imageData = new byte[this.header.Width * this.header.Height * this.bytesPerPixel];
|
||||||
|
this.stride = this.header.Width * this.bytesPerPixel;
|
||||||
|
//while ((this.stride % 4) != 0)
|
||||||
|
//{
|
||||||
|
// this.stride++;
|
||||||
|
//}
|
||||||
|
if (this.header.MagicNumber == "P1" | this.header.MagicNumber == "P2" | this.header.MagicNumber == "P3") // ASCII Encoding
|
||||||
|
{
|
||||||
|
int charsLeft = (int)(binReader.BaseStream.Length - binReader.BaseStream.Position);
|
||||||
|
char[] charData = binReader.ReadChars(charsLeft); // read all the data into an array in one go, for efficiency.
|
||||||
|
string valueString = string.Empty;
|
||||||
|
index = 0;
|
||||||
|
for (int i = 0; i < charData.Length; i++)
|
||||||
|
{
|
||||||
|
if (Char.IsWhiteSpace(charData[i])) // value is ignored if empty, or converted to byte and added to array otherwise.
|
||||||
|
{
|
||||||
|
if (valueString != string.Empty)
|
||||||
|
{
|
||||||
|
this.imageData[index] = (byte)int.Parse(valueString);
|
||||||
|
valueString = string.Empty;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // add the character to the end of the valueString.
|
||||||
|
{
|
||||||
|
valueString += charData[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // binary encoding.
|
||||||
|
{
|
||||||
|
int bytesLeft = (int)(binReader.BaseStream.Length - binReader.BaseStream.Position);
|
||||||
|
this.imageData = binReader.ReadBytes(bytesLeft);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. We need to change the byte order of this.imageData from BGR to RGB.
|
||||||
|
ReorderBGRtoRGB();
|
||||||
|
|
||||||
|
// 4. Create the BitMap
|
||||||
|
if (this.stride % 4 == 0)
|
||||||
|
{
|
||||||
|
this.bitmap = CreateBitMap();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.bitmap = CreateBitmapOffSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. Rotate the BitMap by 180 degrees so it is in the same orientation as the original image.
|
||||||
|
this.bitmap.RotateFlip(RotateFlipType.Rotate180FlipNone);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the end of the stream is reached before reading all of the expected values raise an exception.
|
||||||
|
catch (EndOfStreamException e)
|
||||||
|
{
|
||||||
|
Console.WriteLine(e.Message);
|
||||||
|
throw new Exception("Error reading the stream! ", e);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine(ex.Message);
|
||||||
|
throw new Exception("Error reading the stream! ", ex);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
binReader.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// As it stands, the native byte order in .pbm, .pgm, and .ppm images is BGR. We need to reverse the order
|
||||||
|
/// into RGB as this is what is needed for 24bppRGB bitmap pixel format on Windows.
|
||||||
|
/// </summary>
|
||||||
|
private void ReorderBGRtoRGB()
|
||||||
|
{
|
||||||
|
byte[] tempData = new byte[this.imageData.Length];
|
||||||
|
for (int i = 0; i < this.imageData.Length; i++)
|
||||||
|
{
|
||||||
|
tempData[i] = this.imageData[this.imageData.Length - 1 - i];
|
||||||
|
}
|
||||||
|
this.imageData = tempData;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int ReadValue(BinaryReader binReader)
|
||||||
|
{
|
||||||
|
string value = string.Empty;
|
||||||
|
while (!Char.IsWhiteSpace((char)binReader.PeekChar()))
|
||||||
|
{
|
||||||
|
value += binReader.ReadChar().ToString();
|
||||||
|
}
|
||||||
|
binReader.ReadByte(); // get rid of the whitespace.
|
||||||
|
return int.Parse(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Bitmap CreateBitMap()
|
||||||
|
{
|
||||||
|
IntPtr pImageData = Marshal.AllocHGlobal(this.imageData.Length);
|
||||||
|
Marshal.Copy(this.imageData, 0, pImageData, this.imageData.Length);
|
||||||
|
Bitmap bitmap = new Bitmap(this.header.Width, this.header.Height, this.stride, this.pixelFormat, pImageData);
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Bitmap CreateGreyMap()
|
||||||
|
{
|
||||||
|
byte[] greyData = new byte[this.header.Width * this.header.Height * 3];
|
||||||
|
int stride = this.header.Width * 3;
|
||||||
|
//while (stride % 4 != 0)
|
||||||
|
//{
|
||||||
|
// stride++;
|
||||||
|
//}
|
||||||
|
if (stride % 4 != 0)
|
||||||
|
{
|
||||||
|
return CreateGreyMapOffSize(greyData);
|
||||||
|
}
|
||||||
|
byte grey;
|
||||||
|
switch (this.pixelFormat)
|
||||||
|
{
|
||||||
|
case PixelFormat.Format24bppRgb:
|
||||||
|
int red, green, blue;
|
||||||
|
for (int i = 0; i < this.imageData.Length; i = i + 3)
|
||||||
|
{
|
||||||
|
red = (int)this.imageData[i];
|
||||||
|
green = (int)this.imageData[i + 1];
|
||||||
|
blue = (int)this.imageData[i + 2];
|
||||||
|
grey = (byte)((red + green + blue) / 3);
|
||||||
|
greyData[i] = grey;
|
||||||
|
greyData[i + 1] = grey;
|
||||||
|
greyData[i + 2] = grey;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PixelFormat.Format8bppIndexed:
|
||||||
|
int index = 0;
|
||||||
|
for (int i = 0; i < this.imageData.Length; i++)
|
||||||
|
{
|
||||||
|
index = 3 * i;
|
||||||
|
grey = this.imageData[i];
|
||||||
|
if (this.header.MagicNumber == "P1")
|
||||||
|
{
|
||||||
|
if ((int)grey == 1)
|
||||||
|
{
|
||||||
|
grey = (byte)255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
greyData[index] = grey;
|
||||||
|
greyData[index + 1] = grey;
|
||||||
|
greyData[index + 2] = grey;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception("Unsupported Pixel Format: " + this.pixelFormat.ToString());
|
||||||
|
}
|
||||||
|
IntPtr pGreyData = Marshal.AllocHGlobal(greyData.Length);
|
||||||
|
Marshal.Copy(greyData, 0, pGreyData, greyData.Length);
|
||||||
|
Bitmap bitmap = new Bitmap(this.header.Width, this.header.Height, stride, PixelFormat.Format24bppRgb, pGreyData);
|
||||||
|
bitmap.RotateFlip(RotateFlipType.Rotate180FlipNone);
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This method is able to handle the process of creating Bitmaps that are not sized in widths that are multiples
|
||||||
|
/// of 4 pixels (which is needed for the rapid drawing using the Marshal class.) Unfortunately, this is a very slow
|
||||||
|
/// method, since it uses SetPixel().
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
private Bitmap CreateBitmapOffSize()
|
||||||
|
{
|
||||||
|
Bitmap bitmap = new Bitmap(this.header.Width, this.header.Height, PixelFormat.Format24bppRgb);
|
||||||
|
SysColor sysColor = new SysColor();
|
||||||
|
int red, green, blue, grey;
|
||||||
|
int index;
|
||||||
|
|
||||||
|
for (int x = 0; x < this.header.Width; x++)
|
||||||
|
{
|
||||||
|
for (int y = 0; y < this.header.Height; y++)
|
||||||
|
{
|
||||||
|
index = x + y * this.header.Width;
|
||||||
|
|
||||||
|
switch (this.header.MagicNumber)
|
||||||
|
{
|
||||||
|
case "P1":
|
||||||
|
grey = (int)this.imageData[index];
|
||||||
|
if (grey == 1)
|
||||||
|
{
|
||||||
|
grey = 255;
|
||||||
|
}
|
||||||
|
sysColor = SysColor.FromArgb(grey, grey, grey);
|
||||||
|
break;
|
||||||
|
case "P2":
|
||||||
|
grey = (int)this.imageData[index];
|
||||||
|
sysColor = SysColor.FromArgb(grey, grey, grey);
|
||||||
|
break;
|
||||||
|
case "P3":
|
||||||
|
index = 3 * index;
|
||||||
|
blue = (int)this.imageData[index];
|
||||||
|
green = (int)this.imageData[index + 1];
|
||||||
|
red = (int)this.imageData[index + 2];
|
||||||
|
sysColor = SysColor.FromArgb(red, green, blue);
|
||||||
|
break;
|
||||||
|
case "P4":
|
||||||
|
break;
|
||||||
|
case "P5":
|
||||||
|
grey = (int)this.imageData[index];
|
||||||
|
sysColor = SysColor.FromArgb(grey, grey, grey);
|
||||||
|
break;
|
||||||
|
case "P6":
|
||||||
|
index = 3 * index;
|
||||||
|
blue = (int)this.imageData[index];
|
||||||
|
green = (int)this.imageData[index + 1];
|
||||||
|
red = (int)this.imageData[index + 2];
|
||||||
|
sysColor = SysColor.FromArgb(red, green, blue);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bitmap.SetPixel(x, y, sysColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Bitmap CreateGreyMapOffSize(byte[] greyData)
|
||||||
|
{
|
||||||
|
Bitmap bitmap = new Bitmap(this.header.Width, this.header.Height, PixelFormat.Format24bppRgb);
|
||||||
|
SysColor sysColor = new SysColor();
|
||||||
|
int index = 0;
|
||||||
|
int x = 0;
|
||||||
|
int y = -1;
|
||||||
|
switch (this.pixelFormat)
|
||||||
|
{
|
||||||
|
case PixelFormat.Format24bppRgb:
|
||||||
|
int red, green, blue, grey;
|
||||||
|
for (int i = 0; i < this.imageData.Length; i = i + 3)
|
||||||
|
{
|
||||||
|
index = i / 3; // the current pixel
|
||||||
|
if (index%this.header.Width == 0) y++; // the current row = y;
|
||||||
|
x = index - y * this.header.Width; // the current column = x;
|
||||||
|
red = (int)this.imageData[i];
|
||||||
|
green = (int)this.imageData[i + 1];
|
||||||
|
blue = (int)this.imageData[i + 2];
|
||||||
|
grey = (byte)((red + green + blue) / 3);
|
||||||
|
sysColor = SysColor.FromArgb(grey, grey, grey);
|
||||||
|
bitmap.SetPixel(x, y, sysColor);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PixelFormat.Format8bppIndexed:
|
||||||
|
for (int i = 0; i < this.imageData.Length; i++)
|
||||||
|
{
|
||||||
|
index = i; // the current pixel
|
||||||
|
if (index % this.header.Width == 0) y++; // the current row = y;
|
||||||
|
x = index - y * this.header.Width; // the current column = x;
|
||||||
|
|
||||||
|
grey = this.imageData[i];
|
||||||
|
if (this.header.MagicNumber == "P1")
|
||||||
|
{
|
||||||
|
if ((int)grey == 1)
|
||||||
|
{
|
||||||
|
grey = (byte)255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sysColor = SysColor.FromArgb(grey, grey, grey);
|
||||||
|
bitmap.SetPixel(x, y, sysColor);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception("Unsupported Pixel Format: " + this.pixelFormat.ToString());
|
||||||
|
}
|
||||||
|
bitmap.RotateFlip(RotateFlipType.Rotate180FlipNone);
|
||||||
|
return bitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This struct contains the objects that are found in the header of .pbm, .pgm, and .ppm files.
|
||||||
|
/// </summary>
|
||||||
|
[Serializable]
|
||||||
|
public struct PixelMapHeader
|
||||||
|
{
|
||||||
|
private string magicNumber;
|
||||||
|
/// <summary>
|
||||||
|
/// The "Magic Number" that identifies the type of Pixelmap. P1 = PBM (ASCII); P2 = PGM (ASCII); P3 = PPM (ASCII); P4 is not used;
|
||||||
|
/// P5 = PGM (Binary); P6 = PPM (Binary).
|
||||||
|
/// </summary>
|
||||||
|
public string MagicNumber
|
||||||
|
{
|
||||||
|
get { return magicNumber; }
|
||||||
|
set { magicNumber = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private int width;
|
||||||
|
/// <summary>
|
||||||
|
/// The width of the image.
|
||||||
|
/// </summary>
|
||||||
|
public int Width
|
||||||
|
{
|
||||||
|
get { return width; }
|
||||||
|
set { width = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private int height;
|
||||||
|
/// <summary>
|
||||||
|
/// The height of the image.
|
||||||
|
/// </summary>
|
||||||
|
public int Height
|
||||||
|
{
|
||||||
|
get { return height; }
|
||||||
|
set { height = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private int depth;
|
||||||
|
/// <summary>
|
||||||
|
/// The depth (maximum color value in each channel) of the image. This allows the format to represent
|
||||||
|
/// more than a single byte (0-255) for each color channel.
|
||||||
|
/// </summary>
|
||||||
|
public int Depth
|
||||||
|
{
|
||||||
|
get { return depth; }
|
||||||
|
set { depth = value; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+222
-14
@@ -25,6 +25,10 @@ using org.omg.PortableInterceptor;
|
|||||||
using org.apache.pdfbox.util.@operator;
|
using org.apache.pdfbox.util.@operator;
|
||||||
using java.nio;
|
using java.nio;
|
||||||
using ImageMagick;
|
using ImageMagick;
|
||||||
|
using javax.xml.transform;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using iText.Barcodes.Dmcode;
|
||||||
|
using ZstdSharp;
|
||||||
|
|
||||||
namespace ComicCompressor
|
namespace ComicCompressor
|
||||||
{
|
{
|
||||||
@@ -32,6 +36,7 @@ namespace ComicCompressor
|
|||||||
{
|
{
|
||||||
public static int Main(string[] args) => CommandLineApplication.Execute<Program>(args);
|
public static int Main(string[] args) => CommandLineApplication.Execute<Program>(args);
|
||||||
|
|
||||||
|
#region INPUT_FLAGS
|
||||||
[FileOrDirectoryExists]
|
[FileOrDirectoryExists]
|
||||||
[Option("-i|--input <FOLDER/FIlE>", Description = "The file or folder to convert")]
|
[Option("-i|--input <FOLDER/FIlE>", Description = "The file or folder to convert")]
|
||||||
[Required]
|
[Required]
|
||||||
@@ -63,15 +68,50 @@ namespace ComicCompressor
|
|||||||
|
|
||||||
[Option("-j|--image", Description = "process images only")]
|
[Option("-j|--image", Description = "process images only")]
|
||||||
public bool DoImage { get; } = false;
|
public bool DoImage { get; } = false;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region STATISTICS
|
||||||
|
|
||||||
|
public class file_stat
|
||||||
|
{
|
||||||
|
public string Filename { get; set; }
|
||||||
|
public file_stat(string filename) {
|
||||||
|
Filename = filename;
|
||||||
|
}
|
||||||
|
public long Uncompressed_file_len { get; set; }
|
||||||
|
public long Compressed_file_len { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
private Logger Logger { get; set; }
|
private Logger Logger { get; set; }
|
||||||
|
|
||||||
SimpleEncoder encoder = new SimpleEncoder();
|
SimpleEncoder encoder = new SimpleEncoder();
|
||||||
private List<Stream> imageStreams = null;
|
private List<Stream> imageStreams = null;
|
||||||
public ZipArchive output = null;
|
public ZipArchive output = null;
|
||||||
|
|
||||||
|
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;
|
||||||
private void OnExecute()
|
private void OnExecute()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
File_statistics.Clear();
|
||||||
|
|
||||||
|
myColors = new Color[names.Count()];
|
||||||
|
for(int i = 0; i< myColors.Length; i++)
|
||||||
|
{
|
||||||
|
KnownColor randomColorName = names[randomGen.Next(names.Length)];
|
||||||
|
myColors[i] = Color.FromKnownColor(randomColorName);
|
||||||
|
}
|
||||||
//ImageExtractor7.MainBox();
|
//ImageExtractor7.MainBox();
|
||||||
|
|
||||||
Stopwatch sw = Stopwatch.StartNew();
|
Stopwatch sw = Stopwatch.StartNew();
|
||||||
@@ -99,6 +139,7 @@ namespace ComicCompressor
|
|||||||
|
|
||||||
foreach (var file in files)
|
foreach (var file in files)
|
||||||
{
|
{
|
||||||
|
File_statistics.Add(file, new file_stat(file));
|
||||||
if(file.Length > filename_len)
|
if(file.Length > filename_len)
|
||||||
filename_len = file.Length;
|
filename_len = file.Length;
|
||||||
}
|
}
|
||||||
@@ -115,6 +156,25 @@ namespace ComicCompressor
|
|||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,37 +182,107 @@ namespace ComicCompressor
|
|||||||
{
|
{
|
||||||
MaxDegreeOfParallelism = (NumOfCpu > Environment.ProcessorCount) ? Environment.ProcessorCount : NumOfCpu
|
MaxDegreeOfParallelism = (NumOfCpu > Environment.ProcessorCount) ? Environment.ProcessorCount : NumOfCpu
|
||||||
};
|
};
|
||||||
|
#if true
|
||||||
|
ParallelQuery<string> source = Partitioner.Create(files)
|
||||||
|
.AsParallel()
|
||||||
|
.AsOrdered();
|
||||||
|
|
||||||
Parallel.ForEach(files, options, file => CompressTask(compressor, file, filename_len, true));
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CompressTask(Compressor compressor, string filename, int max_name_len = -1, Boolean isPar = false)
|
private void CompressTask(Compressor compressor, string filename, int max_name_len = -1, Boolean isPar = false, ParallelLoopState state = null, long index = 0, long total = 0)
|
||||||
{
|
{
|
||||||
var relativePath = Path.GetRelativePath(Input, filename);
|
var relativePath = Path.GetRelativePath(Input, filename);
|
||||||
var outputPath = Path.Join(OutputFolder, Path.ChangeExtension(relativePath, "cbz"));
|
var outputPath = Path.Join(OutputFolder, Path.ChangeExtension(relativePath, "cbz"));
|
||||||
var outputPath_webp = Path.Join(OutputFolder, Path.ChangeExtension(relativePath, "webp"));
|
var outputPath_webp = Path.Join(OutputFolder, Path.ChangeExtension(relativePath, "webp"));
|
||||||
|
int digits = 1+(int)Math.Floor(Math.Log((Double)total) / Math.Log(10.0));
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
if (File.Exists(outputPath) && Skip)
|
if (File.Exists(outputPath) && Skip)
|
||||||
{
|
{
|
||||||
|
long lengthin = new System.IO.FileInfo(filename).Length;
|
||||||
|
long lengthout = new System.IO.FileInfo(outputPath).Length;
|
||||||
|
Program.file_stat fs = null;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Logger.Log(outputPath, LogLevel.Verbose, true, Color.Yellow);
|
Logger.Log(outputPath, LogLevel.Verbose, true, Color.Yellow);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (DoImage && Skip && File.Exists(outputPath_webp))
|
if (DoImage && Skip && File.Exists(outputPath_webp))
|
||||||
{
|
{
|
||||||
|
long lengthin = new System.IO.FileInfo(filename).Length;
|
||||||
|
long lengthout = new System.IO.FileInfo(outputPath).Length;
|
||||||
|
Program.file_stat fs = null;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
Logger.Log(outputPath_webp, LogLevel.Verbose, true, Color.Yellow);
|
Logger.Log(outputPath_webp, LogLevel.Verbose, true, Color.Yellow);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DoPdf && filename.ToLower().EndsWith(".pdf"))
|
if (DoPdf && filename.ToLower().EndsWith(".pdf"))
|
||||||
{
|
{
|
||||||
ExtractImageFromPDF(filename, outputPath);
|
|
||||||
|
ExtractImageFromPDF(compressor,filename, outputPath);
|
||||||
|
|
||||||
|
long lengthin = new System.IO.FileInfo(filename).Length;
|
||||||
|
long lengthout = new System.IO.FileInfo(outputPath).Length;
|
||||||
|
Program.file_stat fs = null;
|
||||||
|
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);
|
||||||
|
}
|
||||||
//compressor.CompressPdf(filename, outputPath);
|
//compressor.CompressPdf(filename, outputPath);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DoPdf)
|
//if (DoPdf)
|
||||||
return;
|
// return;
|
||||||
|
|
||||||
if (DoImage &&
|
if (DoImage &&
|
||||||
filename.ToLower().EndsWith("jpg") ||
|
filename.ToLower().EndsWith("jpg") ||
|
||||||
@@ -161,7 +291,18 @@ namespace ComicCompressor
|
|||||||
filename.ToLower().EndsWith("png"))
|
filename.ToLower().EndsWith("png"))
|
||||||
{
|
{
|
||||||
outputPath = Path.Join(OutputFolder, Path.ChangeExtension(relativePath, "webp"));
|
outputPath = Path.Join(OutputFolder, Path.ChangeExtension(relativePath, "webp"));
|
||||||
CompressImage(filename, outputPath, max_name_len,isPar);
|
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;
|
||||||
|
Program.file_stat fs = null;
|
||||||
|
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);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,7 +429,7 @@ namespace ComicCompressor
|
|||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
#else
|
#elif false
|
||||||
public int GetPlace(int value, int place)
|
public int GetPlace(int value, int place)
|
||||||
{
|
{
|
||||||
return ((value % (place * 10)) - (value % place)) / place;
|
return ((value % (place * 10)) - (value % place)) / place;
|
||||||
@@ -437,18 +578,64 @@ namespace ComicCompressor
|
|||||||
|
|
||||||
//Logger.Log(sw.ElapsedMilliseconds.ToString(), LogLevel.Verbose);
|
//Logger.Log(sw.ElapsedMilliseconds.ToString(), LogLevel.Verbose);
|
||||||
}
|
}
|
||||||
|
#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);
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region COMPRESS_IMAGE
|
#region COMPRESS_IMAGE
|
||||||
public void CompressImage(string imagefile, string outputFolder, int max_name_len = -1, Boolean isPar = false)
|
public void CompressImage(string imagefile, string outputFolder, int max_name_len = -1, Boolean isPar = false, string print_line_header = "")
|
||||||
{
|
{
|
||||||
string name_print = imagefile;
|
string name_print = imagefile;
|
||||||
if(max_name_len > 0)
|
if(max_name_len > 0)
|
||||||
name_print = imagefile.PadRight(max_name_len);
|
name_print = imagefile.PadRight(max_name_len);
|
||||||
if(!isPar)
|
if(!isPar)
|
||||||
Logger.Log(name_print, LogLevel.Verbose, false, col:Color.LightBlue);
|
Logger.Log(print_line_header+name_print, LogLevel.Verbose, false, col:Color.LightBlue);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -482,13 +669,34 @@ namespace ComicCompressor
|
|||||||
FileInfo finfo = new FileInfo(outputFolder);
|
FileInfo finfo = new FileInfo(outputFolder);
|
||||||
long length_out = finfo.Length;
|
long length_out = finfo.Length;
|
||||||
if (isPar)
|
if (isPar)
|
||||||
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);
|
{
|
||||||
|
#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
|
||||||
|
}
|
||||||
else
|
else
|
||||||
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);
|
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);
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
catch(Exception e)
|
||||||
{
|
{
|
||||||
Logger.LogError(e, col: Color.Red);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -548,6 +756,6 @@ namespace ComicCompressor
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
},
|
},
|
||||||
"ComicCompress PDF": {
|
"ComicCompress PDF": {
|
||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
"commandLineArgs": "-i _PDF_ -o _NEW_PDF_ -r -s "
|
"commandLineArgs": "-i _PDF_ -o _NEW_PDF_ -r -s -d"
|
||||||
},
|
},
|
||||||
"Compress Image to webp": {
|
"Compress Image to webp": {
|
||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
@@ -15,6 +15,10 @@
|
|||||||
"Compress Image to WEBP PAR": {
|
"Compress Image to WEBP PAR": {
|
||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
"commandLineArgs": "-i _IMG_ -o _IMG_WEBP_ -r -s -j -p -c 4"
|
"commandLineArgs": "-i _IMG_ -o _IMG_WEBP_ -r -s -j -p -c 4"
|
||||||
|
},
|
||||||
|
"ComicCompress": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"commandLineArgs": "-i _IMG_ -o _IMG_WEBP_ -r -s "
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user