Ejemplo n.º 1
0
        private static Bitmap GenerateImageFromTextWithStyleInner(MakeBitmapParameter parameter)
        {
            string text = parameter.P.Text;

            text = RemoveSubStationAlphaFormatting(text);

            text = text.Replace("<I>", "<i>");
            text = text.Replace("</I>", "</i>");
            text = Utilities.FixInvalidItalicTags(text);

            text = text.Replace("<B>", "<b>");
            text = text.Replace("</B>", "</b>");

            // no support for underline
            text = text.Replace("<u>", string.Empty);
            text = text.Replace("</u>", string.Empty);
            text = text.Replace("<U>", string.Empty);
            text = text.Replace("</U>", string.Empty);

            var bmp = new Bitmap(1, 1);
            var g = Graphics.FromImage(bmp);
            var fontSize = g.DpiY * parameter.SubtitleFontSize / 72;
            Font font = SetFont(parameter, parameter.SubtitleFontSize);
            var lineHeight = parameter.LineHeight; // (textSize.Height * 0.64f);

            var textSize = g.MeasureString(Utilities.RemoveHtmlTags(text), font);
            g.Dispose();
            bmp.Dispose();
            int sizeX = (int)(textSize.Width * 1.8) + 150;
            int sizeY = (int)(textSize.Height * 0.9) + 50;
            if (sizeX < 1)
                sizeX = 1;
            if (sizeY < 1)
                sizeY = 1;
            bmp = new Bitmap(sizeX, sizeY);
            if (parameter.BackgroundColor != Color.Transparent)
            {
                NikseBitmap nbmpTemp = new NikseBitmap(bmp);
                nbmpTemp.Fill(parameter.BackgroundColor);
                var temp = nbmpTemp.GetBitmap();
                bmp.Dispose();
                bmp = temp;
            //                g.FillRectangle(new SolidBrush(parameter.BackgroundColor), 0, 0, bmp.Width, bmp.Height);

            }

            g = Graphics.FromImage(bmp);

            // align lines with gjpqy, a bit lower
            var lines = text.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
            int baseLinePadding = 13;
            if (parameter.SubtitleFontSize < 30)
                baseLinePadding = 12;
            if (parameter.SubtitleFontSize < 25)
                baseLinePadding = 9;
            if (lines.Length > 0)
            {
                if (lines[lines.Length - 1].Contains("g") || lines[lines.Length - 1].Contains("j") || lines[lines.Length - 1].Contains("p") || lines[lines.Length - 1].Contains("q") || lines[lines.Length - 1].Contains("y") || lines[lines.Length - 1].Contains(","))
                {
                    string textNoBelow = lines[lines.Length - 1].Replace("g", "a").Replace("j", "a").Replace("p", "a").Replace("q", "a").Replace("y", "a").Replace(",", "a");
                    baseLinePadding -= (int)Math.Round((TextDraw.MeasureTextHeight(font, lines[lines.Length - 1], parameter.SubtitleFontBold) - TextDraw.MeasureTextHeight(font, textNoBelow, parameter.SubtitleFontBold)));
                }
                else
                {
                    baseLinePadding += 1;
                }
                if (baseLinePadding < 0)
                    baseLinePadding = 0;
            }

            //TODO: Better baseline - test http://bobpowell.net/formattingtext.aspx
            //float baselineOffset=font.SizeInPoints/font.FontFamily.GetEmHeight(font.Style)*font.FontFamily.GetCellAscent(font.Style);
            //float baselineOffsetPixels = g.DpiY/72f*baselineOffset;
            //baseLinePadding = (int)Math.Round(baselineOffsetPixels);

            var lefts = new List<float>();
            if (text.ToLower().Contains("<font") || text.ToLower().Contains("<i>"))
            {
                foreach (string line in text.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries))
                {
                    string lineNoHtml = Utilities.RemoveHtmlFontTag(line.Replace("<i>", string.Empty).Replace("</i>", string.Empty));
                    if (parameter.AlignLeft)
                        lefts.Add(5);
                    else if (parameter.AlignRight)
                        lefts.Add(bmp.Width - CalcWidthViaDraw(lineNoHtml, parameter) - 15); // calculate via drawing+crop
                    else
                        lefts.Add((bmp.Width - CalcWidthViaDraw(lineNoHtml, parameter) + 5) / 2); // calculate via drawing+crop
                }
            }
            else
            {
                foreach (string line in Utilities.RemoveHtmlFontTag(text.Replace("<i>", string.Empty).Replace("</i>", string.Empty)).Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries))
                {
                    if (parameter.AlignLeft)
                        lefts.Add(5);
                    else if (parameter.AlignRight)
                        lefts.Add(bmp.Width - (TextDraw.MeasureTextWidth(font, line, parameter.SubtitleFontBold) + 15));
                    else
                        lefts.Add((bmp.Width - TextDraw.MeasureTextWidth(font, line, parameter.SubtitleFontBold) + 15) / 2);
                }
            }

            g.CompositingQuality = CompositingQuality.HighQuality;
            g.InterpolationMode = InterpolationMode.HighQualityBicubic;
            g.SmoothingMode = SmoothingMode.HighQuality;
            g.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;

            var sf = new StringFormat();
            sf.Alignment = StringAlignment.Near;
            sf.LineAlignment = StringAlignment.Near;// draw the text to a path

            if (parameter.SimpleRendering)
            {
                if (text.StartsWith("<font ") && Utilities.CountTagInText(text, "<font") == 1)
                {
                    parameter.SubtitleColor = Utilities.GetColorFromFontString(text, parameter.SubtitleColor);
                }

                text = Utilities.RemoveHtmlTags(text, true); //TODO: Perhaps check single color...
                var brush = new SolidBrush(parameter.BorderColor);
                int x = 3;
                int y = 3;
                sf.Alignment = StringAlignment.Near;
                if (parameter.AlignLeft)
                {
                    sf.Alignment = StringAlignment.Near;
                }
                else if (parameter.AlignRight)
                {
                    sf.Alignment = StringAlignment.Far;
                    x = parameter.ScreenWidth - 5;
                }
                else
                {
                    sf.Alignment = StringAlignment.Center;
                    x = parameter.ScreenWidth / 2;
                }

                bmp = new Bitmap(parameter.ScreenWidth, sizeY);

                Graphics surface = Graphics.FromImage(bmp);
                surface.CompositingQuality = CompositingQuality.HighSpeed;
                surface.InterpolationMode = InterpolationMode.Default;
                surface.SmoothingMode = SmoothingMode.HighSpeed;
                surface.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
                for (int j = 0; j < parameter.BorderWidth; j++)
                {
                    surface.DrawString(text, font, brush, new PointF { X = x + j, Y = y - 1 + j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x + j, Y = y - 0 + j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x + j, Y = y + 1 + j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x + j + 1, Y = y - 1 + j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x + j + 1, Y = y - 0 + j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x + j + 1, Y = y + 1 + j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x + j - 1, Y = y - 1 + j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x + j - 1, Y = y - 0 + j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x + j - 1, Y = y + 1 + j }, sf);

                    surface.DrawString(text, font, brush, new PointF { X = x - j, Y = y - 1 + j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x - j, Y = y - 0 + j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x - j, Y = y + 1 + j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x - j + 1, Y = y - 1 + j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x - j + 1, Y = y - 0 + j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x - j + 1, Y = y + 1 + j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x - j - 1, Y = y - 1 + j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x - j - 1, Y = y - 0 + j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x - j - 1, Y = y + 1 + j }, sf);

                    surface.DrawString(text, font, brush, new PointF { X = x - j, Y = y - 1 - j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x - j, Y = y - 0 - j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x - j, Y = y + 1 - j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x - j + 1, Y = y - 1 - j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x - j + 1, Y = y - 0 - j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x - j + 1, Y = y + 1 - j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x - j - 1, Y = y - 1 - j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x - j - 1, Y = y - 0 - j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x - j - 1, Y = y + 1 - j }, sf);

                    surface.DrawString(text, font, brush, new PointF { X = x + j, Y = y - 1 - j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x + j, Y = y - 0 - j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x + j, Y = y + 1 - j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x + j + 1, Y = y - 1 - j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x + j + 1, Y = y - 0 - j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x + j + 1, Y = y + 1 - j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x + j - 1, Y = y - 1 - j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x + j - 1, Y = y - 0 - j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x + j - 1, Y = y + 1 - j }, sf);

                    surface.DrawString(text, font, brush, new PointF { X = x + j, Y = y - 1 + j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x + j, Y = y - 0 + j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x + j, Y = y + 1 + j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x + j + 1, Y = y - 1 + j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x + j + 1, Y = y - 0 + j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x + j + 1, Y = y + 1 + j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x + j - 1, Y = y - 1 + j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x + j - 1, Y = y - 0 + j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x + j - 1, Y = y + 1 + j }, sf);

                    surface.DrawString(text, font, brush, new PointF { X = x, Y = y - 1 - j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x, Y = y - 0 - j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x, Y = y + 1 - j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x + 1, Y = y - 1 - j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x + 1, Y = y - 0 - j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x + 1, Y = y + 1 - j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x - 1, Y = y - 1 - j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x - 1, Y = y - 0 - j }, sf);
                    surface.DrawString(text, font, brush, new PointF { X = x - 1, Y = y + 1 - j }, sf);

                }
                brush.Dispose();
                brush = new SolidBrush(parameter.SubtitleColor);
                surface.CompositingQuality = CompositingQuality.HighQuality;
                surface.SmoothingMode = SmoothingMode.HighQuality;
                surface.InterpolationMode = InterpolationMode.HighQualityBicubic;
                surface.DrawString(text, font, brush, new PointF { X = x, Y = y }, sf);
                surface.Dispose();
                brush.Dispose();
            }
            else
            {
                var path = new GraphicsPath();
                var sb = new StringBuilder();
                int i = 0;
                bool isItalic = false;
                bool isBold = parameter.SubtitleFontBold;
                float left = 5;
                if (lefts.Count > 0)
                    left = lefts[0];
                float top = 5;
                bool newLine = false;
                int lineNumber = 0;
                float leftMargin = left;
                int newLinePathPoint = -1;
                Color c = parameter.SubtitleColor;
                var colorStack = new Stack<Color>();
                var lastText = new StringBuilder();
                while (i < text.Length)
                {
                    if (text.Substring(i).ToLower().StartsWith("<font "))
                    {
                        float addLeft = 0;
                        int oldPathPointIndex = path.PointCount;
                        if (oldPathPointIndex < 0)
                            oldPathPointIndex = 0;

                        if (sb.Length > 0)
                        {
                            lastText.Append(sb);
                            TextDraw.DrawText(font, sf, path, sb, isItalic, parameter.SubtitleFontBold, false, left, top, ref newLine, leftMargin, ref newLinePathPoint);
                        }
                        if (path.PointCount > 0)
                        {
                            PointF[] 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 (path.PointCount == 0)
                            addLeft = left;
                        else if (addLeft < 0.01)
                            addLeft = left + 2;
                        left = addLeft;

                        DrawShadowAndPAth(parameter, g, path);
                        var p2 = new SolidBrush(c);
                        g.FillPath(p2, path);
                        p2.Dispose();
                        path.Reset();
                        path = new GraphicsPath();
                        sb = new StringBuilder();

                        int endIndex = text.Substring(i).IndexOf(">", StringComparison.Ordinal);
                        if (endIndex == -1)
                        {
                            i += 9999;
                        }
                        else
                        {
                            string fontContent = text.Substring(i, endIndex);
                            if (fontContent.Contains(" color="))
                            {
                                string[] arr = fontContent.Substring(fontContent.IndexOf(" color=", StringComparison.Ordinal) + 7).Trim().Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                                if (arr.Length > 0)
                                {
                                    string fontColor = arr[0].Trim('\'').Trim('"').Trim('\'');
                                    try
                                    {
                                        colorStack.Push(c); // save old color
                                        if (fontColor.StartsWith("rgb("))
                                        {
                                            arr = fontColor.Remove(0, 4).TrimEnd(')').Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                                            c = Color.FromArgb(int.Parse(arr[0]), int.Parse(arr[1]), int.Parse(arr[2]));
                                        }
                                        else
                                        {
                                            c = ColorTranslator.FromHtml(fontColor);
                                        }
                                    }
                                    catch
                                    {
                                        c = parameter.SubtitleColor;
                                    }
                                }
                            }
                            i += endIndex;
                        }
                    }
                    else if (text.Substring(i).ToLower().StartsWith("</font>"))
                    {
                        if (text.Substring(i).ToLower().Replace("</font>", string.Empty).Length > 0)
                        {
                            if (lastText.ToString().EndsWith(" ") && !sb.ToString().StartsWith(" "))
                            {
                                string t = sb.ToString();
                                sb = new StringBuilder();
                                sb.Append(" " + t);
                            }

                            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, parameter.SubtitleFontBold, false, left, top, ref newLine, leftMargin, ref newLinePathPoint);
                            }
                            if (path.PointCount > 0)
                            {
                                PointF[] 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;

                            DrawShadowAndPAth(parameter, g, path);
                            g.FillPath(new SolidBrush(c), path);
                            path.Reset();
                            sb = new StringBuilder();
                            if (colorStack.Count > 0)
                                c = colorStack.Pop();
                            if (left >= 3)
                                left -= 2.5f;
                        }
                        i += 6;
                    }
                    else if (text.Substring(i).ToLower().StartsWith("<i>"))
                    {
                        if (sb.ToString().Trim().Length > 0)
                        {
                            lastText.Append(sb);
                            TextDraw.DrawText(font, sf, path, sb, isItalic, parameter.SubtitleFontBold, false, left, top, ref newLine, leftMargin, ref newLinePathPoint);
                        }
                        isItalic = true;
                        i += 2;
                    }
                    else if (text.Substring(i).ToLower().StartsWith("</i>") && isItalic)
                    {
                        if (lastText.ToString().EndsWith(" ") && !sb.ToString().StartsWith(" "))
                        {
                            string t = sb.ToString();
                            sb = new StringBuilder();
                            sb.Append(" " + t);
                        }
                        lastText.Append(sb);
                        TextDraw.DrawText(font, sf, path, sb, isItalic, parameter.SubtitleFontBold, false, left, top, ref newLine, leftMargin, ref newLinePathPoint);
                        isItalic = false;
                        i += 3;
                    }
                    else if (text.Substring(i).ToLower().StartsWith("<b>"))
                    {
                        if (sb.ToString().Trim().Length > 0)
                        {
                            lastText.Append(sb);
                            TextDraw.DrawText(font, sf, path, sb, isItalic, isBold, false, left, top, ref newLine, leftMargin, ref newLinePathPoint);
                        }
                        isBold = true;
                        i += 2;
                    }
                    else if (text.Substring(i).ToLower().StartsWith("</b>") && isBold)
                    {
                        if (lastText.ToString().EndsWith(" ") && !sb.ToString().StartsWith(" "))
                        {
                            string t = sb.ToString();
                            sb = new StringBuilder();
                            sb.Append(" " + t);
                        }
                        lastText.Append(sb);
                        TextDraw.DrawText(font, sf, path, sb, isItalic, isBold, false, left, top, ref newLine, leftMargin, ref newLinePathPoint);
                        isBold = false;
                        i += 3;
                    }
                    else if (text.Substring(i).StartsWith(Environment.NewLine))
                    {
                        lastText.Append(sb);
                        TextDraw.DrawText(font, sf, path, sb, isItalic, isBold, false, left, top, ref newLine, leftMargin, ref newLinePathPoint);

                        top += lineHeight;
                        newLine = true;
                        i += Environment.NewLine.Length - 1;
                        lineNumber++;
                        if (lineNumber < lefts.Count)
                        {
                            leftMargin = lefts[lineNumber];
                            left = leftMargin;
                        }
                    }
                    else
                    {
                        sb.Append(text.Substring(i, 1));
                    }
                    i++;
                }
                if (sb.Length > 0)
                    TextDraw.DrawText(font, sf, path, sb, isItalic, parameter.SubtitleFontBold, false, left, top, ref newLine, leftMargin, ref newLinePathPoint);

                DrawShadowAndPAth(parameter, g, path);
                g.FillPath(new SolidBrush(c), path);
            }
            g.Dispose();
            sf.Dispose();

            var nbmp = new NikseBitmap(bmp);
            if (parameter.BackgroundColor == Color.Transparent)
            {
                nbmp.CropTransparentSidesAndBottom(baseLinePadding, true);
                nbmp.CropTransparentSidesAndBottom(2, false);
            }
            else
            {
                nbmp.CropSidesAndBottom(4, parameter.BackgroundColor, true);
                nbmp.CropTop(4, parameter.BackgroundColor);
            }

            if (nbmp.Width > parameter.ScreenWidth)
            {
                parameter.Error = "#" + parameter.P.Number.ToString(CultureInfo.InvariantCulture) + ": " + nbmp.Width.ToString(CultureInfo.InvariantCulture) + " > " + parameter.ScreenWidth.ToString(CultureInfo.InvariantCulture);
            }

            if (parameter.Type3D == 1) // Half-side-by-side 3D
            {
                Bitmap singleBmp = nbmp.GetBitmap();
                Bitmap singleHalfBmp = ScaleToHalfWidth(singleBmp);
                singleBmp.Dispose();
                Bitmap sideBySideBmp = new Bitmap(parameter.ScreenWidth, singleHalfBmp.Height);
                int singleWidth = parameter.ScreenWidth / 2;
                int singleLeftMargin = (singleWidth - singleHalfBmp.Width) / 2;

                using (Graphics gSideBySide = Graphics.FromImage(sideBySideBmp))
                {
                    gSideBySide.DrawImage(singleHalfBmp, singleLeftMargin + parameter.Depth3D, 0);
                    gSideBySide.DrawImage(singleHalfBmp, singleWidth + singleLeftMargin - parameter.Depth3D, 0);
                }
                nbmp = new NikseBitmap(sideBySideBmp);
                if (parameter.BackgroundColor == Color.Transparent)
                    nbmp.CropTransparentSidesAndBottom(2, true);
                else
                    nbmp.CropSidesAndBottom(4, parameter.BackgroundColor, true);
            }
            else if (parameter.Type3D == 2) // Half-Top/Bottom 3D
            {
                nbmp = Make3DTopBottom(parameter, nbmp);
            }
            return nbmp.GetBitmap();
        }
