Skip to content

Commit

Permalink
Fixed issue with raster images begin reported as having the wrong res…
Browse files Browse the repository at this point in the history
…olution.
  • Loading branch information
arklumpus committed Jan 18, 2021
1 parent aea60b4 commit 4b85820
Show file tree
Hide file tree
Showing 11 changed files with 320 additions and 28 deletions.
2 changes: 1 addition & 1 deletion Demo/Demo.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="MuPDFCore" Version="1.2.0" />
<PackageReference Include="MuPDFCore" Version="1.2.2" />
</ItemGroup>

<ItemGroup>
Expand Down
4 changes: 2 additions & 2 deletions MuPDFCore.MuPDFRenderer/MuPDFCore.MuPDFRenderer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<PackageLicenseExpression>AGPL-3.0-only</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/arklumpus/MuPDFCore</PackageProjectUrl>
<RepositoryUrl>https://github.com/arklumpus/MuPDFCore</RepositoryUrl>
<Version>1.2.0-rc1</Version>
<Version>1.2.2-rc1</Version>
<PackageIcon>icon.png</PackageIcon>
</PropertyGroup>

Expand All @@ -23,7 +23,7 @@

<ItemGroup>
<PackageReference Include="Avalonia" Version="0.10.0-rc1" />
<PackageReference Include="MuPDFCore" Version="1.2.0" />
<PackageReference Include="MuPDFCore" Version="1.2.2" />
</ItemGroup>

</Project>
10 changes: 8 additions & 2 deletions MuPDFCore/MuPDF.cs
Original file line number Diff line number Diff line change
Expand Up @@ -448,23 +448,29 @@ internal static class NativeMethods
/// <param name="data">A pointer to a byte array containing the data that makes up the document.</param>
/// <param name="data_length">The length in bytes of the data that makes up the document.</param>
/// <param name="file_type">The type (extension) of the document.</param>
/// <param name="get_image_resolution">If this is not 0, try opening the stream as an image and return the actual resolution (in DPI) of the image. Otherwise (or if trying to open the stream as an image fails), the returned resolution will be -1.</param>
/// <param name="out_doc">The newly created document.</param>
/// <param name="out_str">The newly created stream (so that it can be disposed later).</param>
/// <param name="out_page_count">The number of pages in the document.</param>
/// <param name="out_image_xres">If the document is an image file, the horizontal resolution of the image.</param>
/// <param name="out_image_yres">If the document is an image file, the vertical resolution of the image.</param>
/// <returns>An integer equivalent to <see cref="ExitCodes"/> detailing whether any errors occurred.</returns>
[DllImport("MuPDFWrapper", CallingConvention = CallingConvention.Cdecl)]
internal static extern int CreateDocumentFromStream(IntPtr ctx, IntPtr data, ulong data_length, string file_type, ref IntPtr out_doc, ref IntPtr out_str, ref int out_page_count);
internal static extern int CreateDocumentFromStream(IntPtr ctx, IntPtr data, ulong data_length, string file_type, int get_image_resolution, ref IntPtr out_doc, ref IntPtr out_str, ref int out_page_count, ref float out_image_xres, ref float out_image_yres);

/// <summary>
/// Create a new document from a file name.
/// </summary>
/// <param name="ctx">The context to which the document will belong.</param>
/// <param name="file_name">The path of the file to open.</param>
/// <param name="get_image_resolution">If this is not 0, try opening the file as an image and return the actual resolution (in DPI) of the image. Otherwise (or if trying to open the file as an image fails), the returned resolution will be -1.</param>
/// <param name="out_doc">The newly created document.</param>
/// <param name="out_page_count">The number of pages in the document.</param>
/// <returns>An integer equivalent to <see cref="ExitCodes"/> detailing whether any errors occurred.</returns>
/// <param name="out_image_xres">If the document is an image file, the horizontal resolution of the image.</param>
/// <param name="out_image_yres">If the document is an image file, the vertical resolution of the image.</param>
[DllImport("MuPDFWrapper", CallingConvention = CallingConvention.Cdecl)]
internal static extern int CreateDocumentFromFile(IntPtr ctx, string file_name, ref IntPtr out_doc, ref int out_page_count);
internal static extern int CreateDocumentFromFile(IntPtr ctx, string file_name, int get_image_resolution, ref IntPtr out_doc, ref int out_page_count, ref float out_image_xres, ref float out_image_yres);

