#region PDFsharp - A .NET library for processing PDF // // Authors: // Thomas Hövel // // Copyright (c) 2005-2017 empira Software GmbH, Cologne Area (Germany) // // http://www.pdfsharp.com // http://sourceforge.net/projects/pdfsharp // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. #endregion using System; using System.Diagnostics; using System.IO; using PdfSharp.Pdf; namespace PdfSharp.Drawing { /// /// This interface will be implemented by specialized classes, one for JPEG, one for BMP, one for PNG, one for GIF. Maybe more. /// internal interface IImageImporter { /// /// Imports the image. Returns null if the image importer does not support the format. /// ImportedImage ImportImage(StreamReaderHelper stream, PdfDocument document); /// /// Prepares the image data needed for the PDF file. /// ImageData PrepareImage(ImagePrivateData data); } // $THHO Add IDispose?. /// /// Helper for dealing with Stream data. /// internal class StreamReaderHelper { internal StreamReaderHelper(Stream stream) { #if GDI || WPF _stream = stream; MemoryStream ms = stream as MemoryStream; if (ms == null) { // THHO4STLA byte[] or MemoryStream? _ownedMemoryStream = ms = new MemoryStream(); CopyStream(stream, ms); // For .NET 4: stream.CopyTo(ms); } _data = ms.GetBuffer(); _length = (int)ms.Length; #else // For WinRT there is no GetBuffer() => alternative implementation for WinRT. // TODO: Are there advantages of GetBuffer()? It should reduce LOH fragmentation. _stream = stream; _stream.Position = 0; if (_stream.Length > int.MaxValue) throw new ArgumentException("Stream is too large.", "stream"); _length = (int)_stream.Length; _data = new byte[_length]; _stream.Read(_data, 0, _length); #endif } internal byte GetByte(int offset) { if (_currentOffset + offset >= _length) { Debug.Assert(false); return 0; } return _data[_currentOffset + offset]; } internal ushort GetWord(int offset, bool bigEndian) { return (ushort)(bigEndian ? GetByte(offset) * 256 + GetByte(offset + 1) : GetByte(offset) + GetByte(offset + 1) * 256); } internal uint GetDWord(int offset, bool bigEndian) { return (uint)(bigEndian ? GetWord(offset, true) * 65536 + GetWord(offset + 2, true) : GetWord(offset, false) + GetWord(offset + 2, false) * 65536); } private static void CopyStream(Stream input, Stream output) { byte[] buffer = new byte[65536]; int read; while ((read = input.Read(buffer, 0, buffer.Length)) > 0) { output.Write(buffer, 0, read); } } /// /// Resets this instance. /// public void Reset() { _currentOffset = 0; } /// /// Gets the original stream. /// public Stream OriginalStream { get { return _stream; } } private readonly Stream _stream; internal int CurrentOffset { get { return _currentOffset; } set { _currentOffset = value; } } private int _currentOffset; /// /// Gets the data as byte[]. /// public byte[] Data { get { return _data; } } private readonly byte[] _data; /// /// Gets the length of Data. /// public int Length { get { return _length; } } private readonly int _length; #if GDI || WPF /// /// Gets the owned memory stream. Can be null if no MemoryStream was created. /// public MemoryStream OwnedMemoryStream { get { return _ownedMemoryStream; } } private readonly MemoryStream _ownedMemoryStream; #endif } /// /// The imported image. /// internal abstract class ImportedImage { /// /// Initializes a new instance of the class. /// protected ImportedImage(IImageImporter importer, ImagePrivateData data, PdfDocument document) { Data = data; _document = document; data.Image = this; _importer = importer; } /// /// Gets information about the image. /// public ImageInformation Information { get { return _information; } private set { _information = value; } } private ImageInformation _information = new ImageInformation(); /// /// Gets a value indicating whether image data for the PDF file was already prepared. /// public bool HasImageData { get { return _imageData != null; } } /// /// Gets the image data needed for the PDF file. /// public ImageData ImageData { get { if(!HasImageData) _imageData = PrepareImageData(); return _imageData; } private set { _imageData = value; } } private ImageData _imageData; internal virtual ImageData PrepareImageData() { throw new NotImplementedException(); } private IImageImporter _importer; internal ImagePrivateData Data; internal readonly PdfDocument _document; } /// /// Public information about the image, filled immediately. /// Note: The stream will be read and decoded on the first call to PrepareImageData(). /// ImageInformation can be filled for corrupted images that will throw an expection on PrepareImageData(). /// internal class ImageInformation { internal enum ImageFormats { /// /// Standard JPEG format (RGB). /// JPEG, /// /// Grayscale JPEG format. /// JPEGGRAY, /// /// JPEG file with inverted CMYK, thus RGBW. /// JPEGRGBW, /// /// JPEG file with CMYK. /// JPEGCMYK, Palette1, Palette4, Palette8, RGB24, ARGB32 } internal ImageFormats ImageFormat; internal uint Width; internal uint Height; /// /// The horizontal DPI (dots per inch). Can be 0 if not supported by the image format. /// Note: JFIF (JPEG) files may contain either DPI or DPM or just the aspect ratio. Windows BMP files will contain DPM. Other formats may support any combination, including none at all. /// internal decimal HorizontalDPI; /// /// The vertical DPI (dots per inch). Can be 0 if not supported by the image format. /// internal decimal VerticalDPI; /// /// The horizontal DPM (dots per meter). Can be 0 if not supported by the image format. /// internal decimal HorizontalDPM; /// /// The vertical DPM (dots per meter). Can be 0 if not supported by the image format. /// internal decimal VerticalDPM; /// /// The horizontal component of the aspect ratio. Can be 0 if not supported by the image format. /// Note: Aspect ratio will be set if either DPI or DPM was set, but may also be available in the absence of both DPI and DPM. /// internal decimal HorizontalAspectRatio; /// /// The vertical component of the aspect ratio. Can be 0 if not supported by the image format. /// internal decimal VerticalAspectRatio; /// /// The colors used. Only valid for images with palettes, will be 0 otherwise. /// internal uint ColorsUsed; } /// /// Contains internal data. This includes a reference to the Stream if data for PDF was not yet prepared. /// internal abstract class ImagePrivateData { internal ImagePrivateData() { } /// /// Gets the image. /// public ImportedImage Image { get { return _image; } internal set { _image = value; } } private ImportedImage _image; } /// /// Contains data needed for PDF. Will be prepared when needed. /// internal abstract class ImageData { } }