Récupérer l’orientation Exif d’une photo à partir des bytes

admin

by Julien Gustin

June 24, 2018

0

Moi même ayant du chercher pendant des heures pour trouver comment récupérer les informations d’orientation d’une photo à partir des bytes et non à partir d’un filepath, je mets à contribution un petit bout de code qui permet de récupérer l’orientation d’une photo en alternative à ExifInterface.

Ce code n’est valable que pour la plateforme Android. J’ai trouvé un code natif Java Android que j’ai repris tel quel en le rendant compatible C#.

public class Exif
    {
        // Returns the degrees in clockwise. Values are 0, 90, 180, or 270.
        public static int getOrientation(byte[] jpeg)
        {
            if (jpeg == null)
            {
                return 0;
            }

            int offset = 0;
            int length = 0;

            // ISO/IEC 10918-1:1993(E)
            while (offset + 3 < jpeg.Length && (jpeg[offset++] & 0xFF) == 0xFF)
            {
                int marker = jpeg[offset] & 0xFF;

                // Check if the marker is a padding.
                if (marker == 0xFF)
                {
                    continue;
                }
                offset++;

                // Check if the marker is SOI or TEM.
                if (marker == 0xD8 || marker == 0x01)
                {
                    continue;
                }
                // Check if the marker is EOI or SOS.
                if (marker == 0xD9 || marker == 0xDA)
                {
                    break;
                }

                // Get the length and check if it is reasonable.
                length = pack(jpeg, offset, 2, false);
                if (length < 2 || offset + length > jpeg.Length)
                {
                    
                    return 0;
                }

                // Break if the marker is EXIF in APP1.
                if (marker == 0xE1 && length >= 8 &&
                        pack(jpeg, offset + 2, 4, false) == 0x45786966 &&
                        pack(jpeg, offset + 6, 2, false) == 0)
                {
                    offset += 8;
                    length -= 8;
                    break;
                }

                // Skip other markers.
                offset += length;
                length = 0;
            }

            // JEITA CP-3451 Exif Version 2.2
            if (length > 8)
            {
                // Identify the byte order.
                int tag = pack(jpeg, offset, 4, false);
                if (tag != 0x49492A00 && tag != 0x4D4D002A)
                {
                    Console.Write("Invalid byte order");
                    return 0;
                }
                Boolean littleEndian = (tag == 0x49492A00);

                // Get the offset and check if it is reasonable.
                int count = pack(jpeg, offset + 4, 4, littleEndian) + 2;
                if (count < 10 || count > length)
                {
                    Console.Write("Invalid offset");
                    return 0;
                }
                offset += count;
                length -= count;

                // Get the count and go through all the elements.
                count = pack(jpeg, offset - 2, 2, littleEndian);
                while (count-- > 0 && length >= 12)
                {
                    // Get the tag and check if it is orientation.
                    tag = pack(jpeg, offset, 2, littleEndian);
                    if (tag == 0x0112)
                    {
                        // We do not really care about type and count, do we?
                        int orientation = pack(jpeg, offset + 8, 2, littleEndian);
                        switch (orientation)
                        {
                            case 1:
                                return 0;
                            case 3:
                                return 180;
                            case 6:
                                return 90;
                            case 8:
                                return 270;
                        }
                        Console.Write("Unsupported orientation");
                        return 0;
                    }
                    offset += 12;
                    length -= 12;
                }
            }

            
            Console.Write("Orientation not found");
            return 0;
        }

        private static int pack(byte[] bytes, int offset, int length, Boolean littleEndian)
        {
            int step = 1;
            if (littleEndian)
            {
                offset += length - 1;
                step = -1;
            }

            int value = 0;
            while (length-- > 0)
            {
                value = (value << 8) | (bytes[offset] & 0xFF);
                offset += step;
            }
            return value;
        }
    }

Ensuite pour l’utilisation et faire une rotation d’une image, je procède comme ceci :

public async Task<byte[]> ExifRotateBitmap()
        {
            int rotationInDegrees = Exif.getOrientation(imageData);
            if (rotationInDegrees == 0)
            {
                return imageData;
            }

            using (var matrix = new Matrix())
            {
                matrix.PreRotate(rotationInDegrees);
                Bitmap bitmap = BitmapFactory.DecodeByteArray(imageData, 0, imageData.Length);
                bitmap = Bitmap.CreateBitmap(bitmap, 0, 0, bitmap.Width, bitmap.Height, matrix, true);
                byte[] bytes = await getBytesFromBitnamp(bitmap, 100);
                bitmap.Dispose();
                return bytes;
            }
        }

 

Leave a Reply

Your email address will not be published. Required fields are marked *

*

*

*