MakeGif.cs
//
// This code is part of GrapeCity Documents for Imaging samples.
// Copyright (c) GrapeCity, Inc. All rights reserved.
//
using System;
using System.IO;
using System.Drawing;
using System.Collections.Generic;
using System.Linq;
using GrapeCity.Documents.Drawing;
using GrapeCity.Documents.Text;
using GrapeCity.Documents.Imaging;

namespace GcImagingWeb.Samples
{
    // This sample loads the image of a goldfish (same as the one used in BmpTransforms)
    // and applies different transformations to it, creating a number of frames that
    // are combined to produce an animated GIF.
    public class MakeGif
    {
        public Stream GenerateImageStream(ImageEncoding targetEncoding, int pixelWidth = 1024, int pixelHeight = 1024, bool opaque = true, float dpiX = 96, float dpiY = 96)
        {
            if (targetEncoding != ImageEncoding.Gif)
                throw new Exception("This sample only supports GIF output format.");

            // Keep GIF size reasonable:
            var side2 = Math.Min(400, Math.Min(pixelWidth, pixelHeight));

            // Prepare frames for the target GIF flipping/rotating a single image:
            var move1 = new GcBitmap[2];
            var move2 = new GcBitmap[3];
            using (var bmpSrc = new GcBitmap(Path.Combine("Resources", "Stock", "goldfish.jpg")))
            {
                bmpSrc.Opaque = opaque;
                // Adjust straight and flipped images to try and keep the fish's head motionless:
                using (var tbmp = bmpSrc.Resize(side2, side2))
                {
                    move1[0] = new GcBitmap(tbmp.PixelWidth, tbmp.PixelHeight, tbmp.Opaque, tbmp.DpiX, tbmp.DpiY);
                    move1[0].Clear(Color.White);
                    move1[0].BitBlt(tbmp, -(int)(side2 / 14f), 0);
                }
                using (var tbmp = move1[0].FlipRotate(FlipRotateAction.FlipHorizontal))
                {
                    move1[1] = new GcBitmap(tbmp.PixelWidth, tbmp.PixelHeight, tbmp.Opaque, tbmp.DpiX, tbmp.DpiY);
                    move1[1].Clear(Color.White);
                    move1[1].BitBlt(tbmp, (int)(side2 / 14f), 0);
                    move1[1].BitBlt(tbmp, 0, 0);
                }
                move2[0] = move1[0].FlipRotate(FlipRotateAction.Rotate90);
                move2[1] = move1[0].FlipRotate(FlipRotateAction.Rotate180);
                move2[2] = move1[0].FlipRotate(FlipRotateAction.Rotate270);
            }
            // Combine the moves:
            var bmps = new List<GcBitmap>();
            for (int i = 0; i < 4; ++i)
            {
                bmps.Add(move1[0]);
                bmps.Add(move1[1]);
            }
            bmps.Add(move1[0]);
            for (int i = 0; i < 2; ++i)
            {
                bmps.Add(move1[0]);
                bmps.Add(move2[0]);
                bmps.Add(move2[1]);
                bmps.Add(move2[2]);
            }
            bmps.Add(move1[0]);
            // Create the GIF:
            var ms = new MemoryStream();
            using (var gw = new GcGifWriter(ms))
            {
                gw.LogicalScreenWidth = bmps[0].PixelWidth;
                gw.LogicalScreenHeight = bmps[0].PixelHeight;
                gw.PixelAspectRatio = 1;
                gw.AllowAddingTransparentColor = false;

                foreach (var bmp in bmps)
                    gw.AppendFrame(bmp, 255, 0, 0, GifDisposalMethod.DoNotDispose, 16);
            }
            // Dispose bitmaps used to create GIF frames:
            foreach (var bmp in bmps.Distinct())
                bmp.Dispose();

            ms.Seek(0, SeekOrigin.Begin);
            return ms;
        }

        public ImageEncoding DefaultEncoding { get => ImageEncoding.Gif; }
    }
}