Fix log message.
Only display log if related books exist.
Resize very large author images.
MODIFY
XRayBuilder.Core/src/Libraries/Http/HttpClient.cs
XRayBuilder.Core/src/Libraries/Http/HttpClient.cs
@@ -58,11 +58,17 @@ public async Task<HtmlDocument> GetPageAsync(string url, CancellationToken cance
}
// TODO should this return image not bitmap?
- public async Task<Bitmap> GetImageAsync(string url, bool greyscale = false, CancellationToken cancellationToken = default)
+ public async Task<Bitmap> GetImageAsync(string url, int maxWidthHeight = -1, bool greyscale = false, CancellationToken cancellationToken = default)
{
var response = await GetStreamAsync(url, cancellationToken);
var image = new Bitmap(response);
+ if (maxWidthHeight > -1 && (image.Height > maxWidthHeight || image.Width > maxWidthHeight))
+ {
+ var scaledImage = image.Scale(maxWidthHeight, maxWidthHeight, false);
+ image = (Bitmap) scaledImage;
+ }
+
image = greyscale
? (Bitmap) image.ToGrayscale3()
: image;
@@ -70,11 +76,11 @@ public async Task<Bitmap> GetImageAsync(string url, bool greyscale = false, Canc
return image;
}
- public async IAsyncEnumerable<Bitmap> GetImages(IEnumerable<string> urls, bool greyscale = false, [EnumeratorCancellation] CancellationToken cancellationToken = default)
+ public async IAsyncEnumerable<Bitmap> GetImages(IEnumerable<string> urls, int maxWidthHeight = -1, bool greyscale = false, [EnumeratorCancellation] CancellationToken cancellationToken = default)
{
foreach (var url in urls.Where(url => !string.IsNullOrEmpty(url)))
{
- yield return await GetImageAsync(url, greyscale, cancellationToken);
+ yield return await GetImageAsync(url, maxWidthHeight, greyscale, cancellationToken);
}
}

MODIFY
XRayBuilder.Core/src/Libraries/Http/IHttpClient.cs
XRayBuilder.Core/src/Libraries/Http/IHttpClient.cs
@@ -15,8 +15,8 @@ public interface IHttpClient
Task<string> GetStringAsync(string url, CancellationToken cancellationToken);
Task<Stream> GetStreamAsync(string url, CancellationToken cancellationToken);
Task<HtmlDocument> GetPageAsync(string url, CancellationToken cancellationToken = default);
- Task<Bitmap> GetImageAsync(string url, bool greyscale = false, CancellationToken cancellationToken = default);
- IAsyncEnumerable<Bitmap> GetImages(IEnumerable<string> urls, bool greyscale = false, CancellationToken cancellationToken = default);
+ Task<Bitmap> GetImageAsync(string url, int maxWidthHeight = -1, bool greyscale = false, CancellationToken cancellationToken = default);
+ IAsyncEnumerable<Bitmap> GetImages(IEnumerable<string> urls, int maxWidthHeight = -1, bool greyscale = false, CancellationToken cancellationToken = default);
Task<HttpResponseMessage> GetAsync(string requestUri);
Task<HttpResponseMessage> GetAsync(Uri requestUri);
Task<HttpResponseMessage> GetAsync(string requestUri, HttpCompletionOption completionOption);

MODIFY
XRayBuilder.Core/src/Libraries/Images/Extensions/ImageExtensions.cs
XRayBuilder.Core/src/Libraries/Images/Extensions/ImageExtensions.cs
using System;
using System.Drawing;
+using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
@@ -49,5 +50,74 @@ public static string ToBase64(this Image image, ImageFormat format)
image.Save(ms, format);
return Convert.ToBase64String(ms.ToArray());
}
+
+ /// <summary>
+ /// Resize the image to the specified width and height.
+ /// https://stackoverflow.com/a/10323949
+ /// InterpolationMode HighQualityBicubic introducing artifacts on edge of resized images
+ /// https://stackoverflow.com/a/8312531
+ /// </summary>
+ /// <param name="original">The image to resize.</param>
+ /// <param name="width">The width to resize to.</param>
+ /// <param name="height">The height to resize to.</param>
+ /// <param name="fill">Fill the resized image keeping aspect ratio.</param>
+ /// <returns>The resized image.</returns>
+ public static Image Scale(this Image original, int width, int height, bool fill)
+ {
+ #region Calculations
+
+ var sourceWidth = original.Width;
+ var sourceHeight = original.Height;
+ const int sourceX = 0;
+ const int sourceY = 0;
+ double destX = 0;
+ double destY = 0;
+
+ double nScale;
+
+ var nScaleW = width / (double)sourceWidth;
+ var nScaleH = height / (double) sourceHeight;
+ if (!fill)
+ {
+ nScale = Math.Min(nScaleH, nScaleW);
+ }
+ else
+ {
+ nScale = Math.Max(nScaleH, nScaleW);
+ destY = (height - sourceHeight * nScale) / 2;
+ destX = (width - sourceWidth * nScale) / 2;
+ }
+
+ var destWidth = (int) Math.Round(sourceWidth * nScale);
+ var destHeight = (int) Math.Round(sourceHeight * nScale);
+
+ #endregion
+
+ Bitmap bmPhoto;
+ try
+ {
+ bmPhoto = new Bitmap(destWidth + (int) Math.Round(2 * destX), destHeight + (int) Math.Round(2 * destY));
+ }
+ catch (Exception)
+ {
+ return new Bitmap(original);
+ }
+
+ using var grPhoto = Graphics.FromImage(bmPhoto);
+ grPhoto.CompositingMode = CompositingMode.SourceCopy;
+ grPhoto.InterpolationMode = InterpolationMode.HighQualityBicubic;
+ grPhoto.PixelOffsetMode = PixelOffsetMode.HighQuality;
+ grPhoto.CompositingQuality = CompositingQuality.HighQuality;
+ grPhoto.SmoothingMode = SmoothingMode.HighQuality;
+
+ var to = new Rectangle((int) Math.Round(destX), (int) Math.Round(destY), destWidth, destHeight);
+ var from = new Rectangle(sourceX, sourceY, sourceWidth, sourceHeight);
+
+ using var wrapMode = new ImageAttributes();
+ wrapMode.SetWrapMode(WrapMode.TileFlipXY);
+ grPhoto.DrawImage(original, to, 0, 0, from.Width, from.Height, GraphicsUnit.Pixel, wrapMode);
+
+ return bmPhoto;
+ }
}
}
\ No newline at end of file

MODIFY
XRayBuilder/src/UI/Preview/frmPreviewEA.cs
XRayBuilder/src/UI/Preview/frmPreviewEA.cs
@@ -22,6 +22,8 @@ public partial class frmPreviewEA : Form, IPreviewForm
private readonly Settings _settings = Settings.Default;
private string _authorUrl = string.Empty;
+ private const int MaxImageSize = 750;
+
#region SET LISTVIEW ICON SPACING
// http://qdevblog.blogspot.ch/2011/11/c-listview-item-spacing.html
@@ -80,7 +82,7 @@ public async Task Populate(string inputFile, CancellationToken cancellationToken
lblAuthor.Text = author.Name;
lblAuthorRecs.Text = $@"More by {author.Name}";
if (!string.IsNullOrEmpty(author.ImageUrl))
- pbAuthor.Image = await _httpClient.GetImageAsync(author.ImageUrl, false, cancellationToken);
+ pbAuthor.Image = await _httpClient.GetImageAsync(author.ImageUrl, MaxImageSize, false, cancellationToken);
}
if (endActions.Data.PublicSharedRating != null)
@@ -109,7 +111,7 @@ public async Task Populate(string inputFile, CancellationToken cancellationToken
var nextBook = endActions.Data.NextBook;
txtNextInSeries.Text = nextBook.Title;
if (!string.IsNullOrEmpty(nextBook.ImageUrl))
- pbNextCover.Image = await _httpClient.GetImageAsync(nextBook.ImageUrl, false, cancellationToken);
+ pbNextCover.Image = await _httpClient.GetImageAsync(nextBook.ImageUrl, MaxImageSize, false, cancellationToken);
}
else
{
@@ -130,7 +132,7 @@ private async Task PopulateImagesFromBooks(ListView listView, ImageList imageLis
ListViewItem_SetSpacing(listView, 60 + 12, 90 + 12);
var urls = books.Select(book => book.ImageUrl);
- var images = await _httpClient.GetImages(urls, false, cancellationToken).ToArrayAsync(cancellationToken);
+ var images = await _httpClient.GetImages(urls, MaxImageSize, false, cancellationToken).ToArrayAsync(cancellationToken);
var i = 0;
foreach (var image in images)

MODIFY
XRayBuilder/src/UI/Preview/frmPreviewSA.cs
XRayBuilder/src/UI/Preview/frmPreviewSA.cs
@@ -20,6 +20,7 @@ public partial class frmPreviewSA : Form, IPreviewForm
private readonly IHttpClient _httpClient;
private readonly Regex _regexHighlights = new Regex(@"(?<text>(?<num>[\d,.]+) passages have been highlighted (?<total>[\d,.]+) times)", RegexOptions.Compiled);
+ private const int MaxImageSize = 750;
public frmPreviewSA(IHttpClient httpClient)
{
@@ -95,7 +96,7 @@ public async Task Populate(string inputFile, CancellationToken cancellationToken
{
var imageUrl = author.ImageUrl;
if (!string.IsNullOrEmpty(imageUrl))
- pbAuthorImage.Image = await _httpClient.GetImageAsync(imageUrl, false, cancellationToken);
+ pbAuthorImage.Image = await _httpClient.GetImageAsync(imageUrl, MaxImageSize, false, cancellationToken);
lblBiography.Text = author.Bio;
}
@@ -106,7 +107,7 @@ public async Task Populate(string inputFile, CancellationToken cancellationToken
{
var imageUrl = rec.ImageUrl;
if (!string.IsNullOrEmpty(imageUrl))
- ilOtherBooks.Images.Add(await _httpClient.GetImageAsync(imageUrl, false, cancellationToken));
+ ilOtherBooks.Images.Add(await _httpClient.GetImageAsync(imageUrl, MaxImageSize, false, cancellationToken));
}
ListViewItem_SetSpacing(lvOtherBooks, 60 + 12, 90 + 12);
for (var i = 0; i < ilOtherBooks.Images.Count; i++)
@@ -128,7 +129,7 @@ public async Task Populate(string inputFile, CancellationToken cancellationToken
lblPreviousTitle.Text = startActions.Data.PreviousBookInTheSeries.Title;
var imageUrl = startActions.Data.PreviousBookInTheSeries.ImageUrl;
if (!string.IsNullOrEmpty(imageUrl))
- pbPreviousCover.Image = await _httpClient.GetImageAsync(imageUrl, false, cancellationToken);
+ pbPreviousCover.Image = await _httpClient.GetImageAsync(imageUrl, MaxImageSize, false, cancellationToken);
}
}

MODIFY
XRayBuilder/src/UI/frmMain.cs
XRayBuilder/src/UI/frmMain.cs
@@ -465,7 +465,7 @@ private async Task btnKindleExtras_Run()
{
_logger.Log(MainStrings.WritingStartActionsFile);
File.WriteAllText(saPath, Functions.ExpandUnicode(JsonConvert.SerializeObject(startActions)));
- _logger.Log($@"{MainStrings.StartActionsCreated}\r\n{string.Format(MainStrings.SavedTo, saPath)}");
+ _logger.Log($@"{MainStrings.StartActionsCreated}{Environment.NewLine}{string.Format(MainStrings.SavedTo, saPath)}");
needSa = false;
}
}
@@ -486,7 +486,7 @@ private async Task btnKindleExtras_Run()
{
_logger.Log(MainStrings.WritingEndActionsFile);
File.WriteAllText(eaPath, Functions.ExpandUnicode(JsonConvert.SerializeObject(endActions)));
- _logger.Log($@"{MainStrings.EndActionsCreated}\r\n{string.Format(MainStrings.SavedTo, eaPath)}");
+ _logger.Log($@"{MainStrings.EndActionsCreated}{Environment.NewLine}{string.Format(MainStrings.SavedTo, eaPath)}");
needEa = false;
}
}
@@ -629,7 +629,7 @@ string AsinPrompt(string title, string author)
_logger.Log($@"{MainStrings.ErrorCreatingStartActions}: {ex.Message}{Environment.NewLine}{ex.StackTrace}");
}
- _logger.Log($@"{MainStrings.StartActionsCreated}\r\n{string.Format(MainStrings.SavedTo, saPath)}");
+ _logger.Log($@"{MainStrings.StartActionsCreated}{Environment.NewLine}{string.Format(MainStrings.SavedTo, saPath)}");
}
}
@@ -797,6 +797,7 @@ private void Form1_FormClosing(object sender, FormClosingEventArgs e)
_settings.mobiFile = txtMobi.Text;
_settings.xmlFile = txtXMLFile.Text;
_settings.Goodreads = txtGoodreads.Text;
+ _settings.Save();
if (txtOutput.Text.Trim().Length != 0)
File.WriteAllText(_currentLog, txtOutput.Text);

Fix log message.
Only display log if related books exist.
Resize very large author images.