Add transform tests

This commit is contained in:
Ben Olden-Cooligan 2019-03-20 12:38:12 -04:00
parent 0ed3fdd5ec
commit 3770dbb894
27 changed files with 892 additions and 4 deletions

View File

@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NAPS2.Images.Storage;
using Xunit;
namespace NAPS2.Sdk.Tests.Asserts
{
public static class ImageAsserts
{
public static unsafe void Similar(IImage first, IImage second, double rmseThreshold)
{
Assert.Equal(first.Width, second.Width);
Assert.Equal(first.Height, second.Height);
Assert.Equal(first.PixelFormat, second.PixelFormat);
Assert.Equal(first.HorizontalResolution, second.HorizontalResolution);
Assert.Equal(first.VerticalResolution, second.VerticalResolution);
var lock1 = first.Lock(LockMode.ReadOnly, out var scan01, out var stride1);
var lock2 = second.Lock(LockMode.ReadOnly, out var scan02, out var stride2);
try
{
if (first.PixelFormat != StoragePixelFormat.RGB24)
{
throw new InvalidOperationException("Unsupported pixel format");
}
int width = first.Width;
int height = first.Height;
int bytesPerPixel = 3;
long total = 0;
long div = width * height * 3;
byte* data1 = (byte*)scan01;
byte* data2 = (byte*)scan02;
for (int y = 0; y < height; y++)
{
byte* row1 = data1 + stride1 * y;
byte* row2 = data2 + stride2 * y;
for (int x = 0; x < width; x++)
{
byte* pixel1 = row1 + x * bytesPerPixel;
byte* pixel2 = row2 + x * bytesPerPixel;
byte r1 = *pixel1;
byte g1 = *(pixel1 + 1);
byte b1 = *(pixel1 + 2);
byte r2 = *pixel2;
byte g2 = *(pixel2 + 1);
byte b2 = *(pixel2 + 2);
total += (r1 - r2) * (r1 - r2) + (g1 - g2) * (g1 - g2) + (b1 - b2) * (b1 - b2);
}
}
double rmse = Math.Sqrt(total / (double) div);
Assert.True(rmse <= rmseThreshold, $"RMSE was {rmse}, expected <= {rmseThreshold}");
}
finally
{
first.Unlock(lock1);
second.Unlock(lock2);
}
}
}
}

View File

@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace NAPS2.Sdk.Tests.Images
{
public class GdiTests : ContextualTexts
{
}
}

View File

