/// <summary> /// Default case that adds comment with keyword to directory /// </summary> /// <param name="directory">EpsDirectory to add extracted data to</param> /// <param name="name">String that holds name of current comment</param> /// <param name="value">String that holds value of current comment</param> private void AddToDirectory(EpsDirectory directory, string name, string value) { if (!EpsDirectory.TagIntegerMap.ContainsKey(name)) { return; } var tag = EpsDirectory.TagIntegerMap[name]; switch (tag) { case EpsDirectory.TagImageData: ExtractImageData(directory, value); break; case EpsDirectory.TagContinueLine: directory.Set(_previousTag, directory.GetString(_previousTag) + " " + value); break; default: if (EpsDirectory.TagNameMap.ContainsKey(tag) && !directory.ContainsTag(tag)) { directory.Set(tag, value); _previousTag = tag; } else { // Set previous tag to an Integer that doesn't exist in EpsDirectory _previousTag = 0; } break; } _previousTag = tag; }
/// <summary> /// Main method that parses all comments and then distributes data extraction among other methods that parse the /// rest of file and store encountered data in metadata(if there exists an entry in EpsDirectory /// for the found data). Reads until a begin data/binary comment is found or reader's estimated /// available data has run out (or AI09 End Private Data). Will extract data from normal EPS comments, Photoshop, ICC, and XMP. /// </summary> /// <param name="directory"></param> /// <param name="directories">list to add directory to and extracted data</param> /// <param name="reader"></param> private void Extract(EpsDirectory directory, List <Directory> directories, SequentialReader reader) { var line = new StringBuilder(); while (true) { line.Length = 0; // Read the next line, excluding any trailing newline character // Note that for Windows-style line endings ("\r\n") the outer loop will be run a second time with an empty // string, which is fine. while (true) { char c = (char)reader.GetByte(); if (c == '\r' || c == '\n') { break; } line.Append(c); } // Stop when we hit a line that is not a comment if (line.Length != 0 && line[0] != '%') { break; } string name; // ':' signifies there is an associated keyword (should be put in directory) // otherwise, the name could be a marker int colonIndex = line.IndexOf(':'); if (colonIndex != -1) { name = line.ToString(0, colonIndex).Trim(); var value = line.ToString(colonIndex + 1, line.Length - (colonIndex + 1)).Trim(); AddToDirectory(directory, name, value); } else { name = line.ToString().Trim(); } // Some comments will both have a value and signify a new block to follow if (name.Equals("%BeginPhotoshop")) { ExtractPhotoshopData(directories, reader); } else if (name.Equals("%%BeginICCProfile")) { ExtractIccData(directories, reader); } else if (name.Equals("%begin_xml_packet")) { ExtractXmpData(directories, reader); } } }
/// <summary> /// Parses '%ImageData' comment which holds several values including width in px, /// height in px and color type. /// </summary> private static void ExtractImageData(EpsDirectory directory, string imageData) { // %ImageData: 1000 1000 8 3 1 1000 7 "beginimage" directory.Set(EpsDirectory.TagImageData, imageData.Trim()); var imageDataParts = imageData.Split(' '); int width = int.Parse(imageDataParts[0]); int height = int.Parse(imageDataParts[1]); int colorType = int.Parse(imageDataParts[3]); // Only add values that are not already present if (!directory.ContainsTag(EpsDirectory.TagImageWidth)) { directory.Set(EpsDirectory.TagImageWidth, width); } if (!directory.ContainsTag(EpsDirectory.TagImageHeight)) { directory.Set(EpsDirectory.TagImageHeight, height); } if (!directory.ContainsTag(EpsDirectory.TagColorType)) { directory.Set(EpsDirectory.TagColorType, colorType); } if (!directory.ContainsTag(EpsDirectory.TagRamSize)) { int bytesPerPixel = colorType switch { 1 => 1, // grayscale 2 => 3, // Lab 3 => 3, // RGB 4 => 3, // CMYK _ => 0 }; if (bytesPerPixel != 0) { directory.Set(EpsDirectory.TagRamSize, bytesPerPixel * width * height); } } }
public DirectoryList Extract(Stream inputStream) { IndexedReader reader = new IndexedSeekingReader(inputStream); var directory = new EpsDirectory(); var epsDirectories = new List <Directory>() { directory }; // 0xC5D0D3C6 signifies an EPS Header block which contains 32-bytes of basic information // 0x25215053 (%!PS) signifies an EPS File and leads straight into the PostScript int startingPosition = (int)inputStream.Position; switch (reader.GetInt32(0)) { case unchecked ((int)0xC5D0D3C6): reader = reader.WithByteOrder(isMotorolaByteOrder: false); int postScriptOffset = reader.GetInt32(4); int postScriptLength = reader.GetInt32(8); int wmfOffset = reader.GetInt32(12); int wmfSize = reader.GetInt32(16); int tifOffset = reader.GetInt32(20); int tifSize = reader.GetInt32(24); //int checkSum = reader.getInt32(28); // Get Tiff/WMF preview data if applicable if (tifSize != 0) { directory.Set(EpsDirectory.TagTiffPreviewSize, tifSize); directory.Set(EpsDirectory.TagTiffPreviewOffset, tifOffset); // Get Tiff metadata try { ByteArrayReader byteArrayReader = new(reader.GetBytes(tifOffset, tifSize)); TiffReader.ProcessTiff(byteArrayReader, new PhotoshopTiffHandler(epsDirectories)); } catch (TiffProcessingException ex) { directory.AddError("Unable to process TIFF data: " + ex.Message); } } else if (wmfSize != 0) { directory.Set(EpsDirectory.TagWmfPreviewSize, wmfSize); directory.Set(EpsDirectory.TagWmfPreviewOffset, wmfOffset); } // TODO avoid allocating byte array here -- read directly from InputStream Extract(directory, epsDirectories, new SequentialByteArrayReader(reader.GetBytes(postScriptOffset, postScriptLength))); break; case 0x25215053: inputStream.Position = startingPosition; Extract(directory, epsDirectories, new SequentialStreamReader(inputStream)); break; default: directory.AddError("File type not supported."); break; } return(epsDirectories); }