/// <summary>
/// Free a stream and its associated resources.
Expand Down
2 changes: 1 addition & 1 deletion MuPDFCore/MuPDFCore.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Description>MuPDFCore is a set of multiplatform .NET Core bindings for MuPDF. It can render PDF, XPS, EPUB and other formats to raster images returned either as raw bytes, or as image files in multiple formats (including PNG and PSD). It also supports multithreading.</Description>
<Version>1.2.1</Version>
<Version>1.2.2</Version>
<PackageIcon>icon.png</PackageIcon>
<Authors>Giorgio Bianchini</Authors>
<Company>University of Bristol</Company>
Expand Down
2 changes: 1 addition & 1 deletion MuPDFCore/MuPDFDisplayList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public MuPDFDisplayList(MuPDFContext context, MuPDFPage page, bool includeAnnota
throw new MuPDFException("Unknown error", result);
}

this.Bounds = new Rectangle(x0, y0, x1, y1);
this.Bounds = new Rectangle(Math.Round(x0 * page.OwnerDocument.ImageXRes / 72.0 * 1000) / 1000, Math.Round(y0 * page.OwnerDocument.ImageYRes / 72.0 * 1000) / 1000, Math.Round(x1 * page.OwnerDocument.ImageXRes / 72.0 * 1000) / 1000, Math.Round(y1 * page.OwnerDocument.ImageYRes / 72.0 * 1000) / 1000);
}

