using Docnet.Core; using Docnet.Core.Models; Console.WriteLine("=== PDF til Billede Konverter ==="); Console.WriteLine(); Console.Write("Indtast sti til PDF-fil: "); string? pdfPath = Console.ReadLine()?.Trim().Trim('"'); if (string.IsNullOrEmpty(pdfPath)) { Console.WriteLine("Fejl: Ingen fil angivet."); Console.ReadKey(); return; } if (!File.Exists(pdfPath)) { Console.WriteLine($"Fejl: Filen '{pdfPath}' blev ikke fundet."); Console.ReadKey(); return; } Console.Write("Indtast output-mappe (tryk Enter for samme mappe som PDF): "); string? outputInput = Console.ReadLine()?.Trim().Trim('"'); string outputFolder = string.IsNullOrEmpty(outputInput) ? Path.GetDirectoryName(pdfPath) ?? "." : outputInput; Directory.CreateDirectory(outputFolder); string fileNameWithoutExt = Path.GetFileNameWithoutExtension(pdfPath); Console.WriteLine($"Konverterer: {pdfPath}"); using var docReader = DocLib.Instance.GetDocReader(pdfPath, new PageDimensions(1080, 1920)); int pageCount = docReader.GetPageCount(); Console.WriteLine($"Antal sider: {pageCount}"); for (int i = 0; i < pageCount; i++) { using var pageReader = docReader.GetPageReader(i); int width = pageReader.GetPageWidth(); int height = pageReader.GetPageHeight(); byte[] rawBytes = pageReader.GetImage(); string outputPath = Path.Combine(outputFolder, $"{fileNameWithoutExt}_side_{i + 1}.png"); SaveAsPng(rawBytes, width, height, outputPath); Console.WriteLine($"Gemt: {outputPath}"); } Console.WriteLine("Konvertering fuldført!"); Console.WriteLine(); Console.WriteLine("Tryk på en tast for at afslutte..."); Console.ReadKey(); static void SaveAsPng(byte[] bgraData, int width, int height, string outputPath) { using var fileStream = File.Create(outputPath); using var bw = new BinaryWriter(fileStream); // PNG Signature bw.Write(new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }); // IHDR chunk byte[] ihdrData; using (var ms = new MemoryStream()) { WriteBigEndianInt(ms, width); WriteBigEndianInt(ms, height); ms.WriteByte(8); // bit depth ms.WriteByte(6); // color type (RGBA) ms.WriteByte(0); // compression ms.WriteByte(0); // filter ms.WriteByte(0); // interlace ihdrData = ms.ToArray(); } WriteChunk(bw, "IHDR", ihdrData); // Byg uncompressed data (filter-byte + RGBA pixels per scanline) int scanlineSize = 1 + width * 4; // 1 filter byte + RGBA byte[] uncompressed = new byte[height * scanlineSize]; for (int y = 0; y < height; y++) { int rowStart = y * scanlineSize; uncompressed[rowStart] = 0; // filter type: none for (int x = 0; x < width; x++) { int srcIdx = (y * width + x) * 4; int dstIdx = rowStart + 1 + x * 4; // BGRA til RGBA uncompressed[dstIdx + 0] = bgraData[srcIdx + 2]; // R uncompressed[dstIdx + 1] = bgraData[srcIdx + 1]; // G uncompressed[dstIdx + 2] = bgraData[srcIdx + 0]; // B uncompressed[dstIdx + 3] = bgraData[srcIdx + 3]; // A } } // Komprimer med Deflate using var compressedStream = new MemoryStream(); using (var deflate = new System.IO.Compression.DeflateStream(compressedStream, System.IO.Compression.CompressionLevel.Fastest, true)) { deflate.Write(uncompressed); } byte[] compressed = compressedStream.ToArray(); // Beregn Adler-32 på uncompressed data uint adler = Adler32(uncompressed); // Byg zlib stream: header + compressed + adler32 using var zlibStream = new MemoryStream(); zlibStream.WriteByte(0x78); // CMF zlibStream.WriteByte(0x01); // FLG zlibStream.Write(compressed); WriteBigEndianUInt(zlibStream, adler); WriteChunk(bw, "IDAT", zlibStream.ToArray()); // IEND chunk WriteChunk(bw, "IEND", Array.Empty()); } static void WriteChunk(BinaryWriter bw, string type, byte[] data) { byte[] lengthBytes = BitConverter.GetBytes(data.Length); if (BitConverter.IsLittleEndian) Array.Reverse(lengthBytes); bw.Write(lengthBytes); byte[] typeBytes = System.Text.Encoding.ASCII.GetBytes(type); bw.Write(typeBytes); bw.Write(data); // CRC32 byte[] crcData = new byte[4 + data.Length]; Array.Copy(typeBytes, crcData, 4); Array.Copy(data, 0, crcData, 4, data.Length); uint crc = Crc32(crcData); byte[] crcBytes = BitConverter.GetBytes(crc); if (BitConverter.IsLittleEndian) Array.Reverse(crcBytes); bw.Write(crcBytes); } static void WriteBigEndianInt(Stream stream, int value) { byte[] bytes = BitConverter.GetBytes(value); if (BitConverter.IsLittleEndian) Array.Reverse(bytes); stream.Write(bytes); } static void WriteBigEndianUInt(Stream stream, uint value) { byte[] bytes = BitConverter.GetBytes(value); if (BitConverter.IsLittleEndian) Array.Reverse(bytes); stream.Write(bytes); } static uint Crc32(byte[] data) { uint crc = 0xFFFFFFFF; foreach (byte b in data) { crc ^= b; for (int i = 0; i < 8; i++) crc = (crc >> 1) ^ (0xEDB88320 & ~((crc & 1) - 1)); } return ~crc; } static uint Adler32(byte[] data) { uint a = 1, b = 0; foreach (byte d in data) { a = (a + d) % 65521; b = (b + a) % 65521; } return (b << 16) | a; }