I have an error:
Parameter is not valid.
This error occurs about 1 in 5 times.
The error occurs on this line:
TextRenderer.DrawText(drawing, "Code12", font, fullWidthRectangle,
textColor,
flags);
Small code example (not actual code):
public Image CreateTripDetailPreview(Image image)
{
using (var fontCollection = new PrivateFontCollection())
using (var fontCollectionBold = new PrivateFontCollection())
{
fontCollection.AddFontFile("Assets\\SourceSansPro-Regular.ttf");
fontCollectionBold.AddFontFile("Assets\\SourceSansPro-Bold.ttf");
//This will be used to define heigt of text and allign text
Rectangle fullWidthRectangle;
var widthInDip = 360;
var imgHeigtInDip = 168;
var canvasWidth = 1080;
var canvasHeight = 1200;
var dip = canvasWidth / widthInDip;
var leftRightMargin = 15 * dip;
var resolutionScale = 5;
using (Image img = new Bitmap(canvasWidth * resolutionScale, canvasHeight * resolutionScale))
using (Graphics drawing = Graphics.FromImage(img))
{
//Clear 'background' and make it white
drawing.Clear(Color.White);
var imageHeight = (int)167.5 * dip;
var height = imageHeight * resolutionScale;
using (var cityImageBitmap = new Bitmap(image))
using (var resizedCityImage = new Bitmap(cityImageBitmap, new Size(canvasWidth, imageHeight)))
{
canvasWidth *= resolutionScale;
canvasHeight *= resolutionScale;
dip *= resolutionScale;
leftRightMargin *= resolutionScale;
TextFormatFlags flags;
using (var regularFont = new Font(fontCollection.Families[0], 1, FontStyle.Regular))
using (var boldFont = new Font(fontCollectionBold.Families[0], 1, FontStyle.Regular)
) //1 as default fontsize, fontsize will be calculated for each property
{
Color textColor = Color.FromArgb(102, 102, 102);
//FlightCode
height += 4 * dip;
fullWidthRectangle = new Rectangle(leftRightMargin, height,
canvasWidth - leftRightMargin * 2,
(int)22.5 * dip);
using (Font font = GetFontSizeByBox(drawing, "Code12",
fullWidthRectangle.Size,
regularFont))
{
flags = TextFormatFlags.NoPadding | TextFormatFlags.HorizontalCenter;
TextRenderer.DrawText(drawing, "Code12", font, fullWidthRectangle,
textColor,
flags);
}
using (var result = new Bitmap(img, canvasWidth / resolutionScale, canvasHeight / resolutionScale))
using (Graphics drawing2 = Graphics.FromImage(result))
{
drawing2.DrawImage(resizedCityImage, new Point(0, 0));
return new Bitmap(result);
}
}
}
}
}
}
GetFontSizeByBox method:
private static Font GetFontSizeByBox(Graphics g, string longString, Size room, Font preferedFont, int extraSize = 0)
{
SizeF realSize = g.MeasureString(longString, preferedFont);
var heightScaleRatio = room.Height / realSize.Height;
var widthScaleRatio = room.Width / realSize.Width;
var scaleRatio = heightScaleRatio < widthScaleRatio ? heightScaleRatio : widthScaleRatio;
var scaleFontSize = preferedFont.Size * scaleRatio;
return new Font(preferedFont.FontFamily, scaleFontSize + extraSize, preferedFont.Style);
}
Notes
GC.Collect()
at the top of this method fixes the problem, I do not wish to use this 'fix' as its better to prevent it. Values of DrawText when error occurs:
Name = "Source Sans Pro" Size=179.088287
(properties accessible)X = 225 Y = 2565 Width = 4950 Height = 330
Name=ff666666, ARGB=(255, 102, 102, 102)
TextFormatFlags.HorizontalCenter | TextFormatFlags.NoPadding
If anyone know why I'm getting this error or how to fix it, any help is appreciated.
Ok I found the solution, as Hans Passant said GC.Collect();
at the top of the method will fix the problems. This did indeed work but I wanted to find out why.
The way the code is structured all the disposable objects will be disposed after the method is done (because of all the using statements), there is enough memory in a 32bit
application to run this method once or twice. But as soon as the method is called with some generations of garbage still present it would crash on making the bitmap.
Solution:
If you have this problem and you don't wan't to force garbage collection each time you run your method you can set a threshold like so:
if( Process.GetCurrentProcess().PrivateMemorySize64 > someNumber )
{
GC.Collect();
}
Turns out this did not work for me as the threshold was hit every time, so I just settled with the GC.Collect();
every time. If anyone has a better solution (not increasing memory) don't hesitate to post.