diff --git a/libse/NikseBitmap.cs b/libse/NikseBitmap.cs index 923a010ef..45f9164bb 100644 --- a/libse/NikseBitmap.cs +++ b/libse/NikseBitmap.cs @@ -801,6 +801,28 @@ namespace Nikse.SubtitleEdit.Core return newTop; } + public int CalcBottomCropping(Color transparentColor) + { + int y = Height - 1; + int cropping = 0; + while (y > 0) + { + int x = 0; + while (x < Width) + { + var c = GetPixel(x, y); + if (c != transparentColor && c.A != 0) + { + return cropping; + } + x++; + } + y--; + cropping++; + } + return cropping; + } + public void Fill(Color color) { var buffer = new byte[4]; diff --git a/src/Forms/ExportPngXml.cs b/src/Forms/ExportPngXml.cs index dba126e46..32cb4acf1 100644 --- a/src/Forms/ExportPngXml.cs +++ b/src/Forms/ExportPngXml.cs @@ -1897,7 +1897,19 @@ $DROP=[DROPVALUE]" + Environment.NewLine + Environment.NewLine + private static int CalcWidthViaDraw(string text, MakeBitmapParameter parameter) { - //text = HtmlUtil.RemoveHtmlTags(text, true).Trim(); + var nbmp = GenereateBitmapForCalc(text, parameter); + nbmp.CropTransparentSidesAndBottom(0, true); + return nbmp.Width; + } + + private static int CalcButtomCropping(string text, MakeBitmapParameter parameter) + { + var nbmp = GenereateBitmapForCalc(text, parameter); + return nbmp.CalcBottomCropping(parameter.BorderColor); + } + + private static NikseBitmap GenereateBitmapForCalc(string text, MakeBitmapParameter parameter) + { text = text.Trim(); var path = new GraphicsPath(); var sb = new StringBuilder(); @@ -1921,7 +1933,7 @@ $DROP=[DROPVALUE]" + Environment.NewLine + Environment.NewLine + g.TextRenderingHint = TextRenderingHint.AntiAliasGridFit; Font font = SetFont(parameter, parameter.SubtitleFontSize); - Stack fontStack = new Stack(); + var fontStack = new Stack(); while (i < text.Length) { if (text.Substring(i).StartsWith(" _paddingDictionary = new Dictionary(); private static Bitmap GenerateImageFromTextWithStyleInner(MakeBitmapParameter parameter) { string text = parameter.P.Text; @@ -2317,19 +2329,27 @@ $DROP=[DROPVALUE]" + Environment.NewLine + Environment.NewLine + bmp = new Bitmap(sizeX, sizeY); } - // align lines with gjpqy, a bit lower + var paddingKey = font.Name + font.Size.ToString(CultureInfo.InvariantCulture); + int baseLinePadding; + if (_paddingDictionary.ContainsKey(paddingKey)) + { + baseLinePadding = _paddingDictionary[paddingKey]; + } + else + { + baseLinePadding = (int)Math.Round(TextDraw.MeasureTextHeight(font, "yjK)", parameter.SubtitleFontBold) - TextDraw.MeasureTextHeight(font, "ac", parameter.SubtitleFontBold)); + baseLinePadding += 2; + _paddingDictionary.Add(paddingKey, baseLinePadding); + } + + // align lines with "gjpqy,ýęçÇ/()[]" a bit lower var lines = text.SplitToLines(); - int baseLinePadding = 13; - if (parameter.SubtitleFontSize < 30) - baseLinePadding = 12; - if (parameter.SubtitleFontSize < 25) - baseLinePadding = 9; if (lines.Length > 0) { var lastLine = lines[lines.Length - 1]; - if (lastLine.Contains(new[] { 'g', 'j', 'p', 'q', 'y', ',', 'ý', 'ę', 'ç', 'Ç' })) + if (lastLine.Contains(new[] { 'g', 'j', 'p', 'q', 'y', ',', 'ý', 'ę', 'ç', 'Ç', '/', '(', ')', '[', ']' })) { - var textNoBelow = lastLine.Replace('g', 'a').Replace('j', 'a').Replace('p', 'a').Replace('q', 'a').Replace('y', 'a').Replace(',', 'a').Replace('ý', 'a').Replace('ę', 'a').Replace('ç', 'a').Replace('Ç', 'a'); + var textNoBelow = lastLine.Replace('g', 'a').Replace('j', 'a').Replace('p', 'a').Replace('q', 'a').Replace('y', 'a').Replace(',', 'a').Replace('ý', 'a').Replace('ę', 'a').Replace('ç', 'a').Replace('Ç', 'a').Replace('/', 'a').Replace('(', 'a').Replace(')', 'a').Replace('[', 'a').Replace(']', 'a'); baseLinePadding -= (int)Math.Round((TextDraw.MeasureTextHeight(font, lastLine, parameter.SubtitleFontBold) - TextDraw.MeasureTextHeight(font, textNoBelow, parameter.SubtitleFontBold))); } else @@ -2706,8 +2726,36 @@ $DROP=[DROPVALUE]" + Environment.NewLine + Environment.NewLine + sb.Append(' '); sb.Append(t); } - lastText.Append(sb); - TextDraw.DrawText(font, sf, path, sb, isItalic, isBold || parameter.SubtitleFontBold, false, left, top, ref newLine, leftMargin, ref newLinePathPoint); + + if (sb.Length > 0) + { + float addLeft = 0; + int oldPathPointIndex = path.PointCount - 1; + if (oldPathPointIndex < 0) + oldPathPointIndex = 0; + if (sb.Length > 0) + { + if (lastText.Length > 0 && left > 2) + left -= 1.5f; + + lastText.Append(sb); + TextDraw.DrawText(font, sf, path, sb, isItalic, isBold || parameter.SubtitleFontBold, false, left, top, ref newLine, leftMargin, ref newLinePathPoint); + } + + if (path.PointCount > 0) + { + var list = (PointF[])path.PathPoints.Clone(); // avoid using very slow path.PathPoints indexer!!! + for (int k = oldPathPointIndex; k < list.Length; k++) + { + if (list[k].X > addLeft) + addLeft = list[k].X; + } + } + if (addLeft < 0.01) + addLeft = left + 2; + left = addLeft; + } + isItalic = false; i += 3; } @@ -2730,8 +2778,36 @@ $DROP=[DROPVALUE]" + Environment.NewLine + Environment.NewLine + sb.Append(' '); sb.Append(t); } - lastText.Append(sb); - TextDraw.DrawText(font, sf, path, sb, isItalic, isBold, false, left, top, ref newLine, leftMargin, ref newLinePathPoint); + + if (sb.Length > 0) + { + float addLeft = 0; + int oldPathPointIndex = path.PointCount - 1; + if (oldPathPointIndex < 0) + oldPathPointIndex = 0; + if (sb.Length > 0) + { + if (lastText.Length > 0 && left > 2) + left -= 1.5f; + + lastText.Append(sb); + TextDraw.DrawText(font, sf, path, sb, isItalic, isBold, false, left, top, ref newLine, leftMargin, ref newLinePathPoint); + } + + if (path.PointCount > 0) + { + var list = (PointF[])path.PathPoints.Clone(); // avoid using very slow path.PathPoints indexer!!! + for (int k = oldPathPointIndex; k < list.Length; k++) + { + if (list[k].X > addLeft) + addLeft = list[k].X; + } + } + if (addLeft < 0.01) + addLeft = left + 2; + left = addLeft; + } + isBold = false; i += 3; }