using System;
using System.IO;
using Microsoft.Extensions.Logging;
using NetVips;
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);
}
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)
{
_directoryService.ExistOrCreate(targetDirectory);
if (fileCount == 1)
{
_directoryService.CopyFileToDirectory(fileFilePath, targetDirectory);
}
else
{
_directoryService.CopyDirectoryToDirectory(Path.GetDirectoryName(fileFilePath), targetDirectory,
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
/// 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 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}";
}
}