//
// Copyright (c) James South and contributors.
// Licensed under the Apache License, Version 2.0.
//
namespace ImageProcessor.Formats
{
using System;
using System.IO;
using BitMiracle.LibJpeg;
///
/// Image decoder for generating an image out of a jpg stream.
///
public class JpegDecoder : IImageDecoder
{
///
/// Gets the size of the header for this image type.
///
/// The size of the header.
public int HeaderSize => 11;
///
/// Indicates if the image decoder supports the specified
/// file extension.
///
/// The file extension.
///
/// true, if the decoder supports the specified
/// extensions; otherwise false.
///
///
/// is null (Nothing in Visual Basic).
/// is a string
/// of length zero or contains only blanks.
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);
}
///
/// Indicates if the image decoder supports the specified
/// file header.
///
/// The file header.
///
/// true, if the decoder supports the specified
/// file header; otherwise false.
///
///
/// is null (Nothing in Visual Basic).
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;
}
///
/// Decodes the image from the specified stream and sets
/// the data to image.
///
/// The image, where the data should be set to.
/// Cannot be null (Nothing in Visual Basic).
/// The stream, where the image should be
/// decoded from. Cannot be null (Nothing in Visual Basic).
///
/// is null (Nothing in Visual Basic).
/// - or -
/// is null (Nothing in Visual Basic).
///
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);
}
///
///
///
///
///
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;
}
}
}