示例#1
0
    /// <summary>
    /// Reads and writes complex EXIF tags
    /// </summary>
    private static void ProcessComplexExifTypes()
    {
        using (var jpegReader = new JpegReader("../../../../_Input/Chicago.jpg"))
            using (var jpegWriter = new JpegWriter("../../../../_Output/ProcessComplexExifTypes.jpg", 70))
            {
                var exif = new Aurigma.GraphicsMill.Codecs.ExifDictionary(jpegReader.Exif);

                Object[] latitude = null;

                if (exif.Contains(ExifDictionary.GpsLatitude))
                {
                    latitude    = exif.GetItemArray(ExifDictionary.GpsLatitude);
                    latitude[0] = new UnsignedRational(113, 12);
                }
                else
                { // Alexandria, Virginia
                    latitude = new Object[] { new UnsignedRational(38, 1), new UnsignedRational(48, 1), new UnsignedRational(17, 1) };
                }

                exif.SetItemArray(ExifDictionary.GpsLatitude, latitude);

                var gpsVer = new Object[] { (byte)2, (byte)0, (byte)0, (byte)1 };
                exif.SetItemArray(ExifDictionary.GpsVersionId, gpsVer);

                exif[Aurigma.GraphicsMill.Codecs.ExifDictionary.Software] = "Aurigma Graphics Mill";
                jpegWriter.Exif = exif;

                Aurigma.GraphicsMill.Pipeline.Run(jpegReader + jpegWriter);
            }
    }
            public void Encode(bool writeHuffmanTables, bool writeQuantizationTables, bool optimizeCoding)
            {
                JpegWriter writer = CreateJpegWriter();

                WriteStartOfImage(ref writer);
                if (writeQuantizationTables)
                {
                    WriteQuantizationTables(ref writer);
                }
                JpegFrameHeader    frameHeader = WriteStartOfFrame(ref writer);
                JpegBlockAllocator?allocator   = optimizeCoding ? new JpegBlockAllocator(MemoryPool) : null;

                try
                {
                    if (!(allocator is null))
                    {
                        allocator.Allocate(frameHeader);
                        TransformBlocks(allocator);
                        BuildHuffmanTables(frameHeader, allocator, false);
                        WriteHuffmanTables(ref writer);
                        WriteStartOfScan(ref writer);
                        WritePreparedScanData(frameHeader, allocator, ref writer);
                    }
                    else
                    {
                        if (writeHuffmanTables)
                        {
                            WriteHuffmanTables(ref writer);
                        }
                        WriteStartOfScan(ref writer);
                        WriteScanData(ref writer);
                    }
                }
示例#3
0
 /// <summary>
 /// Reads first frame of image in TIFF format using memory-friendly Pipeline API
 /// </summary>
 private static void ReadTiffMemoryFriendly()
 {
     using (var reader = new TiffReader("../../../../_Output/WriteMultiframeTiffMemoryFriendly.tif"))
         using (var writer = new JpegWriter("../../../../_Output/ReadTiffMemoryFriendly.jpg"))
         {
             Pipeline.Run(reader + writer);
         }
 }
示例#4
0
 /// <summary>
 /// Gets thumbnail of image from its EXIF metadata
 /// </summary>
 private static void GetExifThumbnail(string inputPath, string outputPath)
 {
     using (var jpegReader = new JpegReader(inputPath))
         using (var thumbnail = (Bitmap)jpegReader.Exif[ExifDictionary.Thumbnail])
             using (var jpegWriter = new JpegWriter(outputPath))
             {
                 Pipeline.Run(thumbnail + jpegWriter);
             }
 }
示例#5
0
 /// <summary>
 /// Loads and saves image to file with specified encoder options using memory-friendly Pipeline API
 /// </summary>
 private static void LoadSaveFileWithOptionsMemoryFriendly()
 {
     using (var reader = new JpegReader("../../../../_Input/Chicago.jpg"))
         // Set value of JPEG quality to 85
         using (var writer = new JpegWriter("../../../../_Output/LoadSaveFileWithOptionsMemoryFriendly.jpg", 85))
         {
             Pipeline.Run(reader + writer);
         }
 }
示例#6
0
    private static void ResizeAndPreserveMetadata()
    {
        using (var jpegReader = new JpegReader("../../../../_Input/Chicago.jpg"))
            using (var resizer = new Resize(jpegReader.Width / 2, 0))
                using (var jpegWriter = new JpegWriter("../../../../_Output/ResizeAndPreserveMetadata.jpg"))
                {
                    // Read EXIF
                    var exif = jpegReader.Exif;
                    // Check if loaded image contains EXIF metadata
                    if (exif == null)
                    {
                        exif = new ExifDictionary();
                    }
                    exif[ExifDictionary.Software] = "Aurigma Graphics Mill";

                    // Read IPTC
                    var iptc = jpegReader.Iptc;
                    // Check if loaded image contains IPTC metadata
                    if (iptc == null)
                    {
                        iptc = new IptcDictionary();
                    }
                    iptc[IptcDictionary.Keyword] = "mountain";

                    // Read Adobe resource blocks
                    var adobeResources = jpegReader.AdobeResources;
                    // Check if loaded image contains Adobe image resource blocks
                    if (adobeResources == null)
                    {
                        adobeResources = new AdobeResourceDictionary();
                    }
                    // Create new adobe image resource block containing copyright metadata
                    var arBlock = new AdobeResourceBlock("Copyright", new byte[] { 1 });
                    // Set this block to the item with 0x040A ID (copyright flag)
                    adobeResources[0x040A] = arBlock;

                    // Read XMP
                    var xmp = new XmpData();
                    //Check if loaded image contains XMP metadata
                    if (jpegReader.Xmp != null)
                    {
                        xmp.Load(jpegReader.Xmp);
                    }
                    // Create a node containing dc:contributor metadata
                    var node = new XmpValueNode(XmpNodeType.SimpleProperty, "John Doe", XmpTagNames.DCContributor);
                    xmp.AddNode(node);

                    // Write metadata
                    jpegWriter.Exif           = exif;
                    jpegWriter.Iptc           = iptc;
                    jpegWriter.AdobeResources = adobeResources;
                    jpegWriter.Xmp            = xmp.Save();

                    Pipeline.Run(jpegReader + resizer + jpegWriter);
                }
    }
    /// <summary>
    /// Resizes while reading of JPEG image using memory-friendly Pipeline API
    /// </summary>
    private static void ResizeWhileReadingJpegMemoryFriendly()
    {
        using (var reader = new JpegReader("../../../../_Input/Chicago.jpg"))
            using (var writer = new JpegWriter("../../../../_Output/ResizeWhileReadingJpegMemoryFriendly.jpg"))
            {
                reader.Scale = JpegScale.x2;

                Pipeline.Run(reader + writer);
            }
    }
示例#8
0
 /// <summary>
 /// Loads and saves image to stream using memory-friendly Pipeline API
 /// </summary>
 private static void LoadSaveStreamMemoryFriendly()
 {
     using (var readStream = System.IO.File.OpenRead("../../../../_Input/Chicago.jpg"))
         using (var jpegReader = new JpegReader(readStream))
             using (var writerStream = System.IO.File.OpenWrite("../../../../_Output/LoadSaveStreamMemoryFriendly.jpg"))
                 using (var jpegWriter = new JpegWriter(writerStream, 85))
                 {
                     Pipeline.Run(jpegReader + jpegWriter);
                 }
 }
示例#9
0
 /// <summary>
 /// Gets content from the specified PDF file and saves it as JPEG format
 /// </summary>
 private static void SaveGraphicsContainerToJpeg(string pdfPath, string jpegPath)
 {
     using (var reader = new PdfReader(pdfPath))
         using (var gc = reader.Frames[0].GetContent())
             using (var writer = new JpegWriter(jpegPath))
                 using (var ig = new ImageGenerator(gc, PixelFormat.Format24bppRgb, RgbColor.White))
                 {
                     Pipeline.Run(ig + writer);
                 }
 }
    /// <summary>
    /// Crops image and preserves clipping path
    /// </summary>
    private static void CropImageAndPreserveClippingPath()
    {
        using (var reader = new JpegReader("../../../../_Input/Apple.jpg"))
            using (var writer = new JpegWriter("../../../../_Output/CropImageAndPreserveClippingPath.jpg"))
                using (var crop = new Crop(reader.Width / 6, 0, reader.Width / 2, reader.Height / 2))
                {
                    writer.AdobeResources = reader.AdobeResources;

                    Pipeline.Run(reader + crop + writer);
                }
    }
    /// <summary>
    /// Resizes image and clipping path using memory-friendly Pipeline API
    /// </summary>
    private static void ResizeImageAndClippingPathMemoryFriendly()
    {
        using (var reader = new JpegReader("../../../../_Input/Apple.jpg"))
            using (var writer = new JpegWriter("../../../../_Output/ResizeImageAndClippingPathMemoryFriendly.jpg"))
                using (var resize = new Resize(reader.Width / 2, reader.Height / 2))
                {
                    writer.AdobeResources = reader.AdobeResources;

                    Pipeline.Run(reader + resize + writer);
                }
    }
    /// <summary>
    /// Reads and writes image in JPEG format using memory-friendly Pipeline API
    /// </summary>
    private static void ReadAndWriteJpegMemoryFriendly()
    {
        using (var reader = new JpegReader("../../../../_Input/Chicago.jpg"))
            using (var flip = new Flip(FlipType.Vertical))
                using (var writer = new JpegWriter("../../../../_Output/ReadWriteJpegMemoryFriendly.jpg"))
                {
                    writer.Quality        = 90;
                    writer.UseSubsampling = false;
                    writer.IsProgressive  = true;

                    Pipeline.Run(reader + flip + writer);
                }
    }
示例#13
0
 /// <summary>
 /// Reads multiframe image in TIFF format using memory-friendly Pipeline API
 /// </summary>
 private static void ReadMultiframeTiffMemoryFriendly()
 {
     using (var reader = new TiffReader("../../../../_Output/WriteMultiframeTiff.tif"))
     {
         for (int i = 0; i < reader.Frames.Count; i++)
         {
             using (var writer = new JpegWriter("../../../../_Output/ReadMultiframeTiffMemoryFriendly_" + i + ".jpg"))
             {
                 Pipeline.Run(reader.Frames[i] + writer);
             }
         }
     }
 }
示例#14
0
        public void WriteTables(IBufferWriter <byte> buffer)
        {
            if (buffer is null)
            {
                throw new ArgumentNullException(nameof(buffer));
            }

            var writer = new JpegWriter(buffer, minimumBufferSize: MinimumBufferSegmentSize);

            WriteStartOfImage(ref writer);
            WriteQuantizationTables(ref writer);
            WriteEndOfImage(ref writer);

            writer.Flush();
        }
示例#15
0
    /// <summary>
    /// Writes EXIF and IPTC metadata using memory-friendly Pipeline API
    /// </summary>
    private static void WriteExifIptcMemoryFriendly()
    {
        using (var jpegReader = new JpegReader("../../../../_Input/Chicago.jpg"))
            using (var jpegWriter = new JpegWriter("../../../../_Output/WriteExifIptcMemoryFriendly.jpg", 70))
            {
                var exif = new Aurigma.GraphicsMill.Codecs.ExifDictionary();
                exif[Aurigma.GraphicsMill.Codecs.ExifDictionary.Software] = "Aurigma Graphics Mill";
                jpegWriter.Exif = exif;

                var iptc = new Aurigma.GraphicsMill.Codecs.IptcDictionary();
                iptc[Aurigma.GraphicsMill.Codecs.IptcDictionary.Keyword] = "mountain";
                iptc[Aurigma.GraphicsMill.Codecs.IptcDictionary.City]    = "Olympia";
                jpegWriter.Iptc = iptc;

                Aurigma.GraphicsMill.Pipeline.Run(jpegReader + jpegWriter);
            }
    }
 /// <summary>
 /// Converts to PixelFormat.Format24bppRgb to and saves to JPEG format using memory-friendly Pipeline API
 /// </summary>
 private static void ConvertAndWriteJpegMemoryFriendly()
 {
     using (var reader = new PngReader("../../../../_Input/Stamp.png"))
         using (var colorConverter = new ColorConverter(PixelFormat.Format24bppRgb))
             using (var writer = new JpegWriter("../../../../_Output/ConvertAndWriteJpegMemoryFriendly.jpg"))
             {
                 // JPEG format supports PixelFormat.Format32bppCmyk and PixelFormat.Format8bppGrayscale
                 // for CMYK and grayscale images accordingly
                 if (reader.PixelFormat == PixelFormat.Format24bppRgb)
                 {
                     Pipeline.Run(reader + writer);
                 }
                 else
                 {
                     Pipeline.Run(reader + colorConverter + writer);
                 }
             }
 }
    /// <summary>
    /// Modifies clipping path explicitly using memory-friendly Pipeline API
    /// </summary>
    private static void ModifyClippingPathExplicitlyMemoryFriendly()
    {
        int width  = 1000;
        int height = 1000;

        using (var reader = new JpegReader("../../../../_Input/Apple.jpg"))
            using (var generator = new ImageGenerator(width, height, reader.PixelFormat, RgbColor.White))
                using (var combiner = new Combiner(CombineMode.Copy))
                    using (var writer = new JpegWriter("../../../../_Output/ModifyClippingPathExplicitlyMemoryFriendly.jpg"))
                    {
                        combiner.TopImage = reader;
                        combiner.X        = (width - reader.Width) / 2;
                        combiner.Y        = (height - reader.Height) / 2;

                        // The clipping path has relatives coordinates (0.0f ... 1.f0). So we need to transform it.
                        var transform = new System.Drawing.Drawing2D.Matrix();
                        transform.Scale((float)reader.Width / (float)width, (float)reader.Height / (float)height);
                        transform.Translate((float)combiner.X / (float)reader.Width, (float)combiner.Y / (float)reader.Height);

                        var adobeResources = reader.AdobeResources;

                        // Remove clipping paths
                        foreach (long key in adobeResources.Keys)
                        {
                            if (key >= FirstPathId && key <= LastPathId)
                            {
                                adobeResources.Remove(key);
                            }
                        }

                        // Transform and save clipping paths
                        for (var i = 0; i < reader.ClippingPaths.Count; i++)
                        {
                            var clippingPath = reader.ClippingPaths[i];
                            clippingPath.ApplyTransform(transform);

                            adobeResources.Add(FirstPathId + i, new AdobeResourceBlock(clippingPath.Name, clippingPath.Data));
                        }

                        writer.AdobeResources = adobeResources;

                        Pipeline.Run(generator + combiner + writer);
                    }
    }
示例#18
0
    /// <summary>
    /// Write copyright XMP block
    /// </summary>
    private static void WriteAdobeResourceBlock(string inputPath, string outputPath)
    {
        using (var reader = new JpegReader(inputPath))
            using (var writer = new JpegWriter(outputPath))
            {
                var adobeResources = reader.AdobeResources;
                if (adobeResources == null)
                {
                    adobeResources = new AdobeResourceDictionary();
                }

                // Create new adobe image resource block with the required metadata
                var arBlock = new AdobeResourceBlock("Copyright", new byte[] { 1 });
                // Set this block to the item with 0x040A ID (copyright flag)
                adobeResources[0x040A] = arBlock;
                // Remove a block with 0x0409 (thumbnail data)
                adobeResources.Remove(0x0409);

                writer.AdobeResources = adobeResources;
                Pipeline.Run(reader + writer);
            }
    }
    /// <summary>
    /// Compares compression of WebP, JPEG and PNG image formats
    /// </summary>
    private static void CompareImageFormatCompressions()
    {
        using (var reader = new JpegReader("../../../../_Input/Chicago.jpg"))
            using (var writerWebP = new WebPWriter("../../../../_Output/CompareImageFormatCompressions.webp"))
                using (var writerJpeg = new JpegWriter("../../../../_Output/CompareImageFormatCompressions.jpg"))
                    using (var writerPng = new PngWriter("../../../../_Output/CompareImageFormatCompressions.png"))
                    {
                        writerWebP.Quality = 90f;
                        writerJpeg.Quality = 90;

                        Pipeline.Run(reader + writerWebP);
                        Pipeline.Run(reader + writerJpeg);
                        Pipeline.Run(reader + writerPng);
                    }

        var webpFile = new System.IO.FileInfo("../../../../_Output/CompareImageFormatCompressions.webp");
        var jpegFile = new System.IO.FileInfo("../../../../_Output/CompareImageFormatCompressions.jpg");
        var pngFile  = new System.IO.FileInfo("../../../../_Output/CompareImageFormatCompressions.png");

        Console.WriteLine("WebP: {0} b", webpFile.Length);
        Console.WriteLine("JPEG: {0} b", jpegFile.Length);
        Console.WriteLine("PNG: {0} b", pngFile.Length);
    }
    /// <summary>
    /// Copies clipping path using memory-friendly Pipeline API
    /// </summary>
    private static void CopyClippingPathMemoryFriendly()
    {
        using (var reader = new JpegReader("../../../../_Input/Apple.jpg"))
            using (var writer = new JpegWriter("../../../../_Output/CopyClippingPathMemoryFriendly.jpg"))
            {
                if (reader.AdobeResources != null)
                {
                    var adobeResources = new AdobeResourceDictionary();

                    for (int i = FirstPathId; i <= LastPathId; i++)
                    {
                        if (reader.AdobeResources.Contains(i))
                        {
                            adobeResources[i] = reader.AdobeResources[i];
                        }
                    }

                    writer.AdobeResources = adobeResources;
                }

                Pipeline.Run(reader + writer);
            }
    }
示例#21
0
    static void SplitImageIntoTiles(int tileSize)
    {
        var outputPath = "../../../../_Output/SplitImagesintoTiles/";

        if (!Directory.Exists(outputPath))
        {
            Directory.CreateDirectory(outputPath);
        }

        // Store reference to all pipeline elements for further correct object disposing
        var pipelineElements = new List <PipelineElement>();

        try
        {
            var reader = ImageReader.Create("../../../../_Input/Venice.jpg");
            pipelineElements.Add(reader);

            var d = 1f;

            var zoomLevels = new List <ZoomLevel>();

            ZoomLevel zoomLevel;

            do
            {
                zoomLevel.ImageWidth  = (int)((float)reader.Width / d);
                zoomLevel.ImageHeight = (int)((float)reader.Height / d);
                zoomLevel.GridWidth   = (zoomLevel.ImageWidth + tileSize - 1) / tileSize;
                zoomLevel.GridHeight  = (zoomLevel.ImageHeight + tileSize - 1) / tileSize;

                zoomLevels.Add(zoomLevel);

                d *= 2;
            } while (zoomLevel.ImageWidth > tileSize || zoomLevel.ImageHeight > tileSize);

            zoomLevels.Reverse();


            for (int zoom = 0; zoom < zoomLevels.Count; zoom++)
            {
                PipelineElement resize;

                if (zoom == zoomLevels.Count)
                {
                    resize = reader;
                }
                else
                {
                    resize = new Resize(zoomLevels[zoom].ImageWidth, zoomLevels[zoom].ImageHeight, ResizeInterpolationMode.Lanczos3);
                    pipelineElements.Add(resize);
                    reader.Receivers.Add(resize);
                }


                for (int tileX = 0; tileX < zoomLevels[zoom].GridWidth; tileX++)
                {
                    for (int tileY = 0; tileY < zoomLevels[zoom].GridHeight; tileY++)
                    {
                        int x      = tileX * tileSize;
                        int y      = tileY * tileSize;
                        int width  = Math.Min((tileX + 1) * tileSize, zoomLevels[zoom].ImageWidth) - x;
                        int height = Math.Min((tileY + 1) * tileSize, zoomLevels[zoom].ImageHeight) - y;

                        var crop = new Crop(x, y, width, height);
                        pipelineElements.Add(crop);
                        resize.Receivers.Add(crop);

                        var outputFilePath = String.Format(outputPath + "{0}-{1}-{2}.jpg", zoom, tileX, tileY);

                        var p = Path.GetDirectoryName(outputFilePath);

                        var writer = new JpegWriter(outputFilePath);

                        pipelineElements.Add(writer);
                        crop.Receivers.Add(writer);
                    }
                }
            }

            Pipeline.Run(reader);
        }
        finally
        {
            for (var i = 0; i < pipelineElements.Count; i++)
            {
                pipelineElements[i].Dispose();
            }
        }
    }
示例#22
0
        public static void ProcessImage(IProcessorItem item)
        {
            using (ImageReader reader = ImageReader.Create(item.Source))
            using (var contrast = new Contrast(item.Correction.Contrast))
            using (var levels = new Levels(item.Correction.Black, item.Correction.White, item.Correction.Shadow, item.Correction.Midpoint, item.Correction.Highlight, HistogramMode.Luminosity))
            using (var color = new ChannelBalance())
            using (var rotate = new Rotate(item.Correction.Rotate))
            using (var saturation = new AdjustHsl(0f, item.Correction.Saturation, 0f))
            using (var writer = new JpegWriter(Path.ChangeExtension(item.Destination, "jpg"), 99))
            {
                color.Addends = new float[3]
                {
                    item.Correction.Blue,
                    item.Correction.Green,
                    item.Correction.Red
                };
                color.Multipliers = new float[3]
                {
                    1f,
                    1f,
                    1f
                };

                writer.UseSubsampling = false;

                Pipeline.Run(reader + contrast + levels + color + rotate + saturation + writer);
            }
        }
示例#23
0
    /// <summary>
    /// Gets thumbnail of image using different approaches (EXIF, JPEG scale, resize)
    /// </summary>
    private static void GetThumbnail(string inputPath, string outputPath, int thumbnailSize)
    {
        using (var reader = ImageReader.Create(inputPath))
            using (var converter = new ColorConverter(PixelFormat.Format24bppRgb))
                using (var resize = new Resize(thumbnailSize, thumbnailSize, ResizeInterpolationMode.High, ResizeMode.Fit))
                    using (var jpegWriter = new JpegWriter(outputPath, 85))
                    {
                        if (reader.Width <= thumbnailSize && reader.Height <= thumbnailSize)
                        {
                            if (reader.PixelFormat == PixelFormat.Format24bppRgb)
                            {
                                Pipeline.Run(reader + jpegWriter);
                            }
                            else
                            {
                                Pipeline.Run(reader + converter + jpegWriter);
                            }

                            return;
                        }

                        var jpegReader = reader as JpegReader;

                        if (jpegReader != null)
                        {
                            if (jpegReader.Exif.Contains(ExifDictionary.Thumbnail))
                            {
                                using (var thumbnail = (Bitmap)jpegReader.Exif[ExifDictionary.Thumbnail])
                                {
                                    if (thumbnail.Width > thumbnailSize || thumbnail.Height > thumbnailSize)
                                    {
                                        if (thumbnail.PixelFormat == PixelFormat.Format24bppRgb)
                                        {
                                            Pipeline.Run(thumbnail + resize + jpegWriter);
                                        }
                                        else
                                        {
                                            Pipeline.Run(thumbnail + resize + converter + jpegWriter);
                                        }

                                        return;
                                    }
                                }
                            }

                            var size = Math.Max(jpegReader.Width, jpegReader.Height);

                            const float k = 1.5f;

                            if (size / 8 >= thumbnailSize * k)
                            {
                                jpegReader.Scale = JpegScale.x8;
                            }
                            else if (size / 4 >= thumbnailSize * k)
                            {
                                jpegReader.Scale = JpegScale.x4;
                            }
                            else if (size / 2 >= thumbnailSize * k)
                            {
                                jpegReader.Scale = JpegScale.x2;
                            }
                        }

                        if (reader.PixelFormat == PixelFormat.Format24bppRgb)
                        {
                            Pipeline.Run(reader + resize + jpegWriter);
                        }
                        else
                        {
                            Pipeline.Run(reader + resize + converter + jpegWriter);
                        }
                    }
    }
示例#24
0
        public void Generate()
        {
            if (InputFilePath == null)
            {
                throw new InvalidOperationException("Input file path is not specified.");
            }

            if (OutputDirPath == null)
            {
                throw new InvalidOperationException("Output directory path is not specified.");
            }

            if (ViewerCreation && BaseName == null)
            {
                throw new InvalidOperationException("Base name should be specified for viewer creation.");
            }

            var zoomLevels = new List <ZoomLevel>();

            ImageReader reader = null;

            try
            {
                reader = ImageReader.Create(InputFilePath);

                var d = 1f;

                ZoomLevel zoomLevel;

                do
                {
                    zoomLevel.ImageWidth  = (int)((float)reader.Width / d);
                    zoomLevel.ImageHeight = (int)((float)reader.Height / d);
                    zoomLevel.GridWidth   = (zoomLevel.ImageWidth + TileSize - 1) / TileSize;
                    zoomLevel.GridHeight  = (zoomLevel.ImageHeight + TileSize - 1) / TileSize;

                    zoomLevels.Add(zoomLevel);

                    tileTotal += zoomLevel.GridWidth * zoomLevel.GridHeight;

                    d *= 2;
                } while (zoomLevel.ImageWidth > TileSize || zoomLevel.ImageHeight > TileSize);

                zoomLevels.Reverse();


                if (ViewerCreation)
                {
                    var bd = AppDomain.CurrentDomain.BaseDirectory;

                    try
                    {
                        if (!Directory.Exists(OutputDirPath))
                        {
                            Directory.CreateDirectory(OutputDirPath);
                        }
                    }
                    catch (Exception e)
                    {
                        throw new IOException(String.Format("Can't create directory {0}.\r\n  {1}", OutputDirPath, e.Message));
                    }

                    File.Copy(Path.Combine(bd, ScriptFileName), Path.Combine(OutputDirPath, ScriptFileName), true);

                    var viewer = File.ReadAllText(Path.Combine(bd, ViewerFileName)).
                                 Replace("{viewerwidth}", ViewerWidth.ToString()).
                                 Replace("{viewerheight}", ViewerHeight.ToString()).
                                 Replace("{imagewidth}", reader.Width.ToString()).
                                 Replace("{imageheight}", reader.Height.ToString()).
                                 Replace("{basename}", BaseName).
                                 Replace("{structure}", FileStructure.Replace("{ext}", GetTileFileExt()));

                    if (TileSize != 256)
                    {
                        viewer = viewer.Replace("{tilesize}", TileSize.ToString());
                    }
                    else
                    {
                        var r = new Regex(@"^.*{tilesize}.*\r\n", RegexOptions.Multiline);
                        viewer = r.Replace(viewer, "");
                    }

                    File.WriteAllText(Path.Combine(OutputDirPath, BaseName + ".htm"), viewer);
                }
            }
            finally
            {
                if (reader != null)
                {
                    reader.Dispose();
                }
            }

            tileProcessedTotal = 0;

            //Application can't have more than 2048 file handlers.
            //We can reach the limit with >~100 MP images
            for (int minTileIndex = 1; minTileIndex <= tileTotal; minTileIndex += MaxOpenFileCount)
            {
                int maxTileIndex = Math.Min(minTileIndex + MaxOpenFileCount - 1, tileTotal);
                int tileIndex    = 0;

                //Store reference to all pipeline elements for further correct object disposing
                var pipelineElements = new List <PipelineElement>();

                try
                {
                    reader = ImageReader.Create(InputFilePath);

                    pipelineElements.Add(reader);

                    PipelineElement source;

                    //Create progress tracker
                    if (Progress != null)
                    {
                        var progress = new ProgressReporter();
                        progress.Progress += (s, e) =>
                        {
                            OnProgress(e);
                        };
                        pipelineElements.Add(progress);
                        reader.Receivers.Add(progress);

                        source = progress;
                    }
                    else
                    {
                        source = reader;
                    }

                    for (int zoom = 0; zoom < zoomLevels.Count; zoom++)
                    {
                        PipelineElement resize;

                        if (zoom == zoomLevels.Count)
                        {
                            resize = source;
                        }
                        else
                        {
                            resize = new Resize(zoomLevels[zoom].ImageWidth, zoomLevels[zoom].ImageHeight, ResizeInterpolationMode.Anisotropic9);
                            pipelineElements.Add(resize);
                            source.Receivers.Add(resize);
                        }


                        for (int tileX = 0; tileX < zoomLevels[zoom].GridWidth; tileX++)
                        {
                            for (int tileY = 0; tileY < zoomLevels[zoom].GridHeight; tileY++)
                            {
                                tileIndex++;

                                if (tileIndex < minTileIndex)
                                {
                                    continue;
                                }

                                int x      = tileX * TileSize;
                                int y      = tileY * TileSize;
                                int width  = Math.Min((tileX + 1) * TileSize, zoomLevels[zoom].ImageWidth) - x;
                                int height = Math.Min((tileY + 1) * TileSize, zoomLevels[zoom].ImageHeight) - y;

                                var crop = new Crop(x, y, width, height);
                                pipelineElements.Add(crop);
                                resize.Receivers.Add(crop);

                                var outputFilePath = Path.Combine(GetTileOutputDirPath(),
                                                                  String.Format(GetFileStructureFormat(), zoom, tileX, tileY, GetTileFileExt()));

                                var p = Path.GetDirectoryName(outputFilePath);

                                try
                                {
                                    if (!Directory.Exists(p))
                                    {
                                        Directory.CreateDirectory(p);
                                    }
                                }
                                catch (Exception e)
                                {
                                    throw new IOException(String.Format("Can't create directory {0}.\r\n  {1}", p, e.Message));
                                }

                                ImageWriter writer;

                                switch (TileImageFormat)
                                {
                                case TileImageFormat.PNG:
                                    writer = new PngWriter(outputFilePath);
                                    break;

                                default:
                                    writer = new JpegWriter(outputFilePath, TileJpegQuality);
                                    break;
                                }

                                pipelineElements.Add(writer);
                                crop.Receivers.Add(writer);

                                if (tileIndex == maxTileIndex)
                                {
                                    //Remove resize elements without crop receivers
                                    for (var l = source.Receivers.Count - 1; l >= 0; l--)
                                    {
                                        if (source.Receivers[l].Receivers.Count == 0)
                                        {
                                            source.Receivers.RemoveAt(l);
                                        }
                                    }

                                    Pipeline.Run(reader);

                                    tileProcessedTotal = maxTileIndex;

                                    goto LoopOut;
                                }
                            }
                        }
                    }

LoopOut:
                    ;
                }
                finally
                {
                    for (var i = 0; i < pipelineElements.Count; i++)
                    {
                        pipelineElements[i].Dispose();
                    }
                }
            }
        }