diff --git a/src/ImageProcessor/Colors/Color.cs b/src/ImageProcessor/Colors/Color.cs index 3d04a0a41..44ed036e3 100644 --- a/src/ImageProcessor/Colors/Color.cs +++ b/src/ImageProcessor/Colors/Color.cs @@ -11,7 +11,7 @@ namespace ImageProcessor /// /// Represents a four-component color using red, green, blue, and alpha data. - /// Each component is stored in a linear premultiplied format multiplied by the alpha component. + /// Each component is stored in premultiplied format multiplied by the alpha component. /// /// /// This struct is fully mutable. This is done (against the guidelines) for the sake of performance, diff --git a/src/ImageProcessor/Colors/ColorDefinitions.cs b/src/ImageProcessor/Colors/ColorDefinitions.cs index 78ea3fbca..061b509de 100644 --- a/src/ImageProcessor/Colors/ColorDefinitions.cs +++ b/src/ImageProcessor/Colors/ColorDefinitions.cs @@ -7,7 +7,7 @@ namespace ImageProcessor { /// /// Represents a four-component color using red, green, blue, and alpha data. - /// Each component is stored in a linear premultiplied format multiplied by the alpha component. + /// Each component is stored in premultiplied format multiplied by the alpha component. /// /// /// This struct is fully mutable. This is done (against the guidelines) for the sake of performance, diff --git a/src/ImageProcessor/Colors/ColorTransforms.cs b/src/ImageProcessor/Colors/ColorTransforms.cs index 9551222fb..43bc03251 100644 --- a/src/ImageProcessor/Colors/ColorTransforms.cs +++ b/src/ImageProcessor/Colors/ColorTransforms.cs @@ -9,7 +9,7 @@ namespace ImageProcessor /// /// Represents a four-component color using red, green, blue, and alpha data. - /// Each component is stored in a linear premultiplied format multiplied by the alpha component. + /// Each component is stored in premultiplied format multiplied by the alpha component. /// /// /// This struct is fully mutable. This is done (against the guidelines) for the sake of performance, diff --git a/src/ImageProcessor/Colors/ColorspaceTransforms.cs b/src/ImageProcessor/Colors/ColorspaceTransforms.cs index ea08973fe..334c967fb 100644 --- a/src/ImageProcessor/Colors/ColorspaceTransforms.cs +++ b/src/ImageProcessor/Colors/ColorspaceTransforms.cs @@ -9,7 +9,7 @@ namespace ImageProcessor /// /// Represents a four-component color using red, green, blue, and alpha data. - /// Each component is stored in a linear premultiplied format multiplied by the alpha component. + /// Each component is stored in premultiplied format multiplied by the alpha component. /// /// /// This struct is fully mutable. This is done (against the guidelines) for the sake of performance, @@ -86,7 +86,7 @@ namespace ImageProcessor float g = (x * -0.9689F) + (y * 1.8758F) + (z * 0.0415F); float b = (x * 0.0557F) + (y * -0.2040F) + (z * 1.0570F); - return new Color(r, g, b); + return Color.Compress(new Color(r, g, b)); } /// @@ -226,7 +226,7 @@ namespace ImageProcessor float g = (x * -0.9689F) + (y * 1.8758F) + (z * 0.0415F); float b = (x * 0.0557F) + (y * -0.2040F) + (z * 1.0570F); - return new Color(r, g, b); + return Color.Compress(new Color(r, g, b)); } /// diff --git a/src/ImageProcessor/Colors/Colorspaces/CieLab.cs b/src/ImageProcessor/Colors/Colorspaces/CieLab.cs index c1b64134d..d5875da07 100644 --- a/src/ImageProcessor/Colors/Colorspaces/CieLab.cs +++ b/src/ImageProcessor/Colors/Colorspaces/CieLab.cs @@ -79,6 +79,8 @@ namespace ImageProcessor public static implicit operator CieLab(Color color) { // First convert to CIE XYZ + color = Color.Expand(color); + float x = (color.R * 0.4124F) + (color.G * 0.3576F) + (color.B * 0.1805F); float y = (color.R * 0.2126F) + (color.G * 0.7152F) + (color.B * 0.0722F); float z = (color.R * 0.0193F) + (color.G * 0.1192F) + (color.B * 0.9505F); diff --git a/src/ImageProcessor/Colors/Colorspaces/CieXyz.cs b/src/ImageProcessor/Colors/Colorspaces/CieXyz.cs index 8c609dc0d..ab63c868d 100644 --- a/src/ImageProcessor/Colors/Colorspaces/CieXyz.cs +++ b/src/ImageProcessor/Colors/Colorspaces/CieXyz.cs @@ -79,6 +79,8 @@ namespace ImageProcessor /// public static implicit operator CieXyz(Color color) { + color = Color.Expand(color); + float x = (color.R * 0.4124F) + (color.G * 0.3576F) + (color.B * 0.1805F); float y = (color.R * 0.2126F) + (color.G * 0.7152F) + (color.B * 0.0722F); float z = (color.R * 0.0193F) + (color.G * 0.1192F) + (color.B * 0.9505F); diff --git a/src/ImageProcessor/Filters/Brightness.cs b/src/ImageProcessor/Filters/Brightness.cs index 08165037c..6a5ae3985 100644 --- a/src/ImageProcessor/Filters/Brightness.cs +++ b/src/ImageProcessor/Filters/Brightness.cs @@ -50,12 +50,12 @@ namespace ImageProcessor.Filters { for (int x = startX; x < endX; x++) { - Color color = source[x, y]; + Color color = Color.Expand(source[x, y]); Vector3 vector3 = color.ToVector3(); vector3 += new Vector3(brightness); - target[x, y] = new Color(vector3, color.A); + target[x, y] = Color.Compress(new Color(vector3, color.A)); } } }); diff --git a/src/ImageProcessor/Filters/ColorMatrix/ColorMatrixFilter.cs b/src/ImageProcessor/Filters/ColorMatrix/ColorMatrixFilter.cs index 396d5cda1..d63732751 100644 --- a/src/ImageProcessor/Filters/ColorMatrix/ColorMatrixFilter.cs +++ b/src/ImageProcessor/Filters/ColorMatrix/ColorMatrixFilter.cs @@ -17,7 +17,7 @@ namespace ImageProcessor.Filters public abstract Matrix4x4 Matrix { get; } /// - public virtual bool Compand => false; + public virtual bool Compand => true; /// protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) @@ -57,11 +57,11 @@ namespace ImageProcessor.Filters if (compand) { - color = Color.Compress(color); + color = Color.Expand(color); } Vector3 transformed = Vector3.Transform(color.ToVector3(), matrix); - return compand ? Color.Expand(new Color(transformed, color.A)) : new Color(transformed, color.A); + return compand ? Color.Compress(new Color(transformed, color.A)) : new Color(transformed, color.A); } } } diff --git a/src/ImageProcessor/Filters/ColorMatrix/Hue.cs b/src/ImageProcessor/Filters/ColorMatrix/Hue.cs index 9acf9e3bb..a77f6ff09 100644 --- a/src/ImageProcessor/Filters/ColorMatrix/Hue.cs +++ b/src/ImageProcessor/Filters/ColorMatrix/Hue.cs @@ -37,7 +37,7 @@ public override Matrix4x4 Matrix => this.matrix; /// - public override bool Compand => true; + public override bool Compand => false; /// protected override void OnApply(ImageBase source, ImageBase target, Rectangle targetRectangle, Rectangle sourceRectangle) diff --git a/src/ImageProcessor/Filters/ColorMatrix/Sepia.cs b/src/ImageProcessor/Filters/ColorMatrix/Sepia.cs index db5020271..cab932b25 100644 --- a/src/ImageProcessor/Filters/ColorMatrix/Sepia.cs +++ b/src/ImageProcessor/Filters/ColorMatrix/Sepia.cs @@ -28,6 +28,6 @@ namespace ImageProcessor.Filters }; /// - public override bool Compand => true; + public override bool Compand => false; } } diff --git a/src/ImageProcessor/Filters/Contrast.cs b/src/ImageProcessor/Filters/Contrast.cs index 97216f4cc..da55507ff 100644 --- a/src/ImageProcessor/Filters/Contrast.cs +++ b/src/ImageProcessor/Filters/Contrast.cs @@ -51,11 +51,11 @@ namespace ImageProcessor.Filters { for (int x = startX; x < endX; x++) { - Vector4 color = source[x, y].ToVector4(); + Vector4 color = Color.Expand(source[x, y]).ToVector4(); color -= shiftVector; color *= contrastVector; color += shiftVector; - target[x, y] = new Color(color); + target[x, y] = Color.Compress(new Color(color)); } } }); diff --git a/src/ImageProcessor/Formats/Bmp/BmpDecoderCore.cs b/src/ImageProcessor/Formats/Bmp/BmpDecoderCore.cs index e058d48f0..c11f2d7c7 100644 --- a/src/ImageProcessor/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageProcessor/Formats/Bmp/BmpDecoderCore.cs @@ -7,7 +7,6 @@ namespace ImageProcessor.Formats { using System; using System.IO; - using System.Numerics; using System.Threading.Tasks; /// @@ -224,17 +223,11 @@ namespace ImageProcessor.Formats int arrayOffset = ((row * width) + (colOffset + shift)) * 4; // We divide by 255 as we will store the colors in our floating point format. - // Default colorspace is sRGB TODO: Check if we can detect this. // Stored in r-> g-> b-> a order. - // Expand from sRGB to linear RGB - Color color = - Color.Expand( - new Color(new Vector3(colors[colorIndex + 2], colors[colorIndex + 1], colors[colorIndex]) / 255f)); - - imageData[arrayOffset] = color.R; // r - imageData[arrayOffset + 1] = color.G; // g - imageData[arrayOffset + 2] = color.B; // b - imageData[arrayOffset + 3] = color.A; // a + imageData[arrayOffset] = colors[colorIndex + 2] / 255f; // r + imageData[arrayOffset + 1] = colors[colorIndex + 1] / 255f; // g + imageData[arrayOffset + 2] = colors[colorIndex] / 255f; // b + imageData[arrayOffset + 3] = 1; // a } } }); @@ -277,14 +270,11 @@ namespace ImageProcessor.Formats int arrayOffset = ((row * width) + x) * 4; - // Expand from sRGB to linear RGB - Color color = Color.Expand(new Color(r, g, b, 1)); - // Stored in r-> g-> b-> a order. - imageData[arrayOffset] = color.R; - imageData[arrayOffset + 1] = color.G; - imageData[arrayOffset + 2] = color.B; - imageData[arrayOffset + 3] = color.A; + imageData[arrayOffset] = r; + imageData[arrayOffset + 1] = g; + imageData[arrayOffset + 2] = b; + imageData[arrayOffset + 3] = 1; } }); } @@ -315,15 +305,12 @@ namespace ImageProcessor.Formats int offset = rowOffset + (x * 3); int arrayOffset = ((row * width) + x) * 4; - // Expand from sRGB to linear RGB - Color color = Color.Expand(new Color(new Vector3(data[offset + 2], data[offset + 1], data[offset]) / 255f, 1)); - // We divide by 255 as we will store the colors in our floating point format. // Stored in r-> g-> b-> a order. - imageData[arrayOffset] = color.R; - imageData[arrayOffset + 1] = color.G; - imageData[arrayOffset + 2] = color.B; - imageData[arrayOffset + 3] = color.A; + imageData[arrayOffset] = data[offset + 2] / 255f; + imageData[arrayOffset + 1] = data[offset + 1] / 255f; + imageData[arrayOffset + 2] = data[offset] / 255f; + imageData[arrayOffset + 3] = 1; } }); } @@ -356,15 +343,10 @@ namespace ImageProcessor.Formats // We divide by 255 as we will store the colors in our floating point format. // Stored in r-> g-> b-> a order. - - // Expand from sRGB to linear RGB - // TODO: Can we use our real alpha here? - Color color = Color.Expand(new Color(new Vector3(data[offset + 2], data[offset + 1], data[offset]) / 255f, 1)); - - imageData[arrayOffset] = color.R; - imageData[arrayOffset + 1] = color.G; - imageData[arrayOffset + 2] = color.B; - imageData[arrayOffset + 3] = color.A; + imageData[arrayOffset] = data[offset + 2] / 255f; + imageData[arrayOffset + 1] = data[offset + 1] / 255f; + imageData[arrayOffset + 2] = data[offset] / 255f; + imageData[arrayOffset + 3] = 1; // TODO: Can we use our real alpha here? } }); } diff --git a/src/ImageProcessor/Formats/Bmp/BmpEncoder.cs b/src/ImageProcessor/Formats/Bmp/BmpEncoder.cs index cd955612c..ad80bbc76 100644 --- a/src/ImageProcessor/Formats/Bmp/BmpEncoder.cs +++ b/src/ImageProcessor/Formats/Bmp/BmpEncoder.cs @@ -110,13 +110,13 @@ namespace ImageProcessor.Formats // Limit the output range and multiply out from our floating point. // Convert back to b-> g-> r-> a order. - // Convert to non-premultiplied sRGB color. + // Convert to non-premultiplied color. float r = data[offset]; float g = data[offset + 1]; float b = data[offset + 2]; float a = data[offset + 3]; - Bgra32 color = Color.ToNonPremultiplied(Color.Compress(new Color(r, g, b, a))); + Bgra32 color = Color.ToNonPremultiplied(new Color(r, g, b, a)); writer.Write(color.B); writer.Write(color.G); diff --git a/src/ImageProcessor/Formats/Jpg/JpegDecoder.cs b/src/ImageProcessor/Formats/Jpg/JpegDecoder.cs index 6ffcafe06..2f456dfc0 100644 --- a/src/ImageProcessor/Formats/Jpg/JpegDecoder.cs +++ b/src/ImageProcessor/Formats/Jpg/JpegDecoder.cs @@ -7,7 +7,6 @@ namespace ImageProcessor.Formats { using System; using System.IO; - using System.Numerics; using System.Threading.Tasks; using BitMiracle.LibJpeg; @@ -118,14 +117,10 @@ namespace ImageProcessor.Formats int offset = ((y * pixelWidth) + x) * 4; - // Expand from sRGB to linear RGB - Color color = - Color.Expand(new Color(new Vector3(sample[0], sample[1], sample[2]) / 255f)); - - pixels[offset + 0] = color.R; - pixels[offset + 1] = color.G; - pixels[offset + 2] = color.B; - pixels[offset + 3] = color.A; + pixels[offset + 0] = sample[0] / 255f; + pixels[offset + 1] = sample[1] / 255f; + pixels[offset + 2] = sample[2] / 255f; + pixels[offset + 3] = 1; } }); } @@ -144,14 +139,10 @@ namespace ImageProcessor.Formats int offset = ((y * pixelWidth) + x) * 4; - // Expand from sRGB to linear RGB - Color color = - Color.Expand(new Color(new Vector3(sample[0], sample[0], sample[0]) / 255f)); - - pixels[offset + 0] = color.R; - pixels[offset + 1] = color.G; - pixels[offset + 2] = color.B; - pixels[offset + 3] = color.A; + pixels[offset + 0] = sample[0] / 255f; + pixels[offset + 1] = sample[0] / 255f; + pixels[offset + 2] = sample[0] / 255f; + pixels[offset + 3] = 1; } }); } diff --git a/src/ImageProcessor/Formats/Jpg/JpegEncoder.cs b/src/ImageProcessor/Formats/Jpg/JpegEncoder.cs index 9958d6e63..0517b422c 100644 --- a/src/ImageProcessor/Formats/Jpg/JpegEncoder.cs +++ b/src/ImageProcessor/Formats/Jpg/JpegEncoder.cs @@ -111,8 +111,7 @@ namespace ImageProcessor.Formats float b = sourcePixels[source + 2]; float a = sourcePixels[source + 3]; - // Compress back to sRGB - Bgra32 color = Color.ToNonPremultiplied(Color.Compress(new Color(r, g, b, a))); + Bgra32 color = Color.ToNonPremultiplied(new Color(r, g, b, a)); samples[start] = color.R; samples[start + 1] = color.G; diff --git a/src/ImageProcessor/Samplers/Resampler.cs b/src/ImageProcessor/Samplers/Resampler.cs index 22bc7b57c..4fd105f16 100644 --- a/src/ImageProcessor/Samplers/Resampler.cs +++ b/src/ImageProcessor/Samplers/Resampler.cs @@ -193,11 +193,12 @@ namespace ImageProcessor.Samplers foreach (Weight xw in horizontalValues) { int originX = xw.Index; - Color sourceColor = source[originX, originY]; + Color sourceColor = Color.Expand(source[originX, originY]); destination += sourceColor * yw.Value * xw.Value; } } + destination = Color.Compress(destination); target[x, y] = destination; } } @@ -301,12 +302,13 @@ namespace ImageProcessor.Samplers if (sourceRectangle.Contains(rotated.X, rotated.Y)) { - Color sourceColor = source[rotated.X, rotated.Y]; + Color sourceColor = Color.Expand(source[rotated.X, rotated.Y]); destination += sourceColor * yw.Value * xw.Value; } } } + destination = Color.Compress(destination); target[x, y] = destination; } }