@ -0,0 +1,322 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NAPS2.Images.Storage;
using NAPS2.Images.Transforms;
using NAPS2.Sdk.Tests.Asserts;
using Xunit;
namespace NAPS2.Sdk.Tests.Images
{
public class TransformTests : ContextualTexts
{
// JPEG artifacts seem to consistently create a RMSE of about 2.5.
// TODO: Use PNG or some other way to do a precise comparison.
private const double GENERAL_RMSE_THRESHOLD = 3.5;
private const double NULL_RMSE_THRESHOLD = 0.5;
[Fact]
public void BrightnessNull()
{
IImage actual = new GdiImage(TransformTestsData.color_image);
IImage expected = new GdiImage(TransformTestsData.color_image);
actual = Transform.Perform(actual, new BrightnessTransform());
ImageAsserts.Similar(expected, actual, NULL_RMSE_THRESHOLD);
}
[Fact]
public void BrightnessP300()
{
IImage actual = new GdiImage(TransformTestsData.color_image);
IImage expected = new GdiImage(TransformTestsData.color_image_b_p300);
actual = Transform.Perform(actual, new BrightnessTransform(300));
ImageAsserts.Similar(expected, actual, GENERAL_RMSE_THRESHOLD);
}
[Fact]
public void BrightnessN300()
{
IImage actual = new GdiImage(TransformTestsData.color_image);
IImage expected = new GdiImage(TransformTestsData.color_image_b_n300);
actual = Transform.Perform(actual, new BrightnessTransform(-300));
ImageAsserts.Similar(expected, actual, GENERAL_RMSE_THRESHOLD);
}
[Fact]
public void ContrastNull()
{
IImage actual = new GdiImage(TransformTestsData.color_image);
IImage expected = new GdiImage(TransformTestsData.color_image);
actual = Transform.Perform(actual, new TrueContrastTransform());
ImageAsserts.Similar(expected, actual, NULL_RMSE_THRESHOLD);
}
[Fact]
public void ContrastP300()
{
IImage actual = new GdiImage(TransformTestsData.color_image);
IImage expected = new GdiImage(TransformTestsData.color_image_c_p300);
actual = Transform.Perform(actual, new TrueContrastTransform(300));
ImageAsserts.Similar(expected, actual, GENERAL_RMSE_THRESHOLD);
}
[Fact]
public void ContrastN300()
{
IImage actual = new GdiImage(TransformTestsData.color_image);
IImage expected = new GdiImage(TransformTestsData.color_image_c_n300);
actual = Transform.Perform(actual, new TrueContrastTransform(-300));
ImageAsserts.Similar(expected, actual, GENERAL_RMSE_THRESHOLD);
}
[Fact]
public void HueNull()
{
IImage actual = new GdiImage(TransformTestsData.color_image);
IImage expected = new GdiImage(TransformTestsData.color_image);
actual = Transform.Perform(actual, new HueTransform());
ImageAsserts.Similar(expected, actual, NULL_RMSE_THRESHOLD);
}
[Fact]
public void HueP300()
{
IImage actual = new GdiImage(TransformTestsData.color_image);
IImage expected = new GdiImage(TransformTestsData.color_image_h_p300);
actual = Transform.Perform(actual, new HueTransform(300));
ImageAsserts.Similar(expected, actual, GENERAL_RMSE_THRESHOLD);
}
[Fact]
public void HueN300()
{
IImage actual = new GdiImage(TransformTestsData.color_image);
IImage expected = new GdiImage(TransformTestsData.color_image_h_n300);
actual = Transform.Perform(actual, new HueTransform(-300));
ImageAsserts.Similar(expected, actual, GENERAL_RMSE_THRESHOLD);
}
[Fact]
public void SaturationNull()
{
IImage actual = new GdiImage(TransformTestsData.color_image);
IImage expected = new GdiImage(TransformTestsData.color_image);
actual = Transform.Perform(actual, new SaturationTransform());
ImageAsserts.Similar(expected, actual, NULL_RMSE_THRESHOLD);
}
[Fact]
public void SaturationP300()
{
IImage actual = new GdiImage(TransformTestsData.color_image);
IImage expected = new GdiImage(TransformTestsData.color_image_s_p300);
actual = Transform.Perform(actual, new SaturationTransform(300));
ImageAsserts.Similar(expected, actual, GENERAL_RMSE_THRESHOLD);
}
[Fact]
public void SaturationN300()
{
IImage actual = new GdiImage(TransformTestsData.color_image);
IImage expected = new GdiImage(TransformTestsData.color_image_s_n300);
actual = Transform.Perform(actual, new SaturationTransform(-300));
ImageAsserts.Similar(expected, actual, GENERAL_RMSE_THRESHOLD);
}
[Fact]
public void SharpenNull()
{
IImage actual = new GdiImage(TransformTestsData.color_image);
IImage expected = new GdiImage(TransformTestsData.color_image);
actual = Transform.Perform(actual, new SharpenTransform());
ImageAsserts.Similar(expected, actual, NULL_RMSE_THRESHOLD);
}
[Fact]
public void SharpenP300()
{
IImage actual = new GdiImage(TransformTestsData.color_image);
IImage expected = new GdiImage(TransformTestsData.color_image_sh_p1000);
actual = Transform.Perform(actual, new SharpenTransform(1000));
ImageAsserts.Similar(expected, actual, GENERAL_RMSE_THRESHOLD);
}
[Fact]
public void SharpenN300()
{
IImage actual = new GdiImage(TransformTestsData.color_image);
IImage expected = new GdiImage(TransformTestsData.color_image_sh_n1000);
actual = Transform.Perform(actual, new SharpenTransform(-1000));
ImageAsserts.Similar(expected, actual, GENERAL_RMSE_THRESHOLD);
}
[Fact]
public void RotationNull()
{
IImage actual = new GdiImage(TransformTestsData.color_image);
IImage expected = new GdiImage(TransformTestsData.color_image);
actual = Transform.Perform(actual, new RotationTransform());
ImageAsserts.Similar(expected, actual, NULL_RMSE_THRESHOLD);
}
[Fact]
public void RotationP90()
{
IImage actual = new GdiImage(TransformTestsData.color_image);
IImage expected = new GdiImage(TransformTestsData.color_image_r_p90);
actual = Transform.Perform(actual, new RotationTransform(90));
ImageAsserts.Similar(expected, actual, GENERAL_RMSE_THRESHOLD);
}
[Fact]
public void RotationP46()
{
IImage actual = new GdiImage(TransformTestsData.color_image);
IImage expected = new GdiImage(TransformTestsData.color_image_r_p46);
actual = Transform.Perform(actual, new RotationTransform(46));
ImageAsserts.Similar(expected, actual, GENERAL_RMSE_THRESHOLD);
}
[Fact]
public void RotationN45()
{
IImage actual = new GdiImage(TransformTestsData.color_image);
IImage expected = new GdiImage(TransformTestsData.color_image_r_n45);
actual = Transform.Perform(actual, new RotationTransform(-45));
ImageAsserts.Similar(expected, actual, GENERAL_RMSE_THRESHOLD);
}
[Fact]
public void Rotation180()
{
IImage actual = new GdiImage(TransformTestsData.color_image);
IImage actual2 = new GdiImage(TransformTestsData.color_image);
IImage expected = new GdiImage(TransformTestsData.color_image_r_180);
actual = Transform.Perform(actual, new RotationTransform(180));
actual2 = Transform.Perform(actual2, new RotationTransform(-180));
ImageAsserts.Similar(actual2, actual, 0);
ImageAsserts.Similar(expected, actual, GENERAL_RMSE_THRESHOLD);
}
[Fact]
public void CropNull()
{
IImage actual = new GdiImage(TransformTestsData.color_image);
IImage expected = new GdiImage(TransformTestsData.color_image);
actual = Transform.Perform(actual, new CropTransform());
ImageAsserts.Similar(expected, actual, NULL_RMSE_THRESHOLD);
}
[Fact]
public void Crop()
{
IImage actual = new GdiImage(TransformTestsData.color_image);
IImage expected = new GdiImage(TransformTestsData.color_image_c_5_10_15_20);
actual = Transform.Perform(actual, new CropTransform(10, 20, 15, 5));
ImageAsserts.Similar(expected, actual, GENERAL_RMSE_THRESHOLD);
}
[Fact]
public void CropWithOriginal()
{
IImage actual = new GdiImage(TransformTestsData.color_image);
IImage expected = new GdiImage(TransformTestsData.color_image_c_5_10_15_20);
actual = Transform.Perform(actual, new CropTransform(10, 20, 15, 5, actual.Width, actual.Height));
ImageAsserts.Similar(expected, actual, GENERAL_RMSE_THRESHOLD);
}
[Fact]
public void CropWithDifferentOriginal()
{
IImage actual = new GdiImage(TransformTestsData.color_image);
IImage expected = new GdiImage(TransformTestsData.color_image_c_5_10_15_20);
actual = Transform.Perform(actual, new CropTransform(20, 40, 30, 10, actual.Width * 2, actual.Height * 2));
ImageAsserts.Similar(expected, actual, GENERAL_RMSE_THRESHOLD);
}
[Fact]
public void BlackWhite()
{
IImage actual = new GdiImage(TransformTestsData.color_image);
IImage expected = new GdiImage(TransformTestsData.color_image_bw);
actual = Transform.Perform(actual, new BlackWhiteTransform());
Assert.Equal(StoragePixelFormat.BW1, actual.PixelFormat);
actual = To24Bit(actual);
ImageAsserts.Similar(expected, actual, GENERAL_RMSE_THRESHOLD);
}
[Fact]
public void BlackWhiteP300()
{
IImage actual = new GdiImage(TransformTestsData.color_image);
IImage expected = new GdiImage(TransformTestsData.color_image_bw_p300);
actual = Transform.Perform(actual, new BlackWhiteTransform(300));
Assert.Equal(StoragePixelFormat.BW1, actual.PixelFormat);
actual = To24Bit(actual);
ImageAsserts.Similar(expected, actual, GENERAL_RMSE_THRESHOLD);
}
private static IImage To24Bit(IImage actual)
{
// Convert to 24-bit for comparison
// TODO: Maybe have a Color24BitTransform or something to be more reusable
var bitmap = ((GdiImage) actual).Bitmap;
GdiTransformers.EnsurePixelFormat(ref bitmap);
actual = new GdiImage(bitmap);
return actual;
}
}
}

