/// <summary>
///     Helper methods for verifying image content types by validating the first bytes of the file.
///     You can extend this class by adding additional XxxFirstBytes constants and IsXxx methods.
/// </summary>
public static class ImageHelper
{
    // These are the first three bytes of a JPEG, usually enough to determine if the file is an image/jpeg
    private static readonly byte[] JpegFirstBytes = new byte[] { 0xFF, 0xD8, 0xFF };

    //
    // More specific headers. Note that the 5th and 6th byte should be ignored.
    // The second pair and final five bytes is the application marker. The final byte should
    // always be 0x00 to terminate the JPEG header.
    //
    // JIFF, regular
    // new byte[] { 0xFF, 0xD8, 0xFF, 0xE0, 0x00, 0x00, 0x4A, 0x46, 0x49, 0x46, 0x00 }
    //
    // EXIF, Canon Digital Cameras
    // new byte[] { 0xFF, 0xD8, 0xFF, 0xE1, 0x00, 0x00, 0x45, 0x78, 0x69, 0x66, 0x00 }
    // 

    /// <summary>
    ///     Verify that the byte array matches a JPEG sequence. The first three bytes are enough.
    /// </summary>
    /// <param name="bytes">The byte array to verify.</param>
    /// <returns>True if the data matches a JPEG header, otherwise false.</returns>
    public static bool IsJpeg(byte[] bytes)
    {
        return VerifyBytes(bytes, JpegFirstBytes);
    }

    private static bool VerifyBytes(IList<byte> bytes, IList<byte> controlBytes)
    {
        // Do we have any data?
        if (bytes == null || bytes.Count < controlBytes.Count) return false;

        var xorSum = 0;

        for (var i = 0; i < controlBytes.Count && xorSum == 0; i += 1)
            // Use bitwise XOR to make sure the bytes match our array
            xorSum += bytes[i] ^ controlBytes[i];

        // Since we used XOR, sum should be zero if this is a JPEG
        return xorSum == 0;
    }
}