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.
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()); } } 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; } Source: https://ru.stackoverflow.com/questions/707909/
All Articles