Adds basic POC for PDFToImage

This commit is contained in:
Janus C. H. Knudsen 2026-02-05 16:24:54 +01:00
parent 3aeae6315b
commit 4f6337de6b
3 changed files with 223 additions and 0 deletions

24
POC/PdfToImage.sln Normal file
View file

@ -0,0 +1,24 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.2.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PdfToImage", "PdfToImage\PdfToImage.csproj", "{515835BA-A8E0-C3F6-57E3-24410428E129}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{515835BA-A8E0-C3F6-57E3-24410428E129}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{515835BA-A8E0-C3F6-57E3-24410428E129}.Debug|Any CPU.Build.0 = Debug|Any CPU
{515835BA-A8E0-C3F6-57E3-24410428E129}.Release|Any CPU.ActiveCfg = Release|Any CPU
{515835BA-A8E0-C3F6-57E3-24410428E129}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {2F6D3A0F-356F-483E-863D-C672AEE8323E}
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Docnet.Core" Version="2.6.0" />
</ItemGroup>
</Project>

185
POC/PdfToImage/Program.cs Normal file
View file

@ -0,0 +1,185 @@
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<byte>());
}
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;
}