<commit_before>﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using CollectionsOnline.Core.Config;
using CollectionsOnline.Core.Indexes;
using CollectionsOnline.Core.Models;
using CollectionsOnline.Import.Extensions;
using CollectionsOnline.Import.Imports;
using CollectionsOnline.Import.Infrastructure;
using ImageMagick;
using IMu;
using Raven.Client;
using CollectionsOnline.Core.Extensions;
using Serilog;

namespace CollectionsOnline.Import.Factories
{
    public class ImageMediaFactory : IImageMediaFactory
    {
        private readonly IDocumentStore _documentStore;
        private readonly IImuSessionProvider _imuSessionProvider;
        private readonly IList<ImageMediaJob> _imageMediaJobs;

        public ImageMediaFactory(
            IDocumentStore documentStore,
            IImuSessionProvider imuSessionProvider)
        {
            _documentStore = documentStore;
            _imuSessionProvider = imuSessionProvider;

            // Build a list the various image conversions used in the application
            _imageMediaJobs = new List<ImageMediaJob>
            {
                new ImageMediaJob
                {
                    FileDerivativeType = FileDerivativeType.Original,
                    Transform = (image, map) =>
                    {
                        image.Resize(new MagickGeometry(3000) { Greater = true });
                        image.Format = MagickFormat.Jpg;
                        image.Quality = 88;
                        return image;
                    }
                },
                new ImageMediaJob
                {
                    FileDerivativeType = FileDerivativeType.Thumbnail,
                    Transform = (image, map) =>
                    {
                        if (NeedsPadding(map))
                        {
                            image.Resize(new MagickGeometry(250));
                            image.Extent(250, 250, MagickColors.White);
                        }
                        else
                        {
                            image.Resize(new MagickGeometry(250) { FillArea = true });
                            image.Crop(250, 250, Gravity.Center);
                        }

                        image.Format = MagickFormat.Jpg;
                        image.Quality = 65;
                        return image;
                    }
                },
                new ImageMediaJob
                {
                    FileDerivativeType = FileDerivativeType.Medium,
                    Transform = (image, map) =>
                    {
                        image.Resize(new MagickGeometry(0, 500));
                        image.Format = MagickFormat.Jpg;
                        image.Quality = 78;
                        return image;
                    }
                },
                new ImageMediaJob
                {
                    FileDerivativeType = FileDerivativeType.Large,
                    Transform = (image, map) =>
                    {
                        image.Resize(new MagickGeometry(1500) { Greater = true });
                        image.Format = MagickFormat.Jpg;
                        image.Quality = 78;
                        return image;
                    }
                }
            };
        }

