diff --git a/IronSoftware.Drawing/IronSoftware.Drawing.Common.Tests/UnitTests/AnyBitmapFunctionality.cs b/IronSoftware.Drawing/IronSoftware.Drawing.Common.Tests/UnitTests/AnyBitmapFunctionality.cs index b563d9b..86f06d8 100644 --- a/IronSoftware.Drawing/IronSoftware.Drawing.Common.Tests/UnitTests/AnyBitmapFunctionality.cs +++ b/IronSoftware.Drawing/IronSoftware.Drawing.Common.Tests/UnitTests/AnyBitmapFunctionality.cs @@ -4,6 +4,7 @@ using SixLabors.ImageSharp.Processing; using System; using System.Collections.Generic; +using System.Diagnostics; using System.Drawing; using System.Drawing.Imaging; using System.IO; @@ -898,6 +899,28 @@ public void Create_New_Image_With_Background_Instance() } } + [Fact] + public void OCR294Test() + { + var tiffBytes = File.ReadAllBytes("OCR294.tif"); + + Stopwatch sw1 = new Stopwatch(); + /*sw1.Start(); + var bitmap = new AnyBitmap(tiffBytes); + var frames = bitmap.GetAllFrames; + sw1.Stop(); + var elapse1 = sw1.ElapsedMilliseconds;*/ + + sw1.Restart(); + var newBitmap = new AnyBitmap(); + var bitmaps = newBitmap.GetAnyBitmaps(tiffBytes, true); + sw1.Stop(); + var elapse2 = sw1.ElapsedMilliseconds; + + //Assert.True(elapse2 < elapse1); + Assert.NotNull(bitmaps); + } + [FactWithAutomaticDisplayName] public void ExtractAlphaData_With32bppImage_ReturnsAlphaChannel() { diff --git a/IronSoftware.Drawing/IronSoftware.Drawing.Common/AnyBitmap.cs b/IronSoftware.Drawing/IronSoftware.Drawing.Common/AnyBitmap.cs index 94503d4..3ec1406 100644 --- a/IronSoftware.Drawing/IronSoftware.Drawing.Common/AnyBitmap.cs +++ b/IronSoftware.Drawing/IronSoftware.Drawing.Common/AnyBitmap.cs @@ -598,6 +598,10 @@ public AnyBitmap(int width, int height, Color backgroundColor = null) CreateNewImageInstance(width, height, backgroundColor); } + public AnyBitmap() + { + } + /// /// Create a new Bitmap from a file. /// @@ -2016,7 +2020,38 @@ private void CreateNewImageInstance(int width, int height, Color backgroundColor Image.SaveAsBmp(stream); Binary = stream.ToArray(); } - + + public List GetAnyBitmaps(ReadOnlySpan bytes, bool loadImg32 = false) + { + List bitmaps = new List(); + Format = Image.DetectFormat(bytes); + + try + { + if (Format is TiffFormat) + { + bitmaps = OpenTiffToAnyBitmaps(bytes); + } + else + { + LoadSingleFrameImage(bytes, loadImg32); + bitmaps.Add(this); + } + } + catch (DllNotFoundException e) + { + throw new DllNotFoundException( + "Please install SixLabors.ImageSharp from NuGet.", e); + } + catch (Exception e) + { + throw new NotSupportedException( + "Image could not be loaded. File format is not supported.", e); + } + + return bitmaps; + } + private void LoadImage(ReadOnlySpan bytes) { Format = Image.DetectFormat(bytes); @@ -2027,32 +2062,7 @@ private void LoadImage(ReadOnlySpan bytes) else { - Binary = bytes.ToArray(); - Image = Image.Load(bytes); - - var resolutionUnit = this.Image.Metadata.ResolutionUnits; - var horizontal = this.Image.Metadata.HorizontalResolution; - var vertical = this.Image.Metadata.VerticalResolution; - - // Check if image metadata is accurate already - switch (resolutionUnit) - { - case SixLabors.ImageSharp.Metadata.PixelResolutionUnit.PixelsPerMeter: - // Convert metadata of the resolution unit to pixel per inch to match the conversion below of 1 meter = 37.3701 inches - this.Image.Metadata.ResolutionUnits = SixLabors.ImageSharp.Metadata.PixelResolutionUnit.PixelsPerInch; - this.Image.Metadata.HorizontalResolution = Math.Ceiling(horizontal / 39.3701); - this.Image.Metadata.VerticalResolution = Math.Ceiling(vertical / 39.3701); - break; - case SixLabors.ImageSharp.Metadata.PixelResolutionUnit.PixelsPerCentimeter: - // Convert metadata of the resolution unit to pixel per inch to match the conversion below of 1 inch = 2.54 centimeters - this.Image.Metadata.ResolutionUnits = SixLabors.ImageSharp.Metadata.PixelResolutionUnit.PixelsPerInch; - this.Image.Metadata.HorizontalResolution = Math.Ceiling(horizontal * 2.54); - this.Image.Metadata.VerticalResolution = Math.Ceiling(vertical * 2.54); - break; - default: - // No changes required due to teh metadata are accurate already - break; - } + LoadSingleFrameImage(bytes); } } catch (DllNotFoundException e) @@ -2080,6 +2090,39 @@ private void LoadImage(Stream stream) LoadImage(ms.ToArray()); } + private void LoadSingleFrameImage(ReadOnlySpan bytes, bool loadImg32 = false) + { + Binary = bytes.ToArray(); + if (!loadImg32) + Image = Image.Load(bytes); + else + Image = Image.Load(bytes); + + var resolutionUnit = this.Image.Metadata.ResolutionUnits; + var horizontal = this.Image.Metadata.HorizontalResolution; + var vertical = this.Image.Metadata.VerticalResolution; + + // Check if image metadata is accurate already + switch (resolutionUnit) + { + case SixLabors.ImageSharp.Metadata.PixelResolutionUnit.PixelsPerMeter: + // Convert metadata of the resolution unit to pixel per inch to match the conversion below of 1 meter = 37.3701 inches + this.Image.Metadata.ResolutionUnits = SixLabors.ImageSharp.Metadata.PixelResolutionUnit.PixelsPerInch; + this.Image.Metadata.HorizontalResolution = Math.Ceiling(horizontal / 39.3701); + this.Image.Metadata.VerticalResolution = Math.Ceiling(vertical / 39.3701); + break; + case SixLabors.ImageSharp.Metadata.PixelResolutionUnit.PixelsPerCentimeter: + // Convert metadata of the resolution unit to pixel per inch to match the conversion below of 1 inch = 2.54 centimeters + this.Image.Metadata.ResolutionUnits = SixLabors.ImageSharp.Metadata.PixelResolutionUnit.PixelsPerInch; + this.Image.Metadata.HorizontalResolution = Math.Ceiling(horizontal * 2.54); + this.Image.Metadata.VerticalResolution = Math.Ceiling(vertical * 2.54); + break; + default: + // No changes required due to teh metadata are accurate already + break; + } + } + private static AnyBitmap LoadSVGImage(string file) { try @@ -2233,15 +2276,84 @@ private static SKBitmap OpenTiffToSKBitmap(AnyBitmap anyBitmap) } } + private List OpenTiffToAnyBitmaps(ReadOnlySpan bytes) + { + List bitmaps = new List(); + + List images = TiffToImageList(bytes, out int maxWidth, out int maxHeight); + // store first frame to the result list + bitmaps.Add(images[0]); + + // iterate through images past the first + for (int i = 1; i < images.Count; i++) + { + // mute image + images[i].Mutate(img => img.Resize(new ResizeOptions + { + Size = new Size(maxWidth, maxHeight), + Mode = ResizeMode.BoxPad, + PadColor = SixLabors.ImageSharp.Color.Transparent + })); + + // store remaining frames to the result list + bitmaps.Add(images[i]); + } + + // get raw binary + using var memoryStream = new MemoryStream(); + images[0].Save(memoryStream, new TiffEncoder()); + memoryStream.Seek(0, SeekOrigin.Begin); + + // store result + Binary = memoryStream.ToArray(); + Image?.Dispose(); + Image = images[0]; + + return bitmaps; + } + private void OpenTiffToImageSharp(ReadOnlySpan bytes) { + List images = TiffToImageList(bytes, out int maxWidth, out int maxHeight); + + // iterate through images past the first + for (int i = 1; i < images.Count; i++) + { + // mute image + images[i].Mutate(img => img.Resize(new ResizeOptions + { + Size = new Size(maxWidth, maxHeight), + Mode = ResizeMode.BoxPad, + PadColor = SixLabors.ImageSharp.Color.Transparent + })); + + // add frames to fir st image + _ = images[0].Frames.AddFrame(images[i].Frames.RootFrame); + + // dispose images past the first + images[i].Dispose(); + } + + // get raw binary + using var memoryStream = new MemoryStream(); + images[0].Save(memoryStream, new TiffEncoder()); + memoryStream.Seek(0, SeekOrigin.Begin); + + // store result + Binary = memoryStream.ToArray(); + Image?.Dispose(); + Image = images[0]; + } + + private List TiffToImageList(ReadOnlySpan bytes, out int maxWidth, out int maxHeight) + { + List images = new List(); try { int imageWidth = 0; int imageHeight = 0; double imageXResolution = 0; double imageYResolution = 0; - List images = new(); // create a memory stream out of them using MemoryStream tiffStream = new(bytes.ToArray()); @@ -2275,53 +2387,23 @@ private void OpenTiffToImageSharp(ReadOnlySpan bytes) var bits = PrepareByteArray(bmp, raster, width, height); images.Add(Image.LoadPixelData(bits, bmp.Width, bmp.Height)); - + // Update the metadata for image resolutions images[0].Metadata.HorizontalResolution = horizontalResolution; images[0].Metadata.VerticalResolution = verticalResolution; } } - - // find max - FindMaxWidthAndHeight(images, out int maxWidth, out int maxHeight); + (maxWidth, maxHeight) = FindMaxWidthAndHeight(images); // mute first image images[0].Mutate(img => img.Resize(new ResizeOptions { - Size = new Size(maxWidth, maxHeight), + Size = new Size(FindMaxWidthAndHeight(images).Item1, FindMaxWidthAndHeight(images).Item2), Mode = ResizeMode.BoxPad, PadColor = SixLabors.ImageSharp.Color.Transparent })); - - // iterate through images past the first - for (int i = 1; i < images.Count; i++) - { - // mute image - images[i].Mutate(img => img.Resize(new ResizeOptions - { - Size = new Size(maxWidth, maxHeight), - Mode = ResizeMode.BoxPad, - PadColor = SixLabors.ImageSharp.Color.Transparent - })); - - // add frames to first image - _ = images[0].Frames.AddFrame(images[i].Frames.RootFrame); - - // dispose images past the first - images[i].Dispose(); - } - - // get raw binary - using var memoryStream = new MemoryStream(); - images[0].Save(memoryStream, new TiffEncoder()); - memoryStream.Seek(0, SeekOrigin.Begin); - - // store result - Binary = memoryStream.ToArray(); - Image?.Dispose(); - Image = images[0]; } catch (DllNotFoundException e) { @@ -2331,6 +2413,8 @@ private void OpenTiffToImageSharp(ReadOnlySpan bytes) { throw new NotSupportedException("Error while reading TIFF image format.", e); } + + return images; } private void SetTiffCompression(Tiff tiff) @@ -2512,6 +2596,14 @@ private static void FindMaxWidthAndHeight(IEnumerable images, out int max maxHeight = images.Select(img => img.Height).Max(); } + private static (int, int) FindMaxWidthAndHeight(IEnumerable images) + { + int maxWidth = images.Select(img => img.Width).Max(); + int maxHeight = images.Select(img => img.Height).Max(); + + return (maxWidth, maxHeight); + } + private static void FindMaxWidthAndHeight(IEnumerable images, out int maxWidth, out int maxHeight) { maxWidth = images.Select(img => img.Width).Max();