Подсчет ширины строки в пикселях в ячейке Excel - C#
Формулировка задачи:
Всем привет. Стоит задача - получить ширину текста в ячейке таблицы в пикселях.
Работаю с использованием Office.Interop. Пробовал библиотеку EPPlus, но выяснилось, что она даже ширину ячейки выдает неверную, поэтому про неё забыл надолго.
После неоднократного гугления понял, что нужно использовать метод Graphics.MeasureString, но, к сожалению, я получаю неверные результаты. Весь код не могу приложить (раскидано по разным классам и завязано еще с другими библиотеками), поэтому попробую частями:
1. После того, как я получил ячейку в листе экселя, я получаю данные о шрифте. У меня свой промежуточный класс, но думаю, что понятно будет что есть что:
2. Затем я пробую получить ширину строки. Мне нужно в футах, но перед этим я получаю естественно в пикселях:
Пробую "на живую" - в экселе в ячейке текст и ширина ячейки подобрана под ширину текста. При этом ширина ячейки 113 пикселей. Учитывая отступы в ячейке по 4 пикселя я должен получить ширину текста 113-4*2 = 105 пикселей.
Но вот метод Graphics.MeasureString мне выдает 84,54996 пикселей
Причем, что интересно - нашел библиотеку - Aspose.Cells. У них есть прям метод получения ширины текста и он выдал мне 105 пикселей! К сожалению, она платная(
public FontRepresentor(Excel.Font excelFont) { Name = excelFont.Name; Size = excelFont.Size; Color = new ColorRepresenter(excelFont.Color); Bold = excelFont.Bold; Italic = excelFont.Italic; Strike = excelFont.Strikethrough; Underline = GetIsUnderline(excelFont.Underline); Font = new System.Drawing.Font(GetFontFamily(Name), (float)Size, GetFontStyle(), GraphicsUnit.Pixel); } ..... private System.Drawing.FontFamily GetFontFamily(string fontName) { foreach (System.Drawing.FontFamily fontFamily in System.Drawing.FontFamily.Families) { if (fontFamily.Name.Equals(fontName)) return fontFamily; } return System.Drawing.FontFamily.Families.First(ff => ff.Name.Equals("Calibri")); } .... private System.Drawing.FontStyle GetFontStyle() { var fontStyle = FontStyle.Regular; if(Bold) fontStyle |= FontStyle.Bold; if(Italic) fontStyle |= FontStyle.Italic; if(Strike) fontStyle |= FontStyle.Strikeout; if(Underline) fontStyle |= FontStyle.Underline; return fontStyle; }
public double GetTextWidth() { var lineWidth = 0.0; //float displayDpiX = GraphicsHelpers.GetDpiX(); float fontDpi = 72.0f; //float pointSize = Font.Font.SizeInPoints; int viewScale = 1; double stringWidthPx = TextSize.Width; //double stringWidthIn = stringWidthPx / displayDpiX; double stringWidthIn = stringWidthPx / fontDpi; double stringWidthFt = stringWidthIn / 12.0; double borderInPx = 5; lineWidth = ((stringWidthFt * 1) + (borderInPx.ConvertPxToFt() * 2.0)) * viewScale* textKoef; if (WrapText && stringWidthPx > CellRectange.Width) { return CellRectange.Width.ConvertPxToFt(); } return lineWidth; } ..... /// <summary>Получение структуры SizeF для текста в текущей ячейке /// Получение с учетом всех свойств шрифта</summary> public SizeF TextSize => Font.MeasureString(Text); .... public SizeF MeasureString(string text) { SizeF sizeF; using (Graphics g = Graphics.FromHwnd(IntPtr.Zero)) { sizeF = g.MeasureString(text, Font); } return sizeF; }
Решение задачи: «Подсчет ширины строки в пикселях в ячейке Excel»
textual
Листинг программы
private void BtGetSizes_OnClick(object sender, RoutedEventArgs e) { var fileName = @"E:\Test\SizesTest.xlsx"; Excel.Application eXapp = new Excel.Application(); try { Excel.Workbook wb = eXapp.Workbooks.Open(fileName); Excel.Worksheet ws = wb.Worksheets[1]; Excel.Range cell = ws.Cells[1, 1]; float fontDpi = 72.0f; float dpiX = GetDpiX(); float dpiY = GetDpiY(); var str = cell.Text; Msg($"First cell text: {str}"); var cellWidthInPoints = cell.Width; var cellHeightInPoints = cell.Height; Msg($"Cell width in points: {cellWidthInPoints}"); Msg($"Cell height in points: {cellHeightInPoints}"); var cellWidthInPixels = ConvertPointToPixels(cellWidthInPoints, dpiX); var cellHeightInPixels = ConvertPointToPixels(cellHeightInPoints, dpiY); Msg($"Cell width in pixels: {cellWidthInPixels}"); Msg($"Cell height in pixels: {cellHeightInPixels}"); string fontName = cell.Font.Name; double xLfontSize = cell.Font.Size; Font font = new Font(GetFontFamily(fontName),(float)xLfontSize, GetFontStyle((bool)cell.Font.Bold,(bool)cell.Font.Italic,(bool)cell.Font.Strikethrough, false)); float fontSize = font.Size; float fontSizeInPoints = font.SizeInPoints; Msg($"Font size: {fontSize}"); Msg($"Font size in points: {fontSizeInPoints}"); SizeF fontSizeF = MeasureText(str, font); float measureWidth = fontSizeF.Width; float measureHeight = fontSizeF.Height; Msg($"Meusare width: {measureWidth}"); Msg($"Mesuare height: {measureHeight}"); double textWidthInPixels = ConvertPointToPixels(measureWidth, dpiX); double textHeightInPixels = ConvertPointToPixels(measureHeight, dpiY); Msg($"Text width in pixels: {textWidthInPixels}"); Msg($"Text height in pixels: {textHeightInPixels}"); } catch (Exception exception) { MessageBox.Show(exception.Message + Environment.NewLine + exception.StackTrace); } finally { eXapp.Quit(); } } private void Msg(string msg) { TbRes.Text += msg + Environment.NewLine; } private float GetDpiX() { using (Graphics g = Graphics.FromHwnd(IntPtr.Zero)) { return g.DpiX; } } private float GetDpiY() { using (Graphics g = Graphics.FromHwnd(IntPtr.Zero)) { return g.DpiY; } } private double ConvertPointToPixels(double pt, float dpi ) { return pt * dpi / 72.0f; } private System.Drawing.FontFamily GetFontFamily(string fontName) { foreach (System.Drawing.FontFamily fontFamily in System.Drawing.FontFamily.Families) { if (fontFamily.Name.Equals(fontName)) return fontFamily; } return System.Drawing.FontFamily.Families.First(ff => ff.Name.Equals("Calibri")); } private System.Drawing.FontStyle GetFontStyle(bool bold, bool italic, bool strike, bool underline) { var fontStyle = System.Drawing.FontStyle.Regular; if (bold) fontStyle |= System.Drawing.FontStyle.Bold; if (italic) fontStyle |= System.Drawing.FontStyle.Italic; if (strike) fontStyle |= System.Drawing.FontStyle.Strikeout; if (underline) fontStyle |= System.Drawing.FontStyle.Underline; return fontStyle; } private SizeF MeasureText(string text, Font font) { using (Graphics g = Graphics.FromHwnd(IntPtr.Zero)) { g.PageUnit = GraphicsUnit.Point; return g.MeasureString(text, font); } }
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д