diff --git a/src/ImageSharp/Formats/Jpg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpg/JpegDecoderCore.cs index a362af7db..2f22a7ea9 100644 --- a/src/ImageSharp/Formats/Jpg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpg/JpegDecoderCore.cs @@ -1304,13 +1304,8 @@ namespace ImageSharp.Formats byte cb = this.ycbcrImage.CbChannel[co + (x / scale)]; byte cr = this.ycbcrImage.CrChannel[co + (x / scale)]; - // Implicit casting FTW - Color color = new YCbCr(yy, cb, cr); - int keyline = 255 - this.blackPixels[(y * this.blackStride) + x]; - Color final = new Cmyk(color.R / 255F, color.G / 255F, color.B / 255F, keyline / 255F); - TColor packed = default(TColor); - packed.PackFromBytes(final.R, final.G, final.B, final.A); + this.PackCmyk(ref packed, yy, cb, cr, x, y); pixels[x, y] = packed; } }); @@ -2126,6 +2121,42 @@ namespace ImageSharp.Formats packed.PackFromBytes(r, g, b, 255); } + /// + /// Optimized method to pack bytes to the image from the CMYK color space. + /// This is faster than implicit casting as it avoids double packing. + /// + /// The pixel format. + /// The packed format. uint, long, float. + /// The packed pixel. + /// The y luminance component. + /// The cb chroma component. + /// The cr chroma component. + /// The x-position within the image. + /// The y-position within the image. + private void PackCmyk(ref TColor packed, byte y, byte cb, byte cr, int xx, int yy) + where TColor : struct, IPackedPixel + where TPacked : struct + { + // TODO: We can speed this up further with Vector4 + int ccb = cb - 128; + int ccr = cr - 128; + + // First convert from YCbCr to CMY + float cyan = (y + (1.402F * ccr)).Clamp(0, 255) / 255F; + float magenta = (y - (0.34414F * ccb) - (0.71414F * ccr)).Clamp(0, 255) / 255F; + float yellow = (y + (1.772F * ccb)).Clamp(0, 255) / 255F; + + // Get keyline + float keyline = (255 - this.blackPixels[(yy * this.blackStride) + xx]) / 255F; + + // Convert back to RGB + byte r = (byte)(((1 - cyan) * (1 - keyline)).Clamp(0, 1) * 255); + byte g = (byte)(((1 - magenta) * (1 - keyline)).Clamp(0, 1) * 255); + byte b = (byte)(((1 - yellow) * (1 - keyline)).Clamp(0, 1) * 255); + + packed.PackFromBytes(r, g, b, 255); + } + /// /// Represents a component scan ///