mirror of
https://github.com/cyanfish/naps2.git
synced 2024-10-26 17:11:21 +03:00
Gtk: Fix image resolution
This commit is contained in:
parent
2d7d572a38
commit
e42f012188
@ -1,3 +1,4 @@
|
||||
using System.Globalization;
|
||||
using Gdk;
|
||||
using NAPS2.Images.Bitwise;
|
||||
|
||||
@ -10,6 +11,8 @@ public class GtkImage : IMemoryImage
|
||||
ImageContext = imageContext ?? throw new ArgumentNullException(nameof(imageContext));
|
||||
Pixbuf = pixbuf;
|
||||
LogicalPixelFormat = logicalPixelFormat;
|
||||
HorizontalResolution = float.TryParse(pixbuf.GetOption("x-dpi"), out var xDpi) ? xDpi : 0;
|
||||
VerticalResolution = float.TryParse(pixbuf.GetOption("y-dpi"), out var yDpi) ? yDpi : 0;
|
||||
}
|
||||
|
||||
public ImageContext ImageContext { get; }
|
||||
@ -26,7 +29,6 @@ public class GtkImage : IMemoryImage
|
||||
|
||||
public void SetResolution(float xDpi, float yDpi)
|
||||
{
|
||||
// TODO: ?
|
||||
HorizontalResolution = xDpi;
|
||||
VerticalResolution = yDpi;
|
||||
}
|
||||
@ -71,14 +73,8 @@ public class GtkImage : IMemoryImage
|
||||
imageFormat = ImageContext.GetFileFormatFromExtension(path);
|
||||
}
|
||||
var type = GetType(imageFormat);
|
||||
if (imageFormat == ImageFileFormat.Jpeg && quality != -1)
|
||||
{
|
||||
Pixbuf.Savev(path, type, new[] { "quality" }, new[] { quality.ToString() });
|
||||
}
|
||||
else
|
||||
{
|
||||
Pixbuf.Save(path, type);
|
||||
}
|
||||
var (keys, values) = GetSaveOptions(imageFormat, quality);
|
||||
Pixbuf.Savev(path, type, keys, values);
|
||||
}
|
||||
|
||||
public void Save(Stream stream, ImageFileFormat imageFormat, int quality = -1)
|
||||
@ -88,17 +84,9 @@ public class GtkImage : IMemoryImage
|
||||
throw new ArgumentException("Format required to save to a stream", nameof(imageFormat));
|
||||
}
|
||||
var type = GetType(imageFormat);
|
||||
var (keys, values) = GetSaveOptions(imageFormat, quality);
|
||||
// TODO: Map to OutputStream directly?
|
||||
byte[] buffer;
|
||||
if (imageFormat == ImageFileFormat.Jpeg && quality != -1)
|
||||
{
|
||||
buffer = Pixbuf.SaveToBuffer(type, new[] { "quality" }, new[] { quality.ToString() });
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer = Pixbuf.SaveToBuffer(type);
|
||||
}
|
||||
stream.Write(buffer);
|
||||
stream.Write(Pixbuf.SaveToBuffer(type, keys, values));
|
||||
}
|
||||
|
||||
private string GetType(ImageFileFormat fileFormat) => fileFormat switch
|
||||
@ -110,6 +98,26 @@ public class GtkImage : IMemoryImage
|
||||
_ => throw new ArgumentException("Unsupported file format")
|
||||
};
|
||||
|
||||
private (string[] keys, string[] values) GetSaveOptions(ImageFileFormat imageFormat, int quality)
|
||||
{
|
||||
var keys = new List<string>
|
||||
{
|
||||
"x-dpi",
|
||||
"y-dpi"
|
||||
};
|
||||
var values = new List<string>
|
||||
{
|
||||
HorizontalResolution.ToString(CultureInfo.InvariantCulture),
|
||||
VerticalResolution.ToString(CultureInfo.InvariantCulture)
|
||||
};
|
||||
if (imageFormat == ImageFileFormat.Jpeg && quality != -1)
|
||||
{
|
||||
keys.Add("quality");
|
||||
values.Add(quality.ToString());
|
||||
}
|
||||
return (keys.ToArray(), values.ToArray());
|
||||
}
|
||||
|
||||
public IMemoryImage Clone() => new GtkImage(ImageContext, (Pixbuf) Pixbuf.Clone(), LogicalPixelFormat)
|
||||
{
|
||||
OriginalFileFormat = OriginalFileFormat
|
||||
|
@ -82,6 +82,8 @@ internal class LibTiffIo : ITiffWriter
|
||||
private static void WriteTiffMetadata(IntPtr tiff, ImagePixelFormat pixelFormat,
|
||||
TiffCompressionType compression, IMemoryImage image)
|
||||
{
|
||||
// TODO: A lot of these types are wrong (e.g. int32 instead of int16)
|
||||
// http://www.libtiff.org/man/TIFFSetField.3t.html
|
||||
LibTiff.TIFFSetField(tiff, TiffTag.ImageWidth, image.Width);
|
||||
LibTiff.TIFFSetField(tiff, TiffTag.ImageHeight, image.Height);
|
||||
LibTiff.TIFFSetField(tiff, TiffTag.PlanarConfig, 1);
|
||||
@ -110,13 +112,15 @@ internal class LibTiffIo : ITiffWriter
|
||||
}));
|
||||
if (pixelFormat == ImagePixelFormat.ARGB32)
|
||||
{
|
||||
// TODO: I think this is completely wrong
|
||||
LibTiff.TIFFSetField(tiff, TiffTag.ExtraSamples, 1);
|
||||
}
|
||||
if (image.HorizontalResolution != 0 && image.VerticalResolution != 0)
|
||||
{
|
||||
LibTiff.TIFFSetField(tiff, TiffTag.ResolutionUnit, 2);
|
||||
LibTiff.TIFFSetField(tiff, TiffTag.XResolution, (int) image.HorizontalResolution);
|
||||
LibTiff.TIFFSetField(tiff, TiffTag.YResolution, (int) image.VerticalResolution);
|
||||
// TODO: Why do we need to write as a double? It's supposed to be a float.
|
||||
LibTiff.TIFFSetField(tiff, TiffTag.XResolution, (double) image.HorizontalResolution);
|
||||
LibTiff.TIFFSetField(tiff, TiffTag.YResolution, (double) image.VerticalResolution);
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,9 +146,13 @@ internal class LibTiffIo : ITiffWriter
|
||||
{
|
||||
do
|
||||
{
|
||||
LibTiff.TIFFGetField(tiff, TiffTag.ImageWidth, out var w);
|
||||
LibTiff.TIFFGetField(tiff, TiffTag.ImageHeight, out var h);
|
||||
LibTiff.TIFFGetField(tiff, TiffTag.ImageWidth, out int w);
|
||||
LibTiff.TIFFGetField(tiff, TiffTag.ImageHeight, out int h);
|
||||
// TODO: Check return values
|
||||
LibTiff.TIFFGetField(tiff, TiffTag.XResolution, out float xres);
|
||||
LibTiff.TIFFGetField(tiff, TiffTag.YResolution, out float yres);
|
||||
var img = _imageContext.Create(w, h, ImagePixelFormat.ARGB32);
|
||||
img.SetResolution(xres, yres);
|
||||
img.OriginalFileFormat = ImageFileFormat.Tiff;
|
||||
using var imageLock = img.Lock(LockMode.WriteOnly, out var data);
|
||||
ReadTiffFrame(data.safePtr, tiff, w, h);
|
||||
|
@ -56,12 +56,25 @@ internal static class LibTiff
|
||||
[DllImport("libtiff.so.5")]
|
||||
public static extern int TIFFWriteDirectory(IntPtr tiff);
|
||||
|
||||
// TODO: Clean these overloads up
|
||||
[DllImport("libtiff.so.5")]
|
||||
public static extern int TIFFGetField(IntPtr tiff, TiffTag tag, out int field);
|
||||
|
||||
[DllImport("libtiff.so.5")]
|
||||
public static extern int TIFFGetField(IntPtr tiff, TiffTag tag, out float field);
|
||||
|
||||
[DllImport("libtiff.so.5")]
|
||||
public static extern int TIFFGetField(IntPtr tiff, TiffTag tag, out double field);
|
||||
|
||||
[DllImport("libtiff.so.5")]
|
||||
public static extern int TIFFSetField(IntPtr tiff, TiffTag tag, int field);
|
||||
|
||||
[DllImport("libtiff.so.5")]
|
||||
public static extern int TIFFSetField(IntPtr tiff, TiffTag tag, float field);
|
||||
|
||||
[DllImport("libtiff.so.5")]
|
||||
public static extern int TIFFSetField(IntPtr tiff, TiffTag tag, double field);
|
||||
|
||||
[DllImport("libtiff.so.5")]
|
||||
public static extern int TIFFWriteScanline(
|
||||
IntPtr tiff, tdata_t buf, int row, short sample);
|
||||
|
@ -10,27 +10,27 @@ public class LoadSaveTests : ContextualTests
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(TestCases))]
|
||||
public void LoadFromFile(ImageFileFormat format, string ext, string resource, string[] compare)
|
||||
public void LoadFromFile(ImageFileFormat format, string ext, string resource, string[] compare, bool ignoreRes)
|
||||
{
|
||||
var path = CopyResourceToFile(GetResource(resource), $"image{ext}");
|
||||
using var image = ImageContext.Load(path);
|
||||
Assert.Equal(format, image.OriginalFileFormat);
|
||||
ImageAsserts.Similar(GetResource(compare[0]), image);
|
||||
ImageAsserts.Similar(GetResource(compare[0]), image, ignoreResolution: ignoreRes);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(TestCases))]
|
||||
public void LoadFromStream(ImageFileFormat format, string ext, string resource, string[] compare)
|
||||
public void LoadFromStream(ImageFileFormat format, string ext, string resource, string[] compare, bool ignoreRes)
|
||||
{
|
||||
var stream = new MemoryStream(GetResource(resource));
|
||||
using var image = ImageContext.Load(stream);
|
||||
Assert.Equal(format, image.OriginalFileFormat);
|
||||
ImageAsserts.Similar(GetResource(compare[0]), image);
|
||||
ImageAsserts.Similar(GetResource(compare[0]), image, ignoreResolution: ignoreRes);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(TestCases))]
|
||||
public void LoadFramesFromFile(ImageFileFormat format, string ext, string resource, string[] compare)
|
||||
public void LoadFramesFromFile(ImageFileFormat format, string ext, string resource, string[] compare, bool ignoreRes)
|
||||
{
|
||||
var path = CopyResourceToFile(GetResource(resource), $"image{ext}");
|
||||
var images = ImageContext.LoadFrames(path, out var count).ToArray();
|
||||
@ -39,13 +39,13 @@ public class LoadSaveTests : ContextualTests
|
||||
for (int i = 0; i < images.Length; i++)
|
||||
{
|
||||
Assert.Equal(format, images[i].OriginalFileFormat);
|
||||
ImageAsserts.Similar(GetResource(compare[i]), images[i]);
|
||||
ImageAsserts.Similar(GetResource(compare[i]), images[i], ignoreResolution: ignoreRes);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(TestCases))]
|
||||
public void LoadFramesFromStream(ImageFileFormat format, string ext, string resource, string[] compare)
|
||||
public void LoadFramesFromStream(ImageFileFormat format, string ext, string resource, string[] compare, bool ignoreRes)
|
||||
{
|
||||
var stream = new MemoryStream(GetResource(resource));
|
||||
var images = ImageContext.LoadFrames(stream, out var count).ToArray();
|
||||
@ -54,32 +54,32 @@ public class LoadSaveTests : ContextualTests
|
||||
for (int i = 0; i < images.Length; i++)
|
||||
{
|
||||
Assert.Equal(format, images[i].OriginalFileFormat);
|
||||
ImageAsserts.Similar(GetResource(compare[i]), images[i]);
|
||||
ImageAsserts.Similar(GetResource(compare[i]), images[i], ignoreResolution: ignoreRes);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(TestCases))]
|
||||
public void SaveToFile(ImageFileFormat format, string ext, string resource, string[] compare)
|
||||
public void SaveToFile(ImageFileFormat format, string ext, string resource, string[] compare, bool ignoreRes)
|
||||
{
|
||||
var image = LoadImage(GetResource(resource));
|
||||
var path = Path.Combine(FolderPath, $"image{ext}");
|
||||
image.Save(path);
|
||||
var image2 = ImageContext.Load(path);
|
||||
Assert.Equal(format, image2.OriginalFileFormat);
|
||||
ImageAsserts.Similar(GetResource(compare[0]), image2);
|
||||
ImageAsserts.Similar(GetResource(compare[0]), image2, ignoreResolution: ignoreRes);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(TestCases))]
|
||||
public void SaveToStream(ImageFileFormat format, string ext, string resource, string[] compare)
|
||||
public void SaveToStream(ImageFileFormat format, string ext, string resource, string[] compare, bool ignoreRes)
|
||||
{
|
||||
var image = LoadImage(GetResource(resource));
|
||||
var stream = new MemoryStream();
|
||||
image.Save(stream, format);
|
||||
var image2 = ImageContext.Load(stream);
|
||||
Assert.Equal(format, image2.OriginalFileFormat);
|
||||
ImageAsserts.Similar(GetResource(compare[0]), image2);
|
||||
ImageAsserts.Similar(GetResource(compare[0]), image2, ignoreResolution: ignoreRes);
|
||||
}
|
||||
|
||||
private static byte[] GetResource(string resource) =>
|
||||
@ -90,22 +90,22 @@ public class LoadSaveTests : ContextualTests
|
||||
new object[]
|
||||
{
|
||||
ImageFileFormat.Png, ".png", "color_image_png",
|
||||
new[] { "color_image" }
|
||||
new[] { "color_image" }, false
|
||||
},
|
||||
new object[]
|
||||
{
|
||||
ImageFileFormat.Jpeg, ".jpg", "color_image",
|
||||
new[] { "color_image" }
|
||||
new[] { "color_image" }, false
|
||||
},
|
||||
new object[]
|
||||
{
|
||||
ImageFileFormat.Bmp, ".bmp", "color_image_bw_invertpal",
|
||||
new[] { "color_image_bw" }
|
||||
new[] { "color_image_bw" }, true
|
||||
},
|
||||
new object[]
|
||||
{
|
||||
ImageFileFormat.Tiff, ".tiff", "color_image_tiff",
|
||||
new[] { "color_image", "color_image_h_p300", "stock_cat" }
|
||||
new[] { "color_image", "color_image_h_p300", "stock_cat" }, false
|
||||
},
|
||||
};
|
||||
}
|
@ -9,8 +9,7 @@ public class PdfiumPdfRendererTests : ContextualTests
|
||||
[Fact]
|
||||
public void RenderPdfFromWord()
|
||||
{
|
||||
var path = Path.Combine(FolderPath, "test.pdf");
|
||||
File.WriteAllBytes(path, PdfResources.word_generated_pdf);
|
||||
var path = CopyResourceToFile(PdfResources.word_generated_pdf, "test.pdf");
|
||||
|
||||
var images = new PdfiumPdfRenderer().Render(ImageContext, path, PdfRenderSize.Default).ToList();
|
||||
|
||||
@ -22,21 +21,19 @@ public class PdfiumPdfRendererTests : ContextualTests
|
||||
[Fact]
|
||||
public void RenderPlainImagePdf()
|
||||
{
|
||||
var path = Path.Combine(FolderPath, "test.pdf");
|
||||
File.WriteAllBytes(path, PdfResources.image_pdf);
|
||||
var path = CopyResourceToFile(PdfResources.image_pdf, "test.pdf");
|
||||
|
||||
var images = new PdfiumPdfRenderer().Render(ImageContext, path, PdfRenderSize.Default).ToList();
|
||||
|
||||
Assert.Single(images);
|
||||
// This also verifies that the renderer gets the actual image dpi (72)
|
||||
// This also verifies that the renderer gets the actual image dpi (72)
|
||||
ImageAsserts.Similar(ImageResources.color_image, images[0]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RenderImageWithTextPdf()
|
||||
{
|
||||
var path = Path.Combine(FolderPath, "test.pdf");
|
||||
File.WriteAllBytes(path, PdfResources.image_with_text_pdf);
|
||||
var path = CopyResourceToFile(PdfResources.image_with_text_pdf, "test.pdf");
|
||||
|
||||
var images = new PdfiumPdfRenderer().Render(ImageContext, path, PdfRenderSize.Default).ToList();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user