private bool disposedValue;
Expand Down
176 changes: 170 additions & 6 deletions MuPDFCore/MuPDFDocument.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,16 @@ namespace MuPDFCore
/// </summary>
public class MuPDFDocument : IDisposable
{
/// <summary>
/// If the document is an image, the horizontal resolution of the image. Otherwise, 72.
/// </summary>
internal double ImageXRes = double.NaN;

/// <summary>
/// If the document is an image, the vertical resolution of the image. Otherwise, 72.
/// </summary>
internal double ImageYRes = double.NaN;

/// <summary>
/// File extensions corresponding to the supported input formats.
/// </summary>
Expand Down Expand Up @@ -114,9 +124,32 @@ public MuPDFDocument(MuPDFContext context, IntPtr dataAddress, long dataLength,
/// <param name="dataHolder">An <see cref="IDisposable"/> that will be disposed when the <see cref="MuPDFDocument"/> is disposed.</param>
public MuPDFDocument(MuPDFContext context, IntPtr dataAddress, long dataLength, InputFileTypes fileType, ref IDisposable dataHolder)
{
bool isImage = fileType == InputFileTypes.BMP || fileType == InputFileTypes.GIF || fileType == InputFileTypes.JPEG || fileType == InputFileTypes.PAM || fileType == InputFileTypes.PNG || fileType == InputFileTypes.PNM || fileType == InputFileTypes.TIFF;

this.OwnerContext = context;

ExitCodes result = (ExitCodes)NativeMethods.CreateDocumentFromStream(context.NativeContext, dataAddress, (ulong)dataLength, FileTypeMagics[(int)fileType], ref NativeDocument, ref NativeStream, ref PageCount);
float xRes = 0;
float yRes = 0;

ExitCodes result = (ExitCodes)NativeMethods.CreateDocumentFromStream(context.NativeContext, dataAddress, (ulong)dataLength, FileTypeMagics[(int)fileType], isImage ? 1 : 0, ref NativeDocument, ref NativeStream, ref PageCount, ref xRes, ref yRes);

if (xRes > 0)
{
this.ImageXRes = xRes;
}
else
{
this.ImageXRes = 72;
}

if (yRes > 0)
{
this.ImageYRes = yRes;
}
else
{
this.ImageYRes = 72;
}

this.DataHolder = dataHolder;

Expand Down Expand Up @@ -147,13 +180,36 @@ public MuPDFDocument(MuPDFContext context, IntPtr dataAddress, long dataLength,
/// <param name="fileType">The type of the document to read.</param>
public MuPDFDocument(MuPDFContext context, byte[] data, InputFileTypes fileType)
{
bool isImage = fileType == InputFileTypes.BMP || fileType == InputFileTypes.GIF || fileType == InputFileTypes.JPEG || fileType == InputFileTypes.PAM || fileType == InputFileTypes.PNG || fileType == InputFileTypes.PNM || fileType == InputFileTypes.TIFF;

this.OwnerContext = context;

DataHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
IntPtr dataAddress = DataHandle.Value.AddrOfPinnedObject();
ulong dataLength = (ulong)data.Length;

ExitCodes result = (ExitCodes)NativeMethods.CreateDocumentFromStream(context.NativeContext, dataAddress, dataLength, FileTypeMagics[(int)fileType], ref NativeDocument, ref NativeStream, ref PageCount);
float xRes = 0;
float yRes = 0;

ExitCodes result = (ExitCodes)NativeMethods.CreateDocumentFromStream(context.NativeContext, dataAddress, dataLength, FileTypeMagics[(int)fileType], isImage ? 1 : 0, ref NativeDocument, ref NativeStream, ref PageCount, ref xRes, ref yRes);

if (xRes > 0)
{
this.ImageXRes = xRes;
}
else
{
this.ImageXRes = 72;
}

if (yRes > 0)
{
this.ImageYRes = yRes;
}
else
{
this.ImageYRes = 72;
}

switch (result)
{
Expand Down Expand Up @@ -182,6 +238,8 @@ public MuPDFDocument(MuPDFContext context, byte[] data, InputFileTypes fileType)
/// <param name="fileType">The type of the document to read.</param>
public MuPDFDocument(MuPDFContext context, ref MemoryStream data, InputFileTypes fileType)
{
bool isImage = fileType == InputFileTypes.BMP || fileType == InputFileTypes.GIF || fileType == InputFileTypes.JPEG || fileType == InputFileTypes.PAM || fileType == InputFileTypes.PNG || fileType == InputFileTypes.PNM || fileType == InputFileTypes.TIFF;

this.OwnerContext = context;

int origin = (int)data.Seek(0, SeekOrigin.Begin);
Expand All @@ -193,7 +251,29 @@ public MuPDFDocument(MuPDFContext context, ref MemoryStream data, InputFileTypes

DataHolder = data;

ExitCodes result = (ExitCodes)NativeMethods.CreateDocumentFromStream(context.NativeContext, dataAddress, dataLength, FileTypeMagics[(int)fileType], ref NativeDocument, ref NativeStream, ref PageCount);
float xRes = 0;
float yRes = 0;

ExitCodes result = (ExitCodes)NativeMethods.CreateDocumentFromStream(context.NativeContext, dataAddress, dataLength, FileTypeMagics[(int)fileType], isImage ? 1 : 0, ref NativeDocument, ref NativeStream, ref PageCount, ref xRes, ref yRes);

if (xRes > 0)
{
this.ImageXRes = xRes;
}
else
{
this.ImageXRes = 72;
}

if (yRes > 0)
{
this.ImageYRes = yRes;
}
else
{
this.ImageYRes = 72;
}


switch (result)
{
Expand All @@ -220,9 +300,66 @@ public MuPDFDocument(MuPDFContext context, ref MemoryStream data, InputFileTypes
/// <param name="fileName">The path to the file to open.</param>
public MuPDFDocument(MuPDFContext context, string fileName)
{
bool isImage;

string extension = Path.GetExtension(fileName).ToLowerInvariant();

switch (extension)
{
case ".bmp":
case ".dib":

case ".gif":

case ".jpg":
case ".jpeg":
case ".jpe":
case ".jif":
case ".jfif":
case ".jfi":

case ".pam":
case ".pbm":
case ".pgm":
case ".ppm":
case ".pnm":

case ".png":

case ".tif":
case ".tiff":
isImage = true;
break;
default:
isImage = false;
break;
}


this.OwnerContext = context;

ExitCodes result = (ExitCodes)NativeMethods.CreateDocumentFromFile(context.NativeContext, fileName, ref NativeDocument, ref PageCount);
float xRes = 0;
float yRes = 0;

ExitCodes result = (ExitCodes)NativeMethods.CreateDocumentFromFile(context.NativeContext, fileName, isImage ? 1 : 0, ref NativeDocument, ref PageCount, ref xRes, ref yRes);

if (xRes > 0)
{
this.ImageXRes = xRes;
}
else
{
this.ImageXRes = 72;
}

if (yRes > 0)
{
this.ImageYRes = yRes;
}
else
{
this.ImageYRes = 72;
}

switch (result)
{
Expand Down Expand Up @@ -317,6 +454,12 @@ public void Render(int pageNumber, Rectangle region, double zoom, PixelFormats p
throw new ArgumentOutOfRangeException(nameof(zoom), zoom, "The zoom factor is too small!");
}

if (this.ImageXRes != 72 || this.ImageYRes != 72)
{
zoom *= Math.Sqrt(this.ImageXRes * this.ImageYRes) / 72;
region = new Rectangle(region.X0 * 72 / this.ImageXRes, region.Y0 * 72 / this.ImageYRes, region.X1 * 72 / this.ImageXRes, region.Y1 * 72 / this.ImageYRes);
}

float fzoom = (float)zoom;

ExitCodes result = (ExitCodes)NativeMethods.RenderSubDisplayList(OwnerContext.NativeContext, DisplayLists[pageNumber].NativeDisplayList, region.X0, region.Y0, region.X1, region.Y1, fzoom, (int)pixelFormat, destination, IntPtr.Zero);
Expand Down Expand Up @@ -373,7 +516,7 @@ public MuPDFMultiThreadedPageRenderer GetMultiThreadedRenderer(int pageNumber, i
DisplayLists[pageNumber] = new MuPDFDisplayList(this.OwnerContext, this.Pages[pageNumber], includeAnnotations);
}

return new MuPDFMultiThreadedPageRenderer(OwnerContext, DisplayLists[pageNumber], threadCount, Pages[pageNumber].Bounds, this.ClipToPageBounds);
return new MuPDFMultiThreadedPageRenderer(OwnerContext, DisplayLists[pageNumber], threadCount, Pages[pageNumber].Bounds, this.ClipToPageBounds, this.ImageXRes, this.ImageYRes);
}

/// <summary>
Expand Down Expand Up @@ -450,6 +593,12 @@ public void SaveImage(int pageNumber, Rectangle region, double zoom, PixelFormat
throw new ArgumentOutOfRangeException(nameof(zoom), zoom, "The zoom factor is too small!");
}

if (this.ImageXRes != 72 || this.ImageYRes != 72)
{
zoom *= Math.Sqrt(this.ImageXRes * this.ImageYRes) / 72;
region = new Rectangle(region.X0 * 72 / this.ImageXRes, region.Y0 * 72 / this.ImageYRes, region.X1 * 72 / this.ImageXRes, region.Y1 * 72 / this.ImageYRes);
}

float fzoom = (float)zoom;

ExitCodes result = (ExitCodes)NativeMethods.SaveImage(OwnerContext.NativeContext, DisplayLists[pageNumber].NativeDisplayList, region.X0, region.Y0, region.X1, region.Y1, fzoom, (int)pixelFormat, fileName, (int)fileType);
Expand Down Expand Up @@ -509,6 +658,12 @@ public void WriteImage(int pageNumber, Rectangle region, double zoom, PixelForma
throw new ArgumentOutOfRangeException(nameof(zoom), zoom, "The zoom factor is too small!");
}

if (this.ImageXRes != 72 || this.ImageYRes != 72)
{
zoom *= Math.Sqrt(this.ImageXRes * this.ImageYRes) / 72;
region = new Rectangle(region.X0 * 72 / this.ImageXRes, region.Y0 * 72 / this.ImageYRes, region.X1 * 72 / this.ImageXRes, region.Y1 * 72 / this.ImageYRes);
}

float fzoom = (float)zoom;

IntPtr outputBuffer = IntPtr.Zero;
Expand Down Expand Up @@ -609,7 +764,16 @@ public static void CreateDocument(MuPDFContext context, string fileName, Documen
doc.DisplayLists[pageNum] = new MuPDFDisplayList(doc.OwnerContext, doc.Pages[pageNum], includeAnnotations);
}

result = (ExitCodes)NativeMethods.WriteSubDisplayListAsPage(context.NativeContext, doc.DisplayLists[pageNum].NativeDisplayList, pages[i].region.X0, pages[i].region.Y0, pages[i].region.X1, pages[i].region.Y1, pages[i].zoom, documentWriter);
Rectangle region = pages[i].region;
double zoom = pages[i].zoom;

if (pages[i].page.OwnerDocument.ImageXRes != 72 || pages[i].page.OwnerDocument.ImageYRes != 72)
{
zoom *= Math.Sqrt(pages[i].page.OwnerDocument.ImageXRes * pages[i].page.OwnerDocument.ImageYRes) / 72;
region = new Rectangle(region.X0 * 72 / pages[i].page.OwnerDocument.ImageXRes, region.Y0 * 72 / pages[i].page.OwnerDocument.ImageYRes, region.X1 * 72 / pages[i].page.OwnerDocument.ImageXRes, region.Y1 * 72 / pages[i].page.OwnerDocument.ImageYRes);
}

result = (ExitCodes)NativeMethods.WriteSubDisplayListAsPage(context.NativeContext, doc.DisplayLists[pageNum].NativeDisplayList, region.X0, region.Y0, region.X1, region.Y1, (float)zoom, documentWriter);

switch (result)
{
Expand Down
Loading

0 comments on commit 4b85820

Please sign in to comment.