Tell me, how can you quickly read the metadata in a large number of pictures? For example, width and height. As I understand, the standard .NET library loads pictures into a memory by a target. Is it possible without it?

Interested in JPG and PNG.

    2 answers 2

    For PNG: We read the PNG specification , we write a simple code:

    using (var fs = File.OpenRead(filename)) { byte[] header = new byte[8]; fs.Read(header, 0, 8); if (!header.SequenceEqual(new byte[] { 137, 80, 78, 71, 13, 10, 26, 10 })) throw new InvalidOperationException("not a png file"); var br = new BinaryReader(fs, Encoding.ASCII, true); while (fs.Position != fs.Length) { uint chunkLength = br.ReadUInt32BE(); string chunkType = new string(br.ReadChars(4)); if (chunkType == "IHDR") { // читаем чанк uint width = br.ReadUInt32BE(); uint height = br.ReadUInt32BE(); byte bitDepth = br.ReadByte(); byte colorType = br.ReadByte(); byte comprMethod = br.ReadByte(); byte filterMethod = br.ReadByte(); byte interlaceMethod = br.ReadByte(); return; } else // пропускаем чанк fs.Position += chunkLength; uint crc = br.ReadUInt32BE(); } } 

    For jpeg. Specifications not found, only the article . It will not work for all files, but only for the most common format. It is difficult to find examples of other formats.

     using (var fs = File.OpenRead(filename)) { var br = new BinaryReader(fs, Encoding.ASCII, true); ushort marker = br.ReadUInt16BE(); if (marker != 0xFFD8) throw new InvalidOperationException("not valid jpeg file"); while (fs.Position != fs.Length) { marker = br.ReadUInt16BE(); ushort length = br.ReadUInt16BE(); if (marker == 0xFFC0) { byte precision = br.ReadByte(); ushort height = br.ReadUInt16BE(); ushort width = br.ReadUInt16BE(); fs.Position += length - 7; return; } else fs.Position += length - 2; } } 

    For work, you need extension methods from here: https://stackoverflow.com/questions/36928490/what-are-three-ways-to-get-a-big-endian-binaryreader

     static class BinaryReaderExtensionMethods { static public UInt16 ReadUInt16BE(this BinaryReader br) { return (UInt16)IPAddress.NetworkToHostOrder(br.ReadInt16()); } static public UInt32 ReadUInt32BE(this BinaryReader br) { return (UInt32)IPAddress.NetworkToHostOrder(br.ReadInt32()); } } 
    • Specifications can be found at en.wikipedia.org/wiki/JPEG_File_Interchange_Format , and additionally parsit the E0 section, it is easier to find by the signature (although sometimes it may not be) - bukkojot
    • Search by signature bad approach. Firstly, this is contrary to the task, because the fastest way to read the meta-data is required. To search for signatures you have to read everything. And secondly, a signature can be accidentally found somewhere in the data. - Zergatul
    • In this case, the signature is quite large - 6 bytes are constant and the size of the section is predictable, which gives sufficient accuracy. Secondly, this section is at the very beginning. In principle, your variant would be better if you considered sections with fixed data size, and so, the idea with so-called stuffing bytes allows you to search for markers in the stream just like that - bukkojot

    The variant is possible through System.Drawing.Image using the Image.FromStream method (stream, false, false). When we pass false parameters to the 2nd and 3rd parameters, Image will not use color information and validate the data, due to which the speed increases approximately 100 times. The average speed of the Image.FromStream (stream) code is ~ 444 ms, and the Image.FromStream (stream, false, false) code ~ 61500 ms. The lead time is indicated for 512 images with a total size of 1.11 GB.
    Here is the code

      public static List<float[]> ReadResolution(string path) { var files = Directory.GetFiles(path, "*.jpg"); var resolutionList = new List<float[]>(); foreach (var file in files) { var fstream = File.OpenRead(file); var img = Image.FromStream(fstream, false, false); resolutionList.Add(new float[]{ img.HorizontalResolution, img.VerticalResolution }); fstream.Close(); } return resolutionList; } 
    • And you did not mess up with pokozateli time? You say that the method with additional flags is faster, but the MS is something big. - iluxa1810
    • I do not know what you are guided by, saying that the MS is too big, but no, I did not mess up. Checked on 512 files, if that. - Andrei S.