I am looking for some explanation about some weird texts that appears when I write on a bitmap and then upload it to azure blob.
Sometimes when I create an imagem, it comes with theses weird texts where there should be accents. But I recreate it right after and it works...
Here is the imagem gone wrong: https://www.dropbox.com/s/8an62ygys5nnwow/uploaded-image-636488352376069747.png?dl=0
And here is the correct image:
https://www.dropbox.com/s/q3sdsqo3d05skz8/uploaded-image-636493880034621618.png?dl=0
I convert the image url to bitmap:
var request = System.Net.WebRequest.Create(url);
var response = request.GetResponse();
using (var responseStream = response.GetResponseStream())
{
var bitmap = new Bitmap(responseStream);
return bitmap;
}
And then I write the text on it:
private void AddText(System.Drawing.Image image, string text, int x, int y, int width, int height, int fontSize, Color fontColor, Color borderColor, FontFamily fontFamily, FontStyle fontStyle, StringAlignment horizontalAligment, StringAlignment verticalAligment, bool autoFit, int shadowOffsetX, int shadowOffsetY, Color shadowColor, int? maxHeight, out float finalHeight, out float finalWidth)
{
var graphics = Graphics.FromImage(image);
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
var rect = new Rectangle(x, y, width, height);
StringFormat stringFormat = new StringFormat
{
Alignment = horizontalAligment,
LineAlignment = verticalAligment
};
var font = new System.Drawing.Font(fontFamily, graphics.DpiY * fontSize / 72, fontStyle);
if (autoFit)
{
font = FindFont(graphics, text, rect.Size, font);
}
var hasShadow = shadowOffsetX > 0 && shadowOffsetY > 0;
var hasMaxHeight = maxHeight != null && maxHeight.Value > 0;
if (hasShadow)
{
var shadowGraphicsPath = new GraphicsPath();
var shadowRect = new Rectangle(x + shadowOffsetX, y + shadowOffsetY, width, height);
shadowGraphicsPath.AddString(text, fontFamily, (int)fontStyle, font.Size, shadowRect, stringFormat);
if (hasMaxHeight)
{
shadowGraphicsPath = GetTextWithMaxHeight(text, fontFamily, fontStyle, shadowRect, stringFormat, shadowGraphicsPath, font, maxHeight.Value, out float newFontSize);
font = new System.Drawing.Font(font.FontFamily, newFontSize);
}
graphics.FillPath(new SolidBrush(shadowColor), shadowGraphicsPath);
graphics.Flush();
shadowGraphicsPath.Dispose();
}
var graphicsPath = new GraphicsPath();
graphicsPath.AddString(text, fontFamily, (int)fontStyle, font.Size, rect, stringFormat);
if (hasMaxHeight && !hasShadow)
{
graphicsPath = GetTextWithMaxHeight(text, fontFamily, fontStyle, rect, stringFormat, graphicsPath, font, maxHeight.Value, out float newFontSize);
}
graphics.DrawPath(new Pen(borderColor), graphicsPath);
graphics.FillPath(new SolidBrush(fontColor), graphicsPath);
finalHeight = graphicsPath.GetBounds().Height;
finalWidth = graphicsPath.GetBounds().Width;
graphics.Flush();
graphicsPath.Dispose();
}
And then I upload to azure blob
var container = _blobClient.GetContainerReference(_imageConfiguration.BlobContainer);
var blockBlob = container.GetBlockBlobReference($"uploaded-image-{DateTime.Now.ToUniversalTime().Ticks}.png");
using (var imageStream = ConvertToStream(image, ImageFormat.Png))
{
blockBlob.UploadFromStream(imageStream);
var uri = blockBlob.Uri;
return uri;
}
Can someone help me find an explanation for this?
Related
I'm writing a simple application in c# .net core 6 and winform to "assemble" some pngs and write some text on it.
This is the Photoshop output. The Title "Baldur the invincible" is wrote in Diablo Light when i'm writing it with DrawString with Font("Diablo", 30, FontStyle.Regular)
and this is my output with the Font.
In photoshop i used Diablo Light font but in the list of system fonts, from C# code, i see just Diablo Regular.. and the result is different.
How i can set the fontweight ?
here some code:
// ---------------------------------------------------------------------------------------------- +
// All TEXT ------------------------------------------------------------------------------------- +
// ---------------------------------------------------------------------------------------------- +
{
//string familyName;
//string familyList = "";
//FontFamily[] fontFamilies;
//InstalledFontCollection installedFontCollection = new InstalledFontCollection();
//fontFamilies = installedFontCollection.Families;
Font title_font = new Font("Diablo", 30, FontStyle.Regular);
Font sub_font = new Font("Diablo", 25, FontStyle.Regular);
List<Font> list_fonts = new List<Font>();
list_fonts.Add(title_font);
list_fonts.Add(sub_font);
RectangleF tit_rect = new RectangleF(165, 70, w - (165 * 2), h);
//RectangleF sub_rect = new RectangleF(165, 82 + 30, w - (165 * 2), h);
var v = m_dict_titles["Title"];
string curr_string = tabbed_value[v].ToUpper();
float offsety = WriteTitleTextf2(map_back, 0, TL(curr_string, false), tit_rect, list_fonts, StringAlignment.Near, 5);
}
public void WriteOnBitmapf(Bitmap bmp, int col, Font font, String text, RectangleF rectf, StringAlignment st_align, float stringi = 0.0f)
{
float size = font.Size;
Graphics g = Graphics.FromImage(bmp);
g.SmoothingMode = SmoothingMode.AntiAlias;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
StringFormat format = new StringFormat()
{
Alignment = st_align,
LineAlignment = StringAlignment.Near
};
Brush br = col == 0 ? new SolidBrush(Color.FromArgb(0, 0, 0)) : new SolidBrush(Color.FromArgb(255, 255, 255));
g.DrawString(text, font, br, rectf, format);
g.Flush();
}
I want to draw black text over with grey opacity PNG file so text is BLACK.
What I am getting is the text is some % of grey:
Even if I use Brushes.Black the text is still grey;
My code is following:
List<string> GenerateDeviceIcon(string backgroundImageFile, string deviceImageFile, string deviceNumber, int deviceID, string saveNewFilePath, string fontName, int fontSize, Brush textColor)
{
var r = new List<string>();
try
{
Image background = Image.FromFile(backgroundImageFile);
Image logo = Image.FromFile(deviceImageFile);
PointF firstLocation = new PointF(2f, 2f);
using (background)
{
using (var bitmap = new Bitmap(background.Width, background.Height))
{
using (var canvas = Graphics.FromImage(bitmap))
{
using (Font arialFont = new Font(fontName, fontSize))
{
canvas.DrawString(deviceNumber, arialFont, textColor, firstLocation);
}
canvas.InterpolationMode = InterpolationMode.HighQualityBicubic;
canvas.DrawImage(background, new Rectangle(0, 0, background.Width, background.Height), new Rectangle(0, 0, background.Width, background.Height), GraphicsUnit.Pixel);
canvas.DrawImage(logo, (bitmap.Width / 2) - (logo.Width / 2), (bitmap.Height / 2) - (logo.Height / 2));
canvas.Save();
}
try
{
var filename = Path.Combine(saveNewFilePath, deviceID.ToString() + ".png");
if (File.Exists(filename))
{
File.Delete(filename);
}
bitmap.Save(filename, System.Drawing.Imaging.ImageFormat.Png);
}
catch (Exception ex)
{
r.Add(ex.Message);
}
}
}
}
catch (Exception ex)
{
r.Add(ex.Message);
}
return r;
}
How to fix it?
Many thanks!
Well I found the bug: dont draw text BEFORE you draw a background!
And I've improved the code so it draws multiple lines of a transport ID.
Enjoy if you need create complex icons in .NET!
Code:
static List<string> GenerateDeviceIcon2(string backgroundImageFile, string deviceImageFile,
string deviceNumber, int deviceID, string saveNewFilePath, string fontName, int fontSize, Color textColor)
{
var r = new List<string>();
try
{
Image background = Image.FromFile(backgroundImageFile);
Image logo = Image.FromFile(deviceImageFile);
PointF firstLocation = new PointF(2f, 2f);
#region Create text as Image with Transparancy
//first, create a dummy bitmap just to get a graphics object
Image img = new Bitmap(1, 1);
Graphics drawingText = Graphics.FromImage(img);
//measure the string to see how big the image needs to be
int maxWidth = background.Width - 2;
var font = new Font(fontName, fontSize, new FontStyle());
SizeF textSize = drawingText.MeasureString(deviceNumber, font, maxWidth);
//set the stringformat flags to rtl
StringFormat sf = new StringFormat
{
//uncomment the next line for right to left languages
//sf.FormatFlags = StringFormatFlags.DirectionRightToLeft;
Trimming = StringTrimming.Word
};
//free up the dummy image and old graphics object
img.Dispose();
drawingText.Dispose();
//create a new image of the right size
img = new Bitmap((int)textSize.Width, (int)textSize.Height);
// drawingText = Graphics.FromImage(img);
#endregion
//create a brush for the text
Brush textBrush = new SolidBrush(textColor);
using (background)
{
using (var bitmap = new Bitmap(background.Width, background.Height))
{
using (var canvas = Graphics.FromImage(bitmap))
{
//Adjust for high quality
canvas.CompositingQuality = CompositingQuality.HighQuality;
canvas.InterpolationMode = InterpolationMode.HighQualityBilinear;
canvas.PixelOffsetMode = PixelOffsetMode.HighQuality;
canvas.SmoothingMode = SmoothingMode.HighQuality;
canvas.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
//paint the background
canvas.Clear(Color.Transparent);
// First - draw a background!
canvas.DrawImage(background, new Rectangle(0, 0, background.Width, background.Height),
new Rectangle(0, 0, background.Width, background.Height), GraphicsUnit.Pixel);
// Second - draw the text in multiple rows over background
canvas.DrawImage(logo, (bitmap.Width / 2) - (logo.Width / 2), (bitmap.Height / 2) - (logo.Height / 2));
// Third - draw the logo over background
canvas.DrawString(deviceNumber, font, textBrush, new RectangleF(0, 0, textSize.Width, textSize.Height), sf);
canvas.Save();
}
try
{
var filename = Path.Combine(saveNewFilePath, deviceID.ToString() + ".png");
if (File.Exists(filename))
{
File.Delete(filename);
}
bitmap.Save(filename, System.Drawing.Imaging.ImageFormat.Png);
}
catch (Exception ex)
{
r.Add(ex.Message);
}
}
}
textBrush.Dispose();
img.Dispose();
}
catch (Exception ex)
{
r.Add(ex.Message);
}
return r;
}
I'm attempting to draw some centered text inside of a custom panel control. I'm able to create the text path using GraphicsPath.AddString and draw the text using Graphics.FillPath. Here's the code I'm using (it resides inside the custom panel control).
public void ApplyCenteredTextMessage(string message, FontStyle fontStyle)
{
using (Font messageFont = new Font("Arial", 36, fontStyle, GraphicsUnit.Point))
{
using (StringFormat stringFormat = new StringFormat())
{
stringFormat.Alignment = StringAlignment.Center;
stringFormat.LineAlignment = StringAlignment.Center;
using (Graphics graphics = this.CreateGraphics())
{
using (Font adjustedMessageFont = GetAdjustedFont(graphics, message, messageFont, this.Bounds, 160, 10))
{
using (GraphicsPath path = new GraphicsPath())
{
path.AddString(message, adjustedMessageFont.FontFamily, (int) fontStyle, (graphics.DpiY * adjustedMessageFont.Size) / 72, Point.Empty, stringFormat);
RectangleF graphicsPathBounds = path.GetBounds();
PointF[] targetPoints = { new PointF(0, 0), new PointF(ClientSize.Width, 0), new PointF(0, ClientSize.Height) };
var translate = new Matrix(graphicsPathBounds, targetPoints);
path.Transform(translate);
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphics.FillPath(Brushes.LawnGreen, path);
}
}
}
}
}
}
private Font GetAdjustedFont(Graphics graphicRef, string graphicString, Font originalFont, RectangleF container, int maxFontSize, int minFontSize)
{
Font testFont = null;
// We utilize MeasureString which we get via a control instance
for (int adjustedSize = maxFontSize; adjustedSize >= minFontSize; adjustedSize--)
{
testFont = new Font(originalFont.Name, adjustedSize, originalFont.Style);
// Test the string with the new size
SizeF adjustedSizeNew = graphicRef.MeasureString(graphicString, testFont);
if (container.Width > Convert.ToInt32(adjustedSizeNew.Width) && container.Height > Convert.ToInt32(adjustedSizeNew.Height))
{
// Good font, return it
return testFont;
}
}
return testFont;
}
The result is this
After the graphics.FillPath in the above code I try to use the GraphicsPath path with the IsVisible method to detect if any of the black squares intersect with the drawn text, but the results I get from that have the text in a completely different location than the above result in the image. I can't figure out where the difference, or stretch is coming from.
path.IsVisible result
I am creating a PNG picture, using the Bitmap object, using Drawing.Graphics . I create a Bitmap, insert a background image and draw some strings.
Now, when I save the image on the disk, the files does not have my strings!
I am doing this in ASP.NET MVC, where this is my controllers signature:
[AcceptVerbs(HttpVerbs.Get)]
public string GetNewsletterPicture(string headline, string tagline)
When I don't save the image on the disk and instead returns a FileStreamResult from a MemoryStream, the image looks perfectly.
So there is some problem that when I save the image to the disk, the strings are "forgotten" somehow.
Any ideas?
My code:
ColorConverter converter = new ColorConverter();
Color textColor = (Color)converter.ConvertFromString("#FF58595B");
int width = 598;
int height = 77;
int offSet = 40;
int shadowOffset = 1;
var bmp = new Bitmap(width, height);
using (Graphics g = Graphics.FromImage(bmp))
{
g.Clear(Color.LightGray);
Image backgroundImg = new Bitmap(Server.MapPath("~/Static/Images/bgimg.png"));
g.DrawImage(backgroundImg,0,0);
StringFormat sf= new StringFormat();
sf.Alignment = StringAlignment.Center;
var rectangleTop = new RectangleF(0, 0, width, height);
var rectangleTopShadowHack = new RectangleF(shadowOffset, shadowOffset, width + shadowOffset, height + shadowOffset);
g.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
// only show headline and center it
if (!string.IsNullOrEmpty(tagline))
{
var rectangleBottomShadowHack = new RectangleF(shadowOffset, offSet + shadowOffset, width + shadowOffset, height - offSet + shadowOffset);
var rectangleBottom = new RectangleF(0, offSet, width, height - offSet);
g.DrawString(tagline, new Font("Verdana", 18), new SolidBrush(Color.White), rectangleBottomShadowHack, sf);
g.DrawString(tagline, new Font("Verdana", 18), new SolidBrush(textColor), rectangleBottom, sf);
}
else
{
sf.LineAlignment = StringAlignment.Center;
}
g.DrawString(headline, GetFont("Sentinel-Bold", 28, FontStyle.Bold), new SolidBrush(Color.White), rectangleTopShadowHack, sf);
g.DrawString(headline, GetFont("Sentinel-Bold", 28, FontStyle.Bold), new SolidBrush(textColor), rectangleTop, sf);
g.Save();
var fileName = Guid.NewGuid().ToString() + ".png";
var path = Server.MapPath("~/Static/Previews/" + fileName);
bmp.Save(path, ImageFormat.Png);
return fileName;
If in doubt, it is the g.DrawString which is not being saved on the picture.
NEW atttempt (still not working):
[AcceptVerbs(HttpVerbs.Get)]
public string GetNewsletterPicture(string headline, string tagline)
{
ColorConverter converter = new ColorConverter();
Color textColor = (Color)converter.ConvertFromString("#FF58595B");
int width = 598;
int height = 77;
int offSet = 40;
int shadowOffset = 1;
var bmp = new Bitmap(width, height);
using (Graphics g = Graphics.FromImage(bmp))
{
g.Clear(Color.LightGray);
Image backgroundImg = new Bitmap(Server.MapPath("~/Static/Images/bgimg.png"));
g.DrawImage(backgroundImg,0,0);
StringFormat sf= new StringFormat();
sf.Alignment = StringAlignment.Center;
var rectangleTop = new RectangleF(0, 0, width, height);
var rectangleTopShadowHack = new RectangleF(shadowOffset, shadowOffset, width + shadowOffset, height + shadowOffset);
g.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
// only show headline and center it
if (!string.IsNullOrEmpty(tagline))
{
var rectangleBottomShadowHack = new RectangleF(shadowOffset, offSet + shadowOffset, width + shadowOffset, height - offSet + shadowOffset);
var rectangleBottom = new RectangleF(0, offSet, width, height - offSet);
g.DrawString(tagline, new Font("Verdana", 18), new SolidBrush(Color.White), rectangleBottomShadowHack, sf);
g.DrawString(tagline, new Font("Verdana", 18), new SolidBrush(textColor), rectangleBottom, sf);
}
else
{
sf.LineAlignment = StringAlignment.Center;
}
g.DrawString(headline, GetFont("Sentinel-Bold", 28, FontStyle.Bold), new SolidBrush(Color.White), rectangleTopShadowHack, sf);
g.DrawString(headline, GetFont("Sentinel-Bold", 28, FontStyle.Bold), new SolidBrush(textColor), rectangleTop, sf);
g.Flush(FlushIntention.Sync);
}
var fileName = Guid.NewGuid().ToString() + ".png";
var path = Server.MapPath("~/Static/Previews/" + fileName);
bmp.Save(path, ImageFormat.Png);
return fileName;
//MemoryStream stm = new MemoryStream();
//bmp.Save(stm,System.Drawing.Imaging.ImageFormat.Png);
//stm.Position = 0;
//return new FileStreamResult(stm, "image/png");
}
I can't tell for sure, but it looks like you might be confusing g.Save() with g.Flush().
You need to call g.Flush(FlushIntention.Sync) instead of g.Save(). You should probably also call bmp.Save() outside of the using block:
var bmp = new Bitmap(width, height);
using (Graphics g = Graphics.FromImage(bmp))
{
//...
g.Flush(FlushIntention.Sync);
}
var fileName = Guid.NewGuid().ToString() + ".png";
var path = Server.MapPath("~/Static/Previews/" + fileName);
bmp.Save(path, ImageFormat.Png)
Save() is used to save the current graphics state so that you can modify it and then restore it later.:
GraphicsState oldState = g.Save();
// Make some changes to the graphics state...
g.Restore(oldState);
Flush() on the other hand, is used to force the graphics object to complete any pending operations. By passing FlushIntention.Sync as a parameter, Flush() won't return until the flushing is complete.
I want to add 2 string to an image as follows:
This is Text
------------
------------
------------
--Other-----
How do I use the largest font size possible without have the String go off the side of the image?
example: if text is too big then it goes off the image::
This is Text That is too big
------------
------------
------------
--Other-----
I wrote this script on my previous projects to fit some text into the image by calculating its dimensions for each font-size. when the font size is bigger than the image's width, it lowers the font size by 0.1em and tries again until the text fits in the image. Here's the code :
public static string drawTextOnMarker(string markerfile, string text, string newfilename,Color textColor)
{
//Uri uri = new Uri(markerfile, UriKind.Relative);
//markerfile = uri.AbsolutePath;
//uri = new Uri(newfilename, UriKind.Relative);
//newfilename = uri.AbsolutePath;
if (!System.IO.File.Exists(System.Web.HttpContext.Current.Server.MapPath(newfilename)))
{
try
{
Bitmap bmp = new Bitmap(System.Web.HttpContext.Current.Server.MapPath(markerfile));
Graphics g = Graphics.FromImage(bmp);
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;
StringFormat strFormat = new StringFormat();
strFormat.Alignment = StringAlignment.Center;
SolidBrush myBrush = new SolidBrush(textColor);
float fontsize = 10;
bool sizeSetupCompleted = false;
while (!sizeSetupCompleted)
{
SizeF mySize = g.MeasureString(text, new Font("Verdana", fontsize, FontStyle.Bold));
if (mySize.Width > 24 || mySize.Height > 13)
{
fontsize-= float.Parse("0.1");
}
else
{
sizeSetupCompleted = true;
}
}
g.DrawString(text, new Font("Verdana", fontsize, FontStyle.Bold), myBrush, new RectangleF(4, 3, 24, 8), strFormat);
bmp.Save(System.Web.HttpContext.Current.Server.MapPath(newfilename));
return newfilename.Substring(2);
}
catch (Exception)
{
return markerfile.Substring(2);
}
}
return newfilename.Substring(2);
}
Here is a quick solution:
using (Graphics g = Graphics.FromImage(bmp))
{
float width = g.MeasureString(text, font).Width;
float scale = bmp.Width / width;
g.ScaleTransform(scale, scale); //Simple trick not to use other Font instance
g.DrawString(text, font, Brushes.Black, PointF.Empty);
g.ResetTransform();
...
}
Your text won't be always 100% width if you use TextRenderingHint.AntiAliasGridFit or similar, but I think that's not a problem as you just want to make sure the text alawys fits in the image.