📷 A modern, cross-platform, 2D Graphics library for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

156 lines
5.3 KiB

// <copyright file="JpegDecoder.cs" company="James South">
// Copyright (c) James South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessor.Formats
{
using System;
using System.IO;
using BitMiracle.LibJpeg;
/// <summary>
/// Image decoder for generating an image out of a jpg stream.
/// </summary>
public class JpegDecoder : IImageDecoder
{
/// <summary>
/// Gets the size of the header for this image type.
/// </summary>
/// <value>The size of the header.</value>
public int HeaderSize => 11;
/// <summary>
/// Indicates if the image decoder supports the specified
/// file extension.
/// </summary>
/// <param name="extension">The file extension.</param>
/// <returns>
/// <c>true</c>, if the decoder supports the specified
/// extensions; otherwise <c>false</c>.
/// </returns>
/// <exception cref="System.ArgumentNullException"><paramref name="extension"/>
/// is null (Nothing in Visual Basic).</exception>
/// <exception cref="System.ArgumentException"><paramref name="extension"/> is a string
/// of length zero or contains only blanks.</exception>
public bool IsSupportedFileExtension(string extension)
{
Guard.NotNullOrEmpty(extension, "extension");
if (extension.StartsWith("."))
{
extension = extension.Substring(1);
}
return extension.Equals("JPG", StringComparison.OrdinalIgnoreCase) ||
extension.Equals("JPEG", StringComparison.OrdinalIgnoreCase) ||
extension.Equals("JFIF", StringComparison.OrdinalIgnoreCase);
}
/// <summary>
/// Indicates if the image decoder supports the specified
/// file header.
/// </summary>
/// <param name="header">The file header.</param>
/// <returns>
/// <c>true</c>, if the decoder supports the specified
/// file header; otherwise <c>false</c>.
/// </returns>
/// <exception cref="System.ArgumentNullException"><paramref name="header"/>
/// is null (Nothing in Visual Basic).</exception>
public bool IsSupportedFileFormat(byte[] header)
{
Guard.NotNull(header, "header");
bool isSupported = false;
if (header.Length >= 11)
{
bool isJpeg = IsJpeg(header);
bool isExif = this.IsExif(header);
isSupported = isJpeg || isExif;
}
return isSupported;
}
/// <summary>
/// Decodes the image from the specified stream and sets
/// the data to image.
/// </summary>
/// <param name="image">The image, where the data should be set to.
/// Cannot be null (Nothing in Visual Basic).</param>
/// <param name="stream">The stream, where the image should be
/// decoded from. Cannot be null (Nothing in Visual Basic).</param>
/// <exception cref="System.ArgumentNullException">
/// <para><paramref name="image"/> is null (Nothing in Visual Basic).</para>
/// <para>- or -</para>
/// <para><paramref name="stream"/> is null (Nothing in Visual Basic).</para>
/// </exception>
public void Decode(Image image, Stream stream)
{
Guard.NotNull(image, "image");
Guard.NotNull(stream, "stream");
JpegImage jpg = new JpegImage(stream);
int pixelWidth = jpg.Width;
int pixelHeight = jpg.Height;
byte[] pixels = new byte[pixelWidth * pixelHeight * 4];
if (!(jpg.Colorspace == Colorspace.RGB && jpg.BitsPerComponent == 8))
{
throw new NotSupportedException("JpegDecoder only support RGB color space.");
}
for (int y = 0; y < pixelHeight; y++)
{
SampleRow row = jpg.GetRow(y);
for (int x = 0; x < pixelWidth; x++)
{
Sample sample = row.GetAt(x);
int offset = ((y * pixelWidth) + x) * 4;
pixels[offset + 0] = (byte)sample[2];
pixels[offset + 1] = (byte)sample[1];
pixels[offset + 2] = (byte)sample[0];
pixels[offset + 3] = 255;
}
}
image.SetPixels(pixelWidth, pixelHeight, pixels);
}
/// <summary>
///
/// </summary>
/// <param name="header"></param>
/// <returns></returns>
private bool IsExif(byte[] header)
{
bool isExif =
header[6] == 0x45 && // E
header[7] == 0x78 && // x
header[8] == 0x69 && // i
header[9] == 0x66 && // f
header[10] == 0x00;
return isExif;
}
private static bool IsJpeg(byte[] header)
{
bool isJpg =
header[6] == 0x4A && // J
header[7] == 0x46 && // F
header[8] == 0x49 && // I
header[9] == 0x46 && // F
header[10] == 0x00;
return isJpg;
}
}
}