From d35803fcdf1fd4a1426c081764c5dfa2cc45fc42 Mon Sep 17 00:00:00 2001 From: James South Date: Mon, 4 May 2015 16:01:04 +0100 Subject: [PATCH] Enable jpeg Former-commit-id: 40d6b11321e75d800299ed93368cc629411692af Former-commit-id: fe1ce463f33c93ef092b9bb9652128851e4130bf Former-commit-id: 1420fe512ea88a7b4f02cf5cbc327e6ddc04a2bd --- src/ImageProcessor/Formats/Gif/GifDecoder.cs | 8 +- src/ImageProcessor/Formats/Jpg/JpegDecoder.cs | 29 +- src/ImageProcessor/Formats/Jpg/JpegEncoder.cs | 36 +-- .../LibJpeg/Classic/Internal/my_upsampler.cs | 2 +- .../Jpg/LibJpeg/DecompressorToJpegImage.cs | 82 ++++-- .../Jpg/LibJpeg/IDecompressDestination.cs | 217 ++------------ .../Jpg/LibJpeg/LoadedImageAttributes.cs | 274 ++++++++++++++++++ src/ImageProcessor/Image.cs | 22 +- src/ImageProcessor/ImageProcessor.csproj | 78 +++++ .../ImageProcessor.csproj.DotSettings | 1 + .../Formats/EncoderDecoderTests.cs | 6 +- .../TestImages/Formats/Jpg/Backdrop.jpg | 3 + 12 files changed, 477 insertions(+), 281 deletions(-) create mode 100644 src/ImageProcessor/Formats/Jpg/LibJpeg/LoadedImageAttributes.cs create mode 100644 tests/ImageProcessor.Tests/TestImages/Formats/Jpg/Backdrop.jpg diff --git a/src/ImageProcessor/Formats/Gif/GifDecoder.cs b/src/ImageProcessor/Formats/Gif/GifDecoder.cs index 5779d7ff9..00c59db84 100644 --- a/src/ImageProcessor/Formats/Gif/GifDecoder.cs +++ b/src/ImageProcessor/Formats/Gif/GifDecoder.cs @@ -22,13 +22,7 @@ namespace ImageProcessor.Formats /// Gets the size of the header for this image type. /// /// The size of the header. - public int HeaderSize - { - get - { - return 6; - } - } + public int HeaderSize => 6; /// /// Returns a value indicating whether the supports the specified diff --git a/src/ImageProcessor/Formats/Jpg/JpegDecoder.cs b/src/ImageProcessor/Formats/Jpg/JpegDecoder.cs index 9fcb1fc49..3e9663665 100644 --- a/src/ImageProcessor/Formats/Jpg/JpegDecoder.cs +++ b/src/ImageProcessor/Formats/Jpg/JpegDecoder.cs @@ -1,10 +1,12 @@ -// =============================================================================== -// JpegDecoder.cs -// .NET Image Tools -// =============================================================================== -// Copyright (c) .NET Image Tools Development Group. -// All rights reserved. -// =============================================================================== +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright © James South and contributors. +// Licensed under the Apache License, Version 2.0. +// +// +// Image decoder for generating an image out of a jpg stream. +// +// -------------------------------------------------------------------------------------------------------------------- namespace ImageProcessor.Formats { @@ -13,20 +15,15 @@ namespace ImageProcessor.Formats using BitMiracle.LibJpeg; /// - /// Image decoder for generating an image out of an jpg stream. + /// Image decoder for generating an image out of a jpg stream. /// public class JpegDecoder : IImageDecoder { - #region IImageDecoder Members - /// /// Gets the size of the header for this image type. /// /// The size of the header. - public int HeaderSize - { - get { return 11; } - } + public int HeaderSize => 11; /// /// Indicates if the image decoder supports the specified @@ -145,13 +142,11 @@ namespace ImageProcessor.Formats pixels[offset + 0] = (byte)sample[2]; pixels[offset + 1] = (byte)sample[1]; pixels[offset + 2] = (byte)sample[0]; - pixels[offset + 3] = (byte)255; + pixels[offset + 3] = 255; } } image.SetPixels(pixelWidth, pixelHeight, pixels); } - - #endregion } } diff --git a/src/ImageProcessor/Formats/Jpg/JpegEncoder.cs b/src/ImageProcessor/Formats/Jpg/JpegEncoder.cs index 03a395aad..c816e279e 100644 --- a/src/ImageProcessor/Formats/Jpg/JpegEncoder.cs +++ b/src/ImageProcessor/Formats/Jpg/JpegEncoder.cs @@ -1,11 +1,12 @@ -// =============================================================================== -// JpegEncoder.cs -// .NET Image Tools -// =============================================================================== -// Copyright (c) .NET Image Tools Development Group. -// All rights reserved. -// =============================================================================== - +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright © James South and contributors. +// Licensed under the Apache License, Version 2.0. +// +// +// Encoder for writing the data image to a stream in jpg format. +// +// -------------------------------------------------------------------------------------------------------------------- namespace ImageProcessor.Formats { @@ -19,9 +20,7 @@ namespace ImageProcessor.Formats /// public class JpegEncoder : IImageEncoder { - #region Properties - - private int _quality = 100; + private int quality = 100; /// /// Gets or sets the quality, that will be used to encode the image. Quality /// index must be between 0 and 100 (compression from max to min). @@ -29,22 +28,15 @@ namespace ImageProcessor.Formats /// The quality of the jpg image from 0 to 100. public int Quality { - get { return _quality; } - set { _quality = value; } + get { return this.quality; } + set { this.quality = value.Clamp(1, 100); } } - #endregion - - #region IImageEncoder Members - /// /// Gets the default file extension for this encoder. /// /// The default file extension for this encoder. - public string Extension - { - get { return "JPG"; } - } + public string Extension => "JPG"; /// /// Indicates if the image encoder supports the specified @@ -114,7 +106,5 @@ namespace ImageProcessor.Formats JpegImage jpg = new JpegImage(rows, Colorspace.RGB); jpg.WriteJpeg(stream, new CompressionParameters { Quality = this.Quality }); } - - #endregion } } diff --git a/src/ImageProcessor/Formats/Jpg/LibJpeg/Classic/Internal/my_upsampler.cs b/src/ImageProcessor/Formats/Jpg/LibJpeg/Classic/Internal/my_upsampler.cs index 81aaa7ed6..adae0897f 100644 --- a/src/ImageProcessor/Formats/Jpg/LibJpeg/Classic/Internal/my_upsampler.cs +++ b/src/ImageProcessor/Formats/Jpg/LibJpeg/Classic/Internal/my_upsampler.cs @@ -347,7 +347,7 @@ namespace BitMiracle.LibJpeg.Classic.Internal int row = m_upsampleRowOffset + inrow; int outIndex = 0; - for (int col = 0; col < m_cinfo.m_output_width; col++) + for (int col = 0; outIndex < m_cinfo.m_output_width; col++) { byte invalue = input_data[row][col]; /* don't need GETJSAMPLE() here */ output_data[inrow][outIndex] = invalue; diff --git a/src/ImageProcessor/Formats/Jpg/LibJpeg/DecompressorToJpegImage.cs b/src/ImageProcessor/Formats/Jpg/LibJpeg/DecompressorToJpegImage.cs index 83a07ba51..79ab054db 100644 --- a/src/ImageProcessor/Formats/Jpg/LibJpeg/DecompressorToJpegImage.cs +++ b/src/ImageProcessor/Formats/Jpg/LibJpeg/DecompressorToJpegImage.cs @@ -1,30 +1,54 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; -using Nine.Imaging; +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright © James South and contributors. +// Licensed under the Apache License, Version 2.0. +// +// +// Decompresses a jpeg image. +// +// -------------------------------------------------------------------------------------------------------------------- namespace BitMiracle.LibJpeg { + using System; + using System.IO; + using ImageProcessor; - class DecompressorToJpegImage : IDecompressDestination + /// + /// Decompresses a jpeg image. + /// + internal class DecompressorToJpegImage : IDecompressDestination { - private JpegImage m_jpegImage; + /// + /// The jpeg image. + /// + private readonly JpegImage jpegImage; + /// + /// Initializes a new instance of the class. + /// + /// + /// The jpeg image. + /// internal DecompressorToJpegImage(JpegImage jpegImage) { - m_jpegImage = jpegImage; + this.jpegImage = jpegImage; } - public Stream Output - { - get - { - return null; - } - } + /// + /// Gets the stream with decompressed data. + /// + public Stream Output => null; + /// + /// Sets the image attributes. + /// + /// + /// The containing attributes. + /// + /// + /// public void SetImageAttributes(LoadedImageAttributes parameters) { if (parameters.Width > ImageBase.MaxWidth || parameters.Height > ImageBase.MaxHeight) @@ -33,23 +57,37 @@ namespace BitMiracle.LibJpeg $"The input jpg '{ parameters.Width }x{ parameters.Height }' is bigger then the max allowed size '{ ImageBase.MaxWidth }x{ ImageBase.MaxHeight }'"); } - m_jpegImage.Width = parameters.Width; - m_jpegImage.Height = parameters.Height; - m_jpegImage.BitsPerComponent = 8; - m_jpegImage.ComponentsPerSample = (byte)parameters.ComponentsPerSample; - m_jpegImage.Colorspace = parameters.Colorspace; + this.jpegImage.Width = parameters.Width; + this.jpegImage.Height = parameters.Height; + this.jpegImage.BitsPerComponent = 8; + this.jpegImage.ComponentsPerSample = (byte)parameters.ComponentsPerSample; + this.jpegImage.Colorspace = parameters.Colorspace; } + /// + /// Begins writing. + /// + /// Not implemented. public void BeginWrite() { } + /// + /// Processes the given row of pixels. + /// + /// + /// The representing the row. + /// public void ProcessPixelsRow(byte[] row) { - SampleRow samplesRow = new SampleRow(row, m_jpegImage.Width, m_jpegImage.BitsPerComponent, m_jpegImage.ComponentsPerSample); - m_jpegImage.addSampleRow(samplesRow); + SampleRow samplesRow = new SampleRow(row, this.jpegImage.Width, this.jpegImage.BitsPerComponent, this.jpegImage.ComponentsPerSample); + this.jpegImage.addSampleRow(samplesRow); } + /// + /// Ends write. + /// + /// Not implemented. public void EndWrite() { } diff --git a/src/ImageProcessor/Formats/Jpg/LibJpeg/IDecompressDestination.cs b/src/ImageProcessor/Formats/Jpg/LibJpeg/IDecompressDestination.cs index 26f8daafc..1e6cd859b 100644 --- a/src/ImageProcessor/Formats/Jpg/LibJpeg/IDecompressDestination.cs +++ b/src/ImageProcessor/Formats/Jpg/LibJpeg/IDecompressDestination.cs @@ -1,19 +1,21 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; - -using BitMiracle.LibJpeg.Classic; +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright © James South and contributors. +// Licensed under the Apache License, Version 2.0. +// +// -------------------------------------------------------------------------------------------------------------------- namespace BitMiracle.LibJpeg { + using System.IO; + /// /// Common interface for processing of decompression. /// - interface IDecompressDestination + internal interface IDecompressDestination { /// - /// Strean with decompressed data + /// Gets the stream with decompressed data. /// Stream Output { @@ -21,208 +23,29 @@ namespace BitMiracle.LibJpeg } /// - /// Implementor of this interface should process image properties received from decompressor. + /// Sets the image attributes. /// - /// Image properties + /// + /// The containing attributes. + /// void SetImageAttributes(LoadedImageAttributes parameters); /// - /// Called before decompression + /// Begins writing. Called before decompression /// void BeginWrite(); /// - /// It called during decompression - pass row of pixels from JPEG + /// Processes the given row of pixels. /// - /// + /// + /// The representing the row. + /// void ProcessPixelsRow(byte[] row); /// - /// Called after decompression + /// Ends writing. Called after decompression /// void EndWrite(); } - - /// - /// Holds parameters of image for decompression (IDecomressDesination) - /// - class LoadedImageAttributes - { - private Colorspace m_colorspace; - private bool m_quantizeColors; - private int m_width; - private int m_height; - private int m_componentsPerSample; - private int m_components; - private int m_actualNumberOfColors; - private byte[][] m_colormap; - private DensityUnit m_densityUnit; - private int m_densityX; - private int m_densityY; - - /* Decompression processing parameters --- these fields must be set before - * calling jpeg_start_decompress(). Note that jpeg_read_header() initializes - * them to default values. - */ - - // colorspace for output - public Colorspace Colorspace - { - get - { - return m_colorspace; - } - internal set - { - m_colorspace = value; - } - } - - // true=colormapped output wanted - public bool QuantizeColors - { - get - { - return m_quantizeColors; - } - internal set - { - m_quantizeColors = value; - } - } - - /* Description of actual output image that will be returned to application. - * These fields are computed by jpeg_start_decompress(). - * You can also use jpeg_calc_output_dimensions() to determine these values - * in advance of calling jpeg_start_decompress(). - */ - - // scaled image width - public int Width - { - get - { - return m_width; - } - internal set - { - m_width = value; - } - } - - // scaled image height - public int Height - { - get - { - return m_height; - } - internal set - { - m_height = value; - } - } - - // # of color components in out_color_space - public int ComponentsPerSample - { - get - { - return m_componentsPerSample; - } - internal set - { - m_componentsPerSample = value; - } - } - - // # of color components returned. it is 1 (a colormap index) when - // quantizing colors; otherwise it equals out_color_components. - public int Components - { - get - { - return m_components; - } - internal set - { - m_components = value; - } - } - - /* When quantizing colors, the output colormap is described by these fields. - * The application can supply a colormap by setting colormap non-null before - * calling jpeg_start_decompress; otherwise a colormap is created during - * jpeg_start_decompress or jpeg_start_output. - * The map has out_color_components rows and actual_number_of_colors columns. - */ - - // number of entries in use - public int ActualNumberOfColors - { - get - { - return m_actualNumberOfColors; - } - internal set - { - m_actualNumberOfColors = value; - } - } - - // The color map as a 2-D pixel array - public byte[][] Colormap - { - get - { - return m_colormap; - } - internal set - { - m_colormap = value; - } - } - - // These fields record data obtained from optional markers - // recognized by the JPEG library. - - // JFIF code for pixel size units - public DensityUnit DensityUnit - { - get - { - return m_densityUnit; - } - internal set - { - m_densityUnit = value; - } - } - - // Horizontal pixel density - public int DensityX - { - get - { - return m_densityX; - } - internal set - { - m_densityX = value; - } - } - - // Vertical pixel density - public int DensityY - { - get - { - return m_densityY; - } - internal set - { - m_densityY = value; - } - } - } } diff --git a/src/ImageProcessor/Formats/Jpg/LibJpeg/LoadedImageAttributes.cs b/src/ImageProcessor/Formats/Jpg/LibJpeg/LoadedImageAttributes.cs new file mode 100644 index 000000000..17bf0de93 --- /dev/null +++ b/src/ImageProcessor/Formats/Jpg/LibJpeg/LoadedImageAttributes.cs @@ -0,0 +1,274 @@ +namespace BitMiracle.LibJpeg +{ + using BitMiracle.LibJpeg.Classic; + + /// + /// Holds parameters of image for decompression (IDecomressDesination) + /// + class LoadedImageAttributes + { + /// + /// The m_colorspace. + /// + private Colorspace m_colorspace; + + /// + /// The m_quantize colors. + /// + private bool m_quantizeColors; + + /// + /// The m_width. + /// + private int m_width; + + /// + /// The m_height. + /// + private int m_height; + + /// + /// The m_components per sample. + /// + private int m_componentsPerSample; + + /// + /// The m_components. + /// + private int m_components; + + /// + /// The m_actual number of colors. + /// + private int m_actualNumberOfColors; + + /// + /// The m_colormap. + /// + private byte[][] m_colormap; + + /// + /// The m_density unit. + /// + private DensityUnit m_densityUnit; + + /// + /// The m_density x. + /// + private int m_densityX; + + /// + /// The m_density y. + /// + private int m_densityY; + + /* Decompression processing parameters --- these fields must be set before + * calling jpeg_start_decompress(). Note that jpeg_read_header() initializes + * them to default values. + */ + + // colorspace for output + /// + /// Gets the colorspace. + /// + public Colorspace Colorspace + { + get + { + return this.m_colorspace; + } + + internal set + { + this.m_colorspace = value; + } + } + + // true=colormapped output wanted + /// + /// Gets a value indicating whether quantize colors. + /// + public bool QuantizeColors + { + get + { + return this.m_quantizeColors; + } + + internal set + { + this.m_quantizeColors = value; + } + } + + /* Description of actual output image that will be returned to application. + * These fields are computed by jpeg_start_decompress(). + * You can also use jpeg_calc_output_dimensions() to determine these values + * in advance of calling jpeg_start_decompress(). + */ + + // scaled image width + /// + /// Gets the width. + /// + public int Width + { + get + { + return this.m_width; + } + + internal set + { + this.m_width = value; + } + } + + // scaled image height + /// + /// Gets the height. + /// + public int Height + { + get + { + return this.m_height; + } + + internal set + { + this.m_height = value; + } + } + + // # of color components in out_color_space + /// + /// Gets the components per sample. + /// + public int ComponentsPerSample + { + get + { + return this.m_componentsPerSample; + } + + internal set + { + this.m_componentsPerSample = value; + } + } + + // # of color components returned. it is 1 (a colormap index) when + // quantizing colors; otherwise it equals out_color_components. + /// + /// Gets the components. + /// + public int Components + { + get + { + return this.m_components; + } + + internal set + { + this.m_components = value; + } + } + + /* When quantizing colors, the output colormap is described by these fields. + * The application can supply a colormap by setting colormap non-null before + * calling jpeg_start_decompress; otherwise a colormap is created during + * jpeg_start_decompress or jpeg_start_output. + * The map has out_color_components rows and actual_number_of_colors columns. + */ + + // number of entries in use + /// + /// Gets the actual number of colors. + /// + public int ActualNumberOfColors + { + get + { + return this.m_actualNumberOfColors; + } + + internal set + { + this.m_actualNumberOfColors = value; + } + } + + // The color map as a 2-D pixel array + /// + /// Gets the colormap. + /// + public byte[][] Colormap + { + get + { + return this.m_colormap; + } + + internal set + { + this.m_colormap = value; + } + } + + // These fields record data obtained from optional markers + // recognized by the JPEG library. + + // JFIF code for pixel size units + /// + /// Gets the density unit. + /// + public DensityUnit DensityUnit + { + get + { + return this.m_densityUnit; + } + + internal set + { + this.m_densityUnit = value; + } + } + + // Horizontal pixel density + /// + /// Gets the density x. + /// + public int DensityX + { + get + { + return this.m_densityX; + } + + internal set + { + this.m_densityX = value; + } + } + + // Vertical pixel density + /// + /// Gets the density y. + /// + public int DensityY + { + get + { + return this.m_densityY; + } + + internal set + { + this.m_densityY = value; + } + } + } +} \ No newline at end of file diff --git a/src/ImageProcessor/Image.cs b/src/ImageProcessor/Image.cs index fe81e5f79..0e8113167 100644 --- a/src/ImageProcessor/Image.cs +++ b/src/ImageProcessor/Image.cs @@ -48,23 +48,23 @@ namespace ImageProcessor /// private static readonly Lazy> DefaultDecoders = new Lazy>(() => new List - { - new BmpDecoder(), - // new JpegDecoder(), - new PngDecoder(), - // new GifDecoder(), - }); + { + new BmpDecoder(), + new JpegDecoder(), + new PngDecoder(), + // new GifDecoder(), + }); /// /// The default collection of . /// private static readonly Lazy> DefaultEncoders = new Lazy>(() => new List - { - new BmpEncoder(), - // new JpegEncoder(), - new PngEncoder(), - }); + { + new BmpEncoder(), + new JpegEncoder(), + new PngEncoder() + }); /// /// Initializes a new instance of the class. diff --git a/src/ImageProcessor/ImageProcessor.csproj b/src/ImageProcessor/ImageProcessor.csproj index 9fb2db2dd..8ef33006e 100644 --- a/src/ImageProcessor/ImageProcessor.csproj +++ b/src/ImageProcessor/ImageProcessor.csproj @@ -56,6 +56,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -94,6 +171,7 @@ + diff --git a/src/ImageProcessor/ImageProcessor.csproj.DotSettings b/src/ImageProcessor/ImageProcessor.csproj.DotSettings index 36b7564a4..82abcd86d 100644 --- a/src/ImageProcessor/ImageProcessor.csproj.DotSettings +++ b/src/ImageProcessor/ImageProcessor.csproj.DotSettings @@ -9,5 +9,6 @@ True True True + True True True \ No newline at end of file diff --git a/tests/ImageProcessor.Tests/Formats/EncoderDecoderTests.cs b/tests/ImageProcessor.Tests/Formats/EncoderDecoderTests.cs index 5d561094c..fe9133b0f 100644 --- a/tests/ImageProcessor.Tests/Formats/EncoderDecoderTests.cs +++ b/tests/ImageProcessor.Tests/Formats/EncoderDecoderTests.cs @@ -13,10 +13,10 @@ [Theory] //[InlineData("TestImages/Car.bmp")] //[InlineData("TestImages/Portrait.png")] - //[InlineData("TestImages/Backdrop.jpg")] + [InlineData("../../TestImages/Formats/Jpg/Backdrop.jpg")] //[InlineData("TestImages/Windmill.gif")] - [InlineData("../../TestImages/Formats/Bmp/Car.bmp")] - [InlineData("../../TestImages/Formats/Png/cmyk.png")] + //[InlineData("../../TestImages/Formats/Bmp/Car.bmp")] + //[InlineData("../../TestImages/Formats/Png/cmyk.png")] public void DecodeThenEncodeImageFromStreamShouldSucceed(string filename) { if (!Directory.Exists("Encoded")) diff --git a/tests/ImageProcessor.Tests/TestImages/Formats/Jpg/Backdrop.jpg b/tests/ImageProcessor.Tests/TestImages/Formats/Jpg/Backdrop.jpg new file mode 100644 index 000000000..94c60daf3 --- /dev/null +++ b/tests/ImageProcessor.Tests/TestImages/Formats/Jpg/Backdrop.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:048c66eb1d5257d36319da28ca24837429e0604682e4ebb74778175fbbb18db9 +size 49595