using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using SixLabors.ImageSharp;
using Image = NetVips.Image;
namespace API.Services;
public interface IImageService
{
void ExtractImages(string fileFilePath, string targetDirectory, int fileCount = 1);
string GetCoverImage(string path, string fileName, string outputDirectory);
///
/// Creates a Thumbnail version of a base64 image
///
/// base64 encoded image
///
/// File name with extension of the file. This will always write to
string CreateThumbnailFromBase64(string encodedImage, string fileName);
string WriteCoverThumbnail(Stream stream, string fileName, string outputDirectory);
///
/// Converts the passed image to webP and outputs it in the same directory
///
/// Full path to the image to convert
/// Where to output the file
/// File of written webp image
Task ConvertToWebP(string filePath, string outputPath);
Task IsImage(string filePath);
}
public class ImageService : IImageService
{
private readonly ILogger _logger;
private readonly IDirectoryService _directoryService;
public const string ChapterCoverImageRegex = @"v\d+_c\d+";
public const string SeriesCoverImageRegex = @"series\d+";
public const string CollectionTagCoverImageRegex = @"tag\d+";
public const string ReadingListCoverImageRegex = @"readinglist\d+";
///
/// Width of the Thumbnail generation
///
private const int ThumbnailWidth = 320;
public ImageService(ILogger logger, IDirectoryService directoryService)
{
_logger = logger;
_directoryService = directoryService;
}
public void ExtractImages(string fileFilePath, string targetDirectory, int fileCount = 1)
{
_directoryService.ExistOrCreate(targetDirectory);
if (fileCount == 1)
{
_directoryService.CopyFileToDirectory(fileFilePath, targetDirectory);
}
else
{
_directoryService.CopyDirectoryToDirectory(Path.GetDirectoryName(fileFilePath), targetDirectory,
Tasks.Scanner.Parser.Parser.ImageFileExtensions);
}
}
public string GetCoverImage(string path, string fileName, string outputDirectory)
{
if (string.IsNullOrEmpty(path)) return string.Empty;
try
{
using var thumbnail = Image.Thumbnail(path, ThumbnailWidth);
var filename = fileName + ".png";
thumbnail.WriteToFile(_directoryService.FileSystem.Path.Join(outputDirectory, filename));
return filename;
}
catch (Exception ex)
{
_logger.LogWarning(ex, "[GetCoverImage] There was an error and prevented thumbnail generation on {ImageFile}. Defaulting to no cover image", path);
}
return string.Empty;
}
///
/// Creates a thumbnail out of a memory stream and saves to with the passed
/// fileName and .png extension.
///
/// Stream to write to disk. Ensure this is rewinded.
/// filename to save as without extension
/// Where to output the file, defaults to covers directory
/// File name with extension of the file. This will always write to
public string WriteCoverThumbnail(Stream stream, string fileName, string outputDirectory)
{
using var thumbnail = Image.ThumbnailStream(stream, ThumbnailWidth);
var filename = fileName + ".png";
_directoryService.ExistOrCreate(outputDirectory);
try
{
_directoryService.FileSystem.File.Delete(_directoryService.FileSystem.Path.Join(outputDirectory, filename));
} catch (Exception) {/* Swallow exception */}
thumbnail.WriteToFile(_directoryService.FileSystem.Path.Join(outputDirectory, filename));
return filename;
}
public async Task ConvertToWebP(string filePath, string outputPath)
{
var file = _directoryService.FileSystem.FileInfo.FromFileName(filePath);
var fileName = file.Name.Replace(file.Extension, string.Empty);
var outputFile = Path.Join(outputPath, fileName + ".webp");
using var sourceImage = await SixLabors.ImageSharp.Image.LoadAsync(filePath);
await sourceImage.SaveAsWebpAsync(outputFile);
return outputFile;
}
public async Task IsImage(string filePath)
{
try
{
var info = await SixLabors.ImageSharp.Image.IdentifyAsync(filePath);
if (info == null) return false;
return true;
}
catch (Exception)
{
/* Swallow Exception */
}
return false;
}
///
public string CreateThumbnailFromBase64(string encodedImage, string fileName)
{
try
{
using var thumbnail = Image.ThumbnailBuffer(Convert.FromBase64String(encodedImage), ThumbnailWidth);
var filename = fileName + ".png";
thumbnail.WriteToFile(_directoryService.FileSystem.Path.Join(_directoryService.CoverImageDirectory, fileName + ".png"));
return filename;
}
catch (Exception e)
{
_logger.LogError(e, "Error creating thumbnail from url");
}
return string.Empty;
}
///
/// Returns the name format for a chapter cover image
///
///
///
///
public static string GetChapterFormat(int chapterId, int volumeId)
{
return $"v{volumeId}_c{chapterId}";
}
///
/// Returns the name format for a series cover image
///
///
///
public static string GetSeriesFormat(int seriesId)
{
return $"series{seriesId}";
}
///
/// Returns the name format for a collection tag cover image
///
///
///
public static string GetCollectionTagFormat(int tagId)
{
return $"tag{tagId}";
}
///
/// Returns the name format for a reading list cover image
///
///
///
public static string GetReadingListFormat(int readingListId)
{
return $"readinglist{readingListId}";
}
}