        public bool Make(ref ImageMedia imageMedia)
        {
            var stopwatch = Stopwatch.StartNew();

            if (FileExists(ref imageMedia))
            {
                stopwatch.Stop();
                Log.Logger.Debug("Found existing image {Irn} in {ElapsedMilliseconds} ms", imageMedia.Irn, stopwatch.ElapsedMilliseconds);

                return true;
            }

            // Fetch from Imu as we were not able to find local files
            try
            {
                using (var imuSession = _imuSessionProvider.CreateInstance("emultimedia"))
                {
                    imuSession.FindKey(imageMedia.Irn);
                    var result = imuSession.Fetch("start", 0, -1, Columns).Rows[0];

                    var resource = result.GetMap("resource");
                    if (resource == null)
                        throw new IMuException("MultimediaResourceNotFound");
                    var fileStream = resource["file"] as FileStream;
                    
                    using (var originalImage = new MagickImage(fileStream))
                    {
                        var optimizer = new ImageOptimizer();

                        foreach (var imageMediaJob in _imageMediaJobs)
                        {
                            var destPath = PathFactory.MakeDestPath(imageMedia.Irn, ".jpg", imageMediaJob.FileDerivativeType);
                            var uriPath = PathFactory.BuildUriPath(imageMedia.Irn, ".jpg", imageMediaJob.FileDerivativeType);

                            using (var image = imageMediaJob.Transform(originalImage.Clone(), result))
                            {
                                image.Write(destPath);
                                optimizer.LosslessCompress(destPath);

                                // Set property via reflection (ImageMediaFile properties are used instead of a collection due to Raven Indexing)
                                typeof(ImageMedia)
                                    .GetProperties()<commit_msg>fix issue with padded thumbnails<commit_after>﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using CollectionsOnline.Core.Config;
using CollectionsOnline.Core.Indexes;
using CollectionsOnline.Core.Models;
using CollectionsOnline.Import.Extensions;
using CollectionsOnline.Import.Imports;
using CollectionsOnline.Import.Infrastructure;
using ImageMagick;
using IMu;
using Raven.Client;
using CollectionsOnline.Core.Extensions;
using Serilog;

namespace CollectionsOnline.Import.Factories
{
    public class ImageMediaFactory : IImageMediaFactory
    {
        private readonly IDocumentStore _documentStore;
        private readonly IImuSessionProvider _imuSessionProvider;
        private readonly IList<ImageMediaJob> _imageMediaJobs;

        public ImageMediaFactory(
            IDocumentStore documentStore,
            IImuSessionProvider imuSessionProvider)
        {
            _documentStore = documentStore;
            _imuSessionProvider = imuSessionProvider;

            // Build a list the various image conversions used in the application
            _imageMediaJobs = new List<ImageMediaJob>
            {
                new ImageMediaJob
                {
                    FileDerivativeType = FileDerivativeType.Original,
                    Transform = (image, map) =>
                    {
                        image.Resize(new MagickGeometry(3000) { Greater = true });                        
                        image.Quality = 86;                                                
                        return image;
                    }
                },
                new ImageMediaJob
                {
                    FileDerivativeType = FileDerivativeType.Thumbnail,
                    Transform = (image, map) =>
                    {
                        if (NeedsPadding(map))
                        {
                            image.Resize(new MagickGeometry(250));
                            image.Extent(new MagickGeometry(250), Gravity.Center, MagickColors.White);
                        }
                        else
                        {
                            image.Resize(new MagickGeometry(250) { FillArea = true });
                            image.Crop(250, 250, Gravity.Center);
                        }
                        image.Quality = 70;
                        return image;
                    }
                },
                new ImageMediaJob
                {
                    FileDerivativeType = FileDerivativeType.Medium,
                    Transform = (image, map) =>
                    {
                        image.Resize(new MagickGeometry(0, 500));
                        image.Quality = 75;
                        return image;
                    }
                },
                new ImageMediaJob
                {
                    FileDerivativeType = FileDerivativeType.Large,
                    Transform = (image, map) =>
                    {
                        image.Resize(new MagickGeometry(1500) { Greater = true });
                        image.Quality = 75;
                        return image;
                    }
                }
            };
        }

        public bool Make(ref ImageMedia imageMedia)
        {
            var stopwatch = Stopwatch.StartNew();

            if (FileExists(ref imageMedia))
            {
                stopwatch.Stop();
                Log.Logger.Debug("Found existing image {Irn} in {ElapsedMilliseconds} ms", imageMedia.Irn, stopwatch.ElapsedMilliseconds);

                return true;
            }

            // Fetch from Imu as we were not able to find local files
            try
            {
                using (var imuSession = _imuSessionProvider.CreateInstance("emultimedia"))
                {
                    imuSession.FindKey(imageMedia.Irn);
                    var result = imuSession.Fetch("start", 0, -1, Columns).Rows[0];

                    var resource = result.GetMap("resource");
                    if (resource == null)
                        throw new IMuException("MultimediaResourceNotFound");
                    var fileStream = resource["file"] as FileStream;
                    
                    using (var originalImage = new MagickImage(fileStream))
                    {
                        foreach (var imageMediaJob in _imageMediaJobs)
                        {
                            var destPath = PathFactory.MakeDestPath(imageMedia.Irn, ".jpg", imageMediaJob.FileDerivativeType);
                            var uriPath = PathFactory.BuildUriPath(imageMedia.Irn, ".jpg", imageMediaJob.FileDerivativeType);

                            using (var image = imageMediaJob.Transform(originalImage.Clone(), result))
                            {
                                // Save profiles if there are any
                                var profile = image.GetColorProfile();

                                // Strip exif and any profiles
                                image.Strip();

                                // Add original profile back
                                if (profile != null)
                                    image.AddProfile(profile);

                                // Use jpeg format
                                image.Format = MagickFormat.Jpeg;

                                // Write image to disk
                                image.Write(destPath);

                                // Set property via reflection (ImageMediaFile properties are used instead of a collection due to Raven Indexing)
                                typeof(ImageMedia)
                                    .GetProperties()
{'fraction_non_alphanumeric': 0.06679659815733523, 'fraction_numerical': 0.006998582565556343, 'mean_word_length': 1.1941690962099125, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 14, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3869890', 'n_tokens_mistral': 2636, 'n_tokens_neox': 2371, 'n_words': 555}