Ejemplo n.º 2
0
        private static NikseBitmap Make3DTopBottom(MakeBitmapParameter parameter, NikseBitmap nbmp)
        {
            Bitmap singleBmp = nbmp.GetBitmap();
            Bitmap singleHalfBmp = ScaleToHalfHeight(singleBmp);
            singleBmp.Dispose();
            Bitmap topBottomBmp = new Bitmap(parameter.ScreenWidth, parameter.ScreenHeight - parameter.BottomMargin);
            int singleHeight = parameter.ScreenHeight / 2;
            int leftM = (parameter.ScreenWidth / 2) - (singleHalfBmp.Width / 2);

            using (Graphics gTopBottom = Graphics.FromImage(topBottomBmp))
            {
                gTopBottom.DrawImage(singleHalfBmp, leftM + parameter.Depth3D, singleHeight - singleHalfBmp.Height - parameter.BottomMargin);
                gTopBottom.DrawImage(singleHalfBmp, leftM - parameter.Depth3D, parameter.ScreenHeight - parameter.BottomMargin - singleHalfBmp.Height);
            }
            nbmp = new NikseBitmap(topBottomBmp);
            if (parameter.BackgroundColor == Color.Transparent)
            {
                nbmp.CropTop(2, Color.Transparent);
                nbmp.CropTransparentSidesAndBottom(2, false);
            }
            else
            {
                nbmp.CropTop(4, parameter.BackgroundColor);
                nbmp.CropSidesAndBottom(4, parameter.BackgroundColor, false);
            }
            return nbmp;
        }