View File

@ -0,0 +1,243 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace NAPS2.Sdk.Tests.Images {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class TransformTestsData {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal TransformTestsData() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("NAPS2.Sdk.Tests.Images.TransformTestsData", typeof(TransformTestsData).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap color_image {
get {
object obj = ResourceManager.GetObject("color_image", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap color_image_b_n300 {
get {
object obj = ResourceManager.GetObject("color_image_b_n300", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap color_image_b_p300 {
get {
object obj = ResourceManager.GetObject("color_image_b_p300", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap color_image_bw {
get {
object obj = ResourceManager.GetObject("color_image_bw", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap color_image_bw_p300 {
get {
object obj = ResourceManager.GetObject("color_image_bw_p300", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap color_image_c_5_10_15_20 {
get {
object obj = ResourceManager.GetObject("color_image_c_5_10_15_20", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap color_image_c_n300 {
get {
object obj = ResourceManager.GetObject("color_image_c_n300", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap color_image_c_p300 {
get {
object obj = ResourceManager.GetObject("color_image_c_p300", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap color_image_h_n300 {
get {
object obj = ResourceManager.GetObject("color_image_h_n300", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap color_image_h_p300 {
get {
object obj = ResourceManager.GetObject("color_image_h_p300", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap color_image_r_180 {
get {
object obj = ResourceManager.GetObject("color_image_r_180", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap color_image_r_n45 {
get {
object obj = ResourceManager.GetObject("color_image_r_n45", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap color_image_r_p46 {
get {
object obj = ResourceManager.GetObject("color_image_r_p46", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap color_image_r_p90 {
get {
object obj = ResourceManager.GetObject("color_image_r_p90", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap color_image_s_n300 {
get {
object obj = ResourceManager.GetObject("color_image_s_n300", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap color_image_s_p300 {
get {
object obj = ResourceManager.GetObject("color_image_s_p300", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap color_image_sh_n1000 {
get {
object obj = ResourceManager.GetObject("color_image_sh_n1000", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
/// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary>
internal static System.Drawing.Bitmap color_image_sh_p1000 {
get {
object obj = ResourceManager.GetObject("color_image_sh_p1000", resourceCulture);
return ((System.Drawing.Bitmap)(obj));
}
}
}
}

View File

@ -0,0 +1,175 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="color_image" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\color_image.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="color_image_bw" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\color_image_bw.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="color_image_bw_p300" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\color_image_bw_p300.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="color_image_b_n300" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\color_image_b_n300.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="color_image_b_p300" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\color_image_b_p300.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="color_image_c_5_10_15_20" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\color_image_c_5_10_15_20.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="color_image_c_n300" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\color_image_c_n300.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="color_image_c_p300" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\color_image_c_p300.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="color_image_h_n300" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\color_image_h_n300.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="color_image_h_p300" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\color_image_h_p300.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="color_image_r_180" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\color_image_r_180.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="color_image_r_n45" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\color_image_r_n45.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="color_image_r_p46" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\color_image_r_p46.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="color_image_r_p90" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\color_image_r_p90.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="color_image_sh_n1000" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\color_image_sh_n1000.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="color_image_sh_p1000" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\color_image_sh_p1000.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="color_image_s_n300" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\color_image_s_n300.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="color_image_s_p300" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\color_image_s_p300.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

View File

@ -25,6 +25,7 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
@ -33,6 +34,7 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Reference Include="BouncyCastle.Crypto, Version=1.8.4.0, Culture=neutral, PublicKeyToken=0e99375e54769942">
@ -88,12 +90,20 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Asserts\ImageAsserts.cs" />
<Compile Include="Asserts\PdfAsserts.cs" />
<Compile Include="Config\CommonConfigTests.cs" />
<Compile Include="Config\ProfileSerializerTests.cs" />
<Compile Include="GlobalSuppressions.cs" />
<Compile Include="Images\GdiTests.cs" />
<Compile Include="Images\ScannedImageSinkTests.cs" />
<Compile Include="Images\StorageTests.cs" />
<Compile Include="Images\TransformTests.cs" />
<Compile Include="Images\TransformTestsData.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>TransformTestsData.resx</DependentUpon>
</Compile>
<Compile Include="Mocks\MockScanDriver.cs" />
<Compile Include="Scan\AutoSaveTests.cs" />
<Compile Include="Config\ProfileSerializerTestsData.Designer.cs">
@ -121,6 +131,11 @@
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>ProfileSerializerTestsData.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Include="Images\TransformTestsData.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>TransformTestsData.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
@ -129,6 +144,60 @@
<ItemGroup>
<Analyzer Include="..\packages\xunit.analyzers.0.10.0\analyzers\dotnet\cs\xunit.analyzers.dll" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\color_image_s_p300.jpg" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\color_image_h_n300.jpg" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\color_image_h_p300.jpg" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\color_image_c_n300.jpg" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\color_image_c_p300.jpg" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\color_image_b_n300.jpg" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\color_image_b_p300.jpg" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\color_image.jpg" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\color_image_c_5_10_15_20.jpg" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\color_image_r_180.jpg" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\color_image_r_p46.jpg" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\color_image_r_n45.jpg" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\color_image_r_p90.jpg" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\color_image_bw_p300.jpg" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\color_image_bw.jpg" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\color_image_sh_n1000.jpg" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\color_image_sh_p1000.jpg" />
</ItemGroup>
<ItemGroup>
<None Include="Resources\color_image_s_n300.jpg" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

View File

@ -270,12 +270,12 @@ namespace NAPS2.Images.Storage
Bitmap result;
if (transform.Angle > 45.0 && transform.Angle < 135.0 || transform.Angle > 225.0 && transform.Angle < 315.0)
{
result = new Bitmap(image.Height, image.Width);
result = new Bitmap(image.Height, image.Width, PixelFormat.Format24bppRgb);
result.SafeSetResolution(image.VerticalResolution, image.HorizontalResolution);
}
else
{
result = new Bitmap(image.Width, image.Height);
result = new Bitmap(image.Width, image.Height, PixelFormat.Format24bppRgb);
result.SafeSetResolution(image.HorizontalResolution, image.VerticalResolution);
}
using (var g = Graphics.FromImage(result))
@ -402,7 +402,7 @@ namespace NAPS2.Images.Storage
/// If the provided bitmap is 1-bit (black and white), replace it with a 24-bit bitmap so that image transforms will work. If the bitmap is replaced, the original is disposed.
/// </summary>
/// <param name="bitmap">The bitmap that may be replaced.</param>
protected static void EnsurePixelFormat(ref Bitmap bitmap)
protected internal static void EnsurePixelFormat(ref Bitmap bitmap)
{
if (bitmap.PixelFormat == PixelFormat.Format1bppIndexed)
{

View File

@ -1,4 +1,5 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
@ -13,6 +14,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: InternalsVisibleTo("NAPS2.Sdk.Tests")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.

View File

@ -13,4 +13,5 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=Lineart/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Lossless/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=mapi/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Pdfs/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Pdfs/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=rmse/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>