Frage

Gibt es eine kostengünstige Möglichkeit, die Abmessungen eines Bildes (jpg, png, ...) zu ermitteln?Vorzugsweise möchte ich dies erreichen, indem ich nur die Standardklassenbibliothek verwende (aufgrund von Hosting-Einschränkungen).Ich weiß, dass es relativ einfach sein sollte, den Bildkopf zu lesen und selbst zu analysieren, aber es scheint, dass so etwas bereits vorhanden sein sollte.Außerdem habe ich überprüft, dass der folgende Code das gesamte Bild liest (was ich nicht möchte):

using System;
using System.Drawing;

namespace Test
{
    class Program
    {
        static void Main(string[] args)
        {
            Image img = new Bitmap("test.png");
            System.Console.WriteLine(img.Width + " x " + img.Height);
        }
    }
}
War es hilfreich?

Lösung

Ihre beste Wette ist wie immer eine gut getestet Bibliothek zu finden. Allerdings haben Sie gesagt, ist schwierig, so ist hier etwas zwielichtiger weitgehend ungetestet Code, der für eine ganze Reihe von Fällen funktionieren soll:

using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;

namespace ImageDimensions
{
    public static class ImageHelper
    {
        const string errorMessage = "Could not recognize image format.";

        private static Dictionary<byte[], Func<BinaryReader, Size>> imageFormatDecoders = new Dictionary<byte[], Func<BinaryReader, Size>>()
        {
            { new byte[]{ 0x42, 0x4D }, DecodeBitmap},
            { new byte[]{ 0x47, 0x49, 0x46, 0x38, 0x37, 0x61 }, DecodeGif },
            { new byte[]{ 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 }, DecodeGif },
            { new byte[]{ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }, DecodePng },
            { new byte[]{ 0xff, 0xd8 }, DecodeJfif },
        };

        /// <summary>
        /// Gets the dimensions of an image.
        /// </summary>
        /// <param name="path">The path of the image to get the dimensions of.</param>
        /// <returns>The dimensions of the specified image.</returns>
        /// <exception cref="ArgumentException">The image was of an unrecognized format.</exception>
        public static Size GetDimensions(string path)
        {
            using (BinaryReader binaryReader = new BinaryReader(File.OpenRead(path)))
            {
                try
                {
                    return GetDimensions(binaryReader);
                }
                catch (ArgumentException e)
                {
                    if (e.Message.StartsWith(errorMessage))
                    {
                        throw new ArgumentException(errorMessage, "path", e);
                    }
                    else
                    {
                        throw e;
                    }
                }
            }
        }

        /// <summary>
        /// Gets the dimensions of an image.
        /// </summary>
        /// <param name="path">The path of the image to get the dimensions of.</param>
        /// <returns>The dimensions of the specified image.</returns>
        /// <exception cref="ArgumentException">The image was of an unrecognized format.</exception>    
        public static Size GetDimensions(BinaryReader binaryReader)
        {
            int maxMagicBytesLength = imageFormatDecoders.Keys.OrderByDescending(x => x.Length).First().Length;

            byte[] magicBytes = new byte[maxMagicBytesLength];

            for (int i = 0; i < maxMagicBytesLength; i += 1)
            {
                magicBytes[i] = binaryReader.ReadByte();

                foreach(var kvPair in imageFormatDecoders)
                {
                    if (magicBytes.StartsWith(kvPair.Key))
                    {
                        return kvPair.Value(binaryReader);
                    }
                }
            }

            throw new ArgumentException(errorMessage, "binaryReader");
        }

        private static bool StartsWith(this byte[] thisBytes, byte[] thatBytes)
        {
            for(int i = 0; i < thatBytes.Length; i+= 1)
            {
                if (thisBytes[i] != thatBytes[i])
                {
                    return false;
                }
            }
            return true;
        }

        private static short ReadLittleEndianInt16(this BinaryReader binaryReader)
        {
            byte[] bytes = new byte[sizeof(short)];
            for (int i = 0; i < sizeof(short); i += 1)
            {
                bytes[sizeof(short) - 1 - i] = binaryReader.ReadByte();
            }
            return BitConverter.ToInt16(bytes, 0);
        }

        private static int ReadLittleEndianInt32(this BinaryReader binaryReader)
        {
            byte[] bytes = new byte[sizeof(int)];
            for (int i = 0; i < sizeof(int); i += 1)
            {
                bytes[sizeof(int) - 1 - i] = binaryReader.ReadByte();
            }
            return BitConverter.ToInt32(bytes, 0);
        }

        private static Size DecodeBitmap(BinaryReader binaryReader)
        {
            binaryReader.ReadBytes(16);
            int width = binaryReader.ReadInt32();
            int height = binaryReader.ReadInt32();
            return new Size(width, height);
        }

        private static Size DecodeGif(BinaryReader binaryReader)
        {
            int width = binaryReader.ReadInt16();
            int height = binaryReader.ReadInt16();
            return new Size(width, height);
        }

        private static Size DecodePng(BinaryReader binaryReader)
        {
            binaryReader.ReadBytes(8);
            int width = binaryReader.ReadLittleEndianInt32();
            int height = binaryReader.ReadLittleEndianInt32();
            return new Size(width, height);
        }

        private static Size DecodeJfif(BinaryReader binaryReader)
        {
            while (binaryReader.ReadByte() == 0xff)
            {
                byte marker = binaryReader.ReadByte();
                short chunkLength = binaryReader.ReadLittleEndianInt16();

                if (marker == 0xc0)
                {
                    binaryReader.ReadByte();

                    int height = binaryReader.ReadLittleEndianInt16();
                    int width = binaryReader.ReadLittleEndianInt16();
                    return new Size(width, height);
                }

                binaryReader.ReadBytes(chunkLength - 2);
            }

            throw new ArgumentException(errorMessage);
        }
    }
}

Hoffentlich ist der Code ziemlich offensichtlich. So fügen Sie eine neue Datei-Format Sie es in den imageFormatDecoders mit der Taste ein Array der „magischen Bits“ zu sein, die am Anfang jeder Datei des gegebenen Format und der Wert erscheint eine Funktion ist, die die Größe extrahiert aus dem Stream. Die meisten Formate sind einfach genug, die einzige echte Stinker ist jpeg.

Andere Tipps

using (FileStream file = new FileStream(this.ImageFileName, FileMode.Open, FileAccess.Read))
{
    using (Image tif = Image.FromStream(stream: file, 
                                        useEmbeddedColorManagement: false,
                                        validateImageData: false))
    {
        float width = tif.PhysicalDimension.Width;
        float height = tif.PhysicalDimension.Height;
        float hresolution = tif.HorizontalResolution;
        float vresolution = tif.VerticalResolution;
     }
}

validateImageData zu false eingestellt verhindert GDI + von teuerer Analyse der Bilddaten durchgeführt wird, wodurch die Ladezeit erheblich verringert wird. Diese Frage mehr Licht auf das Thema beleuchtet.

Haben Sie versucht, die WPF-Imaging-Klassen? System.Windows.Media.Imaging.BitmapDecoder usw.?

Ich glaube, einige Mühe in die dafür sorgen, war nur die Codecs eine Teilmenge der Datei lesen, um Header-Informationen zu bestimmen. Es lohnt sich eine Überprüfung.

Ich war auf der Suche nach etwas ähnliches ein paar Monate zuvor. Ich wollte den Typ, Ausführung, Höhe und Breite eines GIF-Bild lesen, konnte aber nichts nützlich online finden.

Zum Glück bei GIF, alle erforderlichen Informationen war in den ersten 10 Bytes:

Type: Bytes 0-2
Version: Bytes 3-5
Height: Bytes 6-7
Width: Bytes 8-9

PNG sind etwas komplexer (Breite und Höhe sind 4-Byte jeweils):

Width: Bytes 16-19
Height: Bytes 20-23

Wie oben erwähnt, wotsit ist ein guter Standort für detaillierte Angaben auf Bild- und Datenformate obwohl PNG Spezifikationen unter pnglib sind viel detaillierter. Aber ich denke, den Wikipedia-Eintrag auf PNG und GIF Formate ist der beste Ort zu beginnen.

Hier ist meine Original-Code GIFs für die Kontrolle, ich habe schlug auch gemeinsam etwas für PNGs:

using System;
using System.IO;
using System.Text;

public class ImageSizeTest
{
    public static void Main()
    {
        byte[] bytes = new byte[10];

        string gifFile = @"D:\Personal\Images&Pics\iProduct.gif";
        using (FileStream fs = File.OpenRead(gifFile))
        {
            fs.Read(bytes, 0, 10); // type (3 bytes), version (3 bytes), width (2 bytes), height (2 bytes)
        }
        displayGifInfo(bytes);

        string pngFile = @"D:\Personal\Images&Pics\WaveletsGamma.png";
        using (FileStream fs = File.OpenRead(pngFile))
        {
            fs.Seek(16, SeekOrigin.Begin); // jump to the 16th byte where width and height information is stored
            fs.Read(bytes, 0, 8); // width (4 bytes), height (4 bytes)
        }
        displayPngInfo(bytes);
    }

    public static void displayGifInfo(byte[] bytes)
    {
        string type = Encoding.ASCII.GetString(bytes, 0, 3);
        string version = Encoding.ASCII.GetString(bytes, 3, 3);

        int width = bytes[6] | bytes[7] << 8; // byte 6 and 7 contain the width but in network byte order so byte 7 has to be left-shifted 8 places and bit-masked to byte 6
        int height = bytes[8] | bytes[9] << 8; // same for height

        Console.WriteLine("GIF\nType: {0}\nVersion: {1}\nWidth: {2}\nHeight: {3}\n", type, version, width, height);
    }

    public static void displayPngInfo(byte[] bytes)
    {
        int width = 0, height = 0;

        for (int i = 0; i <= 3; i++)
        {
            width = bytes[i] | width << 8;
            height = bytes[i + 4] | height << 8;            
        }

        Console.WriteLine("PNG\nWidth: {0}\nHeight: {1}\n", width, height);  
    }
}

Auf der Grundlage der Antworten so weit und einige zusätzliche Suche, scheint es, dass in der .NET-2-Klassenbibliothek gibt es keine Funktionalität für sie ist. Also habe ich beschlossen, meine eigenen zu schreiben. Hier ist eine sehr grobe Version davon. Im Moment brauchte ich es nur für JPGs. So schließt es die Antwort gepostet von Abbas.

Es gibt keine Fehlerprüfung oder eine andere Prüfung, aber ich brauche es zur Zeit für eine begrenzte Aufgabe, und es kann hinzugefügt schließlich leicht werden. Getestet habe ich es auf eine bestimmte Anzahl von Bildern, und es ist in der Regel nicht mehr als 6K aus einem Bild zu lesen. Ich denke, es auf die Menge der EXIF-Daten abhängig ist.

using System;
using System.IO;

namespace Test
{

    class Program
    {

        static bool GetJpegDimension(
            string fileName,
            out int width,
            out int height)
        {

            width = height = 0;
            bool found = false;
            bool eof = false;

            FileStream stream = new FileStream(
                fileName,
                FileMode.Open,
                FileAccess.Read);

            BinaryReader reader = new BinaryReader(stream);

            while (!found || eof)
            {

                // read 0xFF and the type
                reader.ReadByte();
                byte type = reader.ReadByte();

                // get length
                int len = 0;
                switch (type)
                {
                    // start and end of the image
                    case 0xD8: 
                    case 0xD9: 
                        len = 0;
                        break;

                    // restart interval
                    case 0xDD: 
                        len = 2;
                        break;

                    // the next two bytes is the length
                    default: 
                        int lenHi = reader.ReadByte();
                        int lenLo = reader.ReadByte();
                        len = (lenHi << 8 | lenLo) - 2;
                        break;
                }

                // EOF?
                if (type == 0xD9)
                    eof = true;

                // process the data
                if (len > 0)
                {

                    // read the data
                    byte[] data = reader.ReadBytes(len);

                    // this is what we are looking for
                    if (type == 0xC0)
                    {
                        width = data[1] << 8 | data[2];
                        height = data[3] << 8 | data[4];
                        found = true;
                    }

                }

            }

            reader.Close();
            stream.Close();

            return found;

        }

        static void Main(string[] args)
        {
            foreach (string file in Directory.GetFiles(args[0]))
            {
                int w, h;
                GetJpegDimension(file, out w, out h);
                System.Console.WriteLine(file + ": " + w + " x " + h);
            }
        }

    }
}

Ich tue dies für PNG-Datei

  var buff = new byte[32];
        using (var d =  File.OpenRead(file))
        {            
            d.Read(buff, 0, 32);
        }
        const int wOff = 16;
        const int hOff = 20;            
        var Widht =BitConverter.ToInt32(new[] {buff[wOff + 3], buff[wOff + 2], buff[wOff + 1], buff[wOff + 0],},0);
        var Height =BitConverter.ToInt32(new[] {buff[hOff + 3], buff[hOff + 2], buff[hOff + 1], buff[hOff + 0],},0);

Ja, das ist durchaus möglich und der Code hängt vom Dateiformat ab.Ich arbeite für einen Imaging-Anbieter (Atalasoft), und unser Produkt stellt für jeden Codec eine GetImageInfo() bereit, die das Minimum tut, um Abmessungen und andere leicht zu erhaltende Daten herauszufinden.

Wenn Sie Ihre eigene Rolle rollen möchten, empfehle ich, mit zu beginnen wotsit.org, das detaillierte Spezifikationen für praktisch alle Bildformate enthält und Sie erfahren, wie Sie die Datei identifizieren und wo die darin enthaltenen Informationen zu finden sind.

Wenn Sie mit C vertraut sind, können Sie auch die kostenlose jpeglib verwenden, um diese Informationen abzurufen.Ich wette, dass Sie dies mit .NET-Bibliotheken tun können, aber ich weiß nicht, wie.

Es wird auf das Dateiformat ab. In der Regel werden sie sie angeben, in den frühen Bytes der Datei auf. Und in der Regel eine gute Bildlese Umsetzung wird das berücksichtigen. Ich kann Ihnen allerdings nicht für .NET einen Punkt.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top