Enhance image processing performance and flexibility by introducing atomic counters, improving file pattern matching, and refining logo positioning logic.
This commit is contained in:
parent
ba965e8266
commit
68c1106f65
8 changed files with 134 additions and 68 deletions
|
|
@ -88,7 +88,28 @@ namespace MaddoShared
|
|||
|
||||
DirectoryInfo destDir;
|
||||
destDir = new DirectoryInfo(Path.Combine(dirDest.FullName));
|
||||
foreach (FileInfo file in dir.GetFiles(filter))
|
||||
|
||||
// Support multiple patterns separated by ';' or ','
|
||||
var patterns = (filter ?? "*").Split(new[] { ';', ',' }, StringSplitOptions.RemoveEmptyEntries).Select(p => p.Trim()).ToArray();
|
||||
|
||||
// Collect matching files for all patterns and avoid duplicates
|
||||
var matchedFiles = new List<FileInfo>();
|
||||
foreach (var pat in patterns)
|
||||
{
|
||||
try
|
||||
{
|
||||
matchedFiles.AddRange(dir.GetFiles(pat));
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore pattern errors and continue
|
||||
}
|
||||
}
|
||||
|
||||
// Remove duplicates (by FullName)
|
||||
var distinctFiles = matchedFiles.GroupBy(f => f.FullName, StringComparer.OrdinalIgnoreCase).Select(g => g.First()).OrderBy(f => f.Name).ToList();
|
||||
|
||||
foreach (FileInfo file in distinctFiles)
|
||||
{
|
||||
contaFilePerDir += 1;
|
||||
|
||||
|
|
|
|||
|
|
@ -142,13 +142,17 @@ namespace MaddoShared
|
|||
|
||||
private List<FileData> GetFilesToProcess(Options options)
|
||||
{
|
||||
// Support multiple common JPEG patterns so files named .jpeg, .jpe, etc. are included
|
||||
var jpgPatterns = new[] { "*.jpg", "*.jpeg", "*.jpe", "*.jfif", "*.pjpeg", "*.pjp" };
|
||||
|
||||
if (options.AggiornaSottodirectory && options.CreaSottocartelle)
|
||||
{
|
||||
var helper = new FileHelperSharp();
|
||||
// Pass patterns joined by ';' - FileHelperSharp will split and handle multiple patterns
|
||||
return helper.GetFilesRecursive(
|
||||
new DirectoryInfo(options.SourcePath),
|
||||
new DirectoryInfo(options.DestinationPath),
|
||||
"*.jpg",
|
||||
string.Join(";", jpgPatterns),
|
||||
new FileHelperOptions
|
||||
{
|
||||
FilesPerFolder = options.FilePerCartella,
|
||||
|
|
@ -158,10 +162,13 @@ namespace MaddoShared
|
|||
});
|
||||
}
|
||||
|
||||
var files = Directory.EnumerateFiles(
|
||||
options.SourcePath,
|
||||
"*.jpg",
|
||||
options.AggiornaSottodirectory ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
|
||||
// For non-recursive or recursive enumeration without using the helper, enumerate for each pattern
|
||||
var searchOption = options.AggiornaSottodirectory ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
|
||||
|
||||
var files = jpgPatterns
|
||||
.SelectMany(p => Directory.EnumerateFiles(options.SourcePath, p, searchOption))
|
||||
.Distinct()
|
||||
.ToList();
|
||||
|
||||
return files.Select(x =>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -267,26 +267,36 @@ public class ImageCreatorSharp(PicSettings picSettings, ILogger<ImageCreatorShar
|
|||
using var graphics = Graphics.FromImage(imgOutputSmall);
|
||||
graphics.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
|
||||
imgState.DimensioneStandardMiniatura = 50;
|
||||
|
||||
// Use the user's configured font size directly
|
||||
using var font1 = CreateFont(picSettings.IlFont, imgState.DimensioneStandardMiniatura, picSettings.Grassetto);
|
||||
var textSize = graphics.MeasureString(imgState.TestoFirmaPiccola, font1);
|
||||
|
||||
AdjustFontToFitWidth(graphics, image.Width, imgState, ref textSize);
|
||||
// Adjust font if it's too large for the image dimensions
|
||||
// Keep text height under 15% of image height to ensure proper spacing when resized
|
||||
// This leaves room for margins and prevents clipping
|
||||
int tempFontSize = imgState.DimensioneStandardMiniatura;
|
||||
float maxTextHeight = image.Height * 0.15f;
|
||||
|
||||
while ((textSize.Width > image.Width * 0.95f || textSize.Height > maxTextHeight) && tempFontSize > 5)
|
||||
{
|
||||
tempFontSize = (tempFontSize > 20) ? tempFontSize - 5 : tempFontSize - 1;
|
||||
using var tempFont = CreateFont(picSettings.IlFont, tempFontSize, picSettings.Grassetto);
|
||||
textSize = graphics.MeasureString(imgState.TestoFirmaPiccola, tempFont);
|
||||
}
|
||||
|
||||
SetVerticalPosition(image.Height, textSize.Height, imgState);
|
||||
// Re-measure text with the final font size for accurate positioning
|
||||
using var finalFont = CreateFont(picSettings.IlFont, tempFontSize, picSettings.Grassetto);
|
||||
var finalTextSize = graphics.MeasureString(imgState.TestoFirmaPiccola, finalFont);
|
||||
|
||||
float xCenter = CalculateHorizontalAlignment(image.Width, textSize.Width);
|
||||
SetVerticalPosition(image.Height, finalTextSize.Height, imgState);
|
||||
|
||||
float xCenter = CalculateHorizontalAlignment(image.Width, finalTextSize.Width);
|
||||
using var stringFormat = new StringFormat();
|
||||
stringFormat.Alignment = StringAlignment.Center;
|
||||
|
||||
using var shadowBrush = new SolidBrush(Color.FromArgb(imgState.AlphaScelta, 0, 0, 0));
|
||||
using var textBrush = new SolidBrush(Color.FromArgb(imgState.AlphaScelta, picSettings.FontColoreRGB));
|
||||
|
||||
imgState.DimensioneStandardMiniatura = picSettings.DimMin;
|
||||
|
||||
using var finalFont =
|
||||
CreateFont(picSettings.IlFont, imgState.DimensioneStandardMiniatura, picSettings.Grassetto);
|
||||
DrawText(graphics, imgState, xCenter, stringFormat, shadowBrush, textBrush, finalFont);
|
||||
|
||||
using var finalThumb =
|
||||
|
|
@ -324,20 +334,6 @@ public class ImageCreatorSharp(PicSettings picSettings, ILogger<ImageCreatorShar
|
|||
return best;
|
||||
}
|
||||
|
||||
private void AdjustFontToFitWidth(Graphics g, int maxWidth, ImageState imgState, ref SizeF size)
|
||||
{
|
||||
int currentSize = imgState.DimensioneStandardMiniatura;
|
||||
|
||||
while (size.Width > maxWidth && currentSize > 5)
|
||||
{
|
||||
currentSize = (currentSize > 20) ? currentSize - 5 : currentSize - 1;
|
||||
using var tempFont = CreateFont(picSettings.IlFont, currentSize, picSettings.Grassetto);
|
||||
size = g.MeasureString(imgState.TestoFirmaPiccola, tempFont);
|
||||
//tempFont.Dispose();
|
||||
}
|
||||
|
||||
imgState.DimensioneStandardMiniatura = currentSize;
|
||||
}
|
||||
|
||||
private void AddText(Image g, ImageState imgState, Bitmap imgOutputBig)
|
||||
{
|
||||
|
|
@ -493,11 +489,17 @@ public class ImageCreatorSharp(PicSettings picSettings, ILogger<ImageCreatorShar
|
|||
imageAttributes.SetRemapTable(remapTable, ColorAdjustType.Bitmap);
|
||||
|
||||
// * The second color manipulation is used to change the opacity by setting the 3rd row and 3rd column to 0.3f
|
||||
// Parse transparency safely (default to 100 if parsing fails)
|
||||
if (!int.TryParse(picSettings.LogoTrasparenza, out var logoTransparencyValue))
|
||||
{
|
||||
logoTransparencyValue = 100;
|
||||
}
|
||||
|
||||
var colorMatrixElements = new[]
|
||||
{
|
||||
new[] { 1.0F, 0.0F, 0.0F, 0.0F, 0.0F }, new[] { 0.0F, 1.0F, 0.0F, 0.0F, 0.0F },
|
||||
new[] { 0.0F, 0.0F, 1.0F, 0.0F, 0.0F },
|
||||
new[] { 0.0F, 0.0F, 0.0F, System.Convert.ToSingle(picSettings.LogoTrasparenza) / 100F, 0.0F },
|
||||
new[] { 0.0F, 0.0F, 0.0F, System.Convert.ToSingle(logoTransparencyValue) / 100F, 0.0F },
|
||||
new[] { 0.0F, 0.0F, 0.0F, 0.0F, 1.0F }
|
||||
};
|
||||
var wmColorMatrix = new ColorMatrix(colorMatrixElements);
|
||||
|
|
@ -511,14 +513,27 @@ public class ImageCreatorSharp(PicSettings picSettings, ILogger<ImageCreatorShar
|
|||
? CalculateThumbnailSize(logo.Width, logo.Height, fotoLogoW, "Larghezza")
|
||||
: CalculateThumbnailSize(logo.Width, logo.Height, fotoLogoH, "Altezza");
|
||||
|
||||
var inPercentualeL = picSettings.LogoMargine.EndsWith('%');
|
||||
var margineL = System.Convert.ToInt32(picSettings.LogoMargine);
|
||||
// Guard against null/empty LogoMargine and percentage parsing
|
||||
var logoMargineStr = picSettings.LogoMargine ?? string.Empty;
|
||||
var inPercentualeL = logoMargineStr.EndsWith('%');
|
||||
var margineL = 0;
|
||||
if (inPercentualeL)
|
||||
{
|
||||
var trimmed = logoMargineStr.TrimEnd('%');
|
||||
if (!int.TryParse(trimmed, out margineL)) margineL = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!int.TryParse(logoMargineStr, out margineL)) margineL = 0;
|
||||
}
|
||||
var margineUsato =
|
||||
inPercentualeL ? System.Convert.ToInt32(imgOutputBig.Height * margineL / (double)100) : margineL;
|
||||
|
||||
int xPosOfWm = 0;
|
||||
int yPosOfWm = 0;
|
||||
switch (picSettings.LogoPosizioneH.ToUpper())
|
||||
var logoH = (picSettings.LogoPosizioneH ?? "NESSUNA").ToUpperInvariant();
|
||||
var logoV = (picSettings.LogoPosizioneV ?? "NESSUNA").ToUpperInvariant();
|
||||
switch (logoH)
|
||||
{
|
||||
case "SINISTRA":
|
||||
case "NESSUNA":
|
||||
|
|
@ -540,7 +555,7 @@ public class ImageCreatorSharp(PicSettings picSettings, ILogger<ImageCreatorShar
|
|||
}
|
||||
}
|
||||
|
||||
switch (picSettings.LogoPosizioneV.ToUpper())
|
||||
switch (logoV)
|
||||
{
|
||||
case "ALTO":
|
||||
case "NESSUNA":
|
||||
|
|
@ -725,16 +740,42 @@ public class ImageCreatorSharp(PicSettings picSettings, ILogger<ImageCreatorShar
|
|||
|
||||
private void SetVerticalPosition(int imgHeight, float textHeight, ImageState imgState)
|
||||
{
|
||||
// Use 1% of image height as minimum margin, or 10px, whichever is larger
|
||||
float minMargin = Math.Max(10f, imgHeight * 0.01f);
|
||||
|
||||
switch (picSettings.Posizione.ToUpper())
|
||||
{
|
||||
case "ALTO":
|
||||
imgState.YPosFromBottom1 = picSettings.Margine;
|
||||
imgState.YPosFromBottom4 = picSettings.MargVert;
|
||||
imgState.YPosFromBottom1 = Math.Max(minMargin, picSettings.Margine);
|
||||
imgState.YPosFromBottom4 = Math.Max(minMargin, picSettings.MargVert);
|
||||
break;
|
||||
|
||||
case "BASSO":
|
||||
imgState.YPosFromBottom1 = (float)(imgHeight - textHeight - (imgHeight * picSettings.Margine / 100.0));
|
||||
imgState.YPosFromBottom4 = (float)(imgHeight - textHeight - (imgHeight * picSettings.MargVert / 100.0));
|
||||
var bottomMargin1 = (float)(imgHeight * picSettings.Margine / 100.0);
|
||||
var bottomMargin4 = (float)(imgHeight * picSettings.MargVert / 100.0);
|
||||
|
||||
// Position from bottom: bottom edge of text at desired margin from bottom
|
||||
// Y = imageHeight - textHeight - bottomMargin
|
||||
var desiredY1 = imgHeight - textHeight - bottomMargin1;
|
||||
var desiredY4 = imgHeight - textHeight - bottomMargin4;
|
||||
|
||||
// Ensure text stays completely within bounds:
|
||||
// - Top edge must be >= minMargin (not clipped at top)
|
||||
// - Bottom edge must be <= imgHeight - minMargin (not clipped at bottom)
|
||||
var maxAllowedY1 = imgHeight - textHeight - minMargin; // Maximum Y to keep bottom margin
|
||||
var maxAllowedY4 = imgHeight - textHeight - minMargin;
|
||||
|
||||
imgState.YPosFromBottom1 = Math.Max(minMargin, Math.Min(desiredY1, maxAllowedY1));
|
||||
imgState.YPosFromBottom4 = Math.Max(minMargin, Math.Min(desiredY4, maxAllowedY4));
|
||||
break;
|
||||
|
||||
case "CENTRO":
|
||||
default:
|
||||
// Center the text vertically
|
||||
var centeredY = (imgHeight - textHeight) / 2f;
|
||||
// Clamp to ensure margins are respected
|
||||
imgState.YPosFromBottom1 = Math.Max(minMargin, Math.Min(centeredY, imgHeight - textHeight - minMargin));
|
||||
imgState.YPosFromBottom4 = imgState.YPosFromBottom1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AsyncEnumerator" Version="4.0.2" />
|
||||
<PackageReference Include="AutoMapper" Version="16.0.0" />
|
||||
<PackageReference Include="Ben.Demystifier" Version="0.4.1" />
|
||||
<PackageReference Include="IDisposableAnalyzers" Version="4.0.8">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
|
|
@ -20,7 +19,7 @@
|
|||
<PackageReference Include="Microsoft.Extensions.Logging" Version="10.0.2" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.12" />
|
||||
<PackageReference Include="System.Buffers" Version="4.6.1" />
|
||||
<PackageReference Include="System.Collections.Immutable" Version="10.0.2" />
|
||||
<PackageReference Include="System.Collections.Immutable" Version="9.0.7" />
|
||||
<PackageReference Include="System.Memory" Version="4.6.3" />
|
||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.1.2" />
|
||||
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.6.3" />
|
||||
|
|
@ -28,6 +27,6 @@
|
|||
<PackageReference Include="Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers" Version="0.4.421302">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Windows.Compatibility" Version="10.0.2" />
|
||||
<PackageReference Include="Microsoft.Windows.Compatibility" Version="9.0.7" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -38,9 +38,10 @@ public class PicSettings
|
|||
public int LogoLarghezza { get; set; }
|
||||
public Color FontColoreRGB { get; set; }
|
||||
public bool LogoAggiungi { get; set; }
|
||||
public string LogoNomeFile { get; set; }
|
||||
public string LogoTrasparenza { get; set; }
|
||||
public string LogoMargine { get; set; }
|
||||
// Initialize logo-related strings to safe defaults to avoid null reference issues
|
||||
public string LogoNomeFile { get; set; } = string.Empty;
|
||||
public string LogoTrasparenza { get; set; } = "100";
|
||||
public string LogoMargine { get; set; } = "0";
|
||||
public string LogoPosizioneH { get; set; }
|
||||
public string LogoPosizioneV { get; set; }
|
||||
public bool FotoGrandeDimOrigina { get; set; }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue