/// <summary> /// Draws the image cropped based on alignment. The image is always drawn in proper aspect ratio by this method. /// </summary> /// <param name="zGraphics"></param> /// <param name="zBmp"></param> /// <param name="zElement"></param> private static void DrawGraphicOriginalSize(Graphics zGraphics, Bitmap zBmp, ProjectLayoutElement zElement) { var nSourceX = 0; var nSourceY = 0; var nX = 0; var nY = 0; // determine if the update is needed for drawing source X or target X if (zBmp.Width > zElement.width) { UpdateAlignmentValue(zElement.GetHorizontalAlignment(), ref nSourceX, zBmp.Width, zElement.width); } else { UpdateAlignmentValue(zElement.GetHorizontalAlignment(), ref nX, zElement.width, zBmp.Width); } // determine if the update is needed for drawing source Y or target Y if (zBmp.Height > zElement.height) { UpdateAlignmentValue(zElement.GetVerticalAlignment(), ref nSourceY, zBmp.Height, zElement.height); } else { UpdateAlignmentValue(zElement.GetVerticalAlignment(), ref nY, zElement.height, zBmp.Height); } zGraphics.DrawImage(zBmp, nX, nY, new Rectangle(nSourceX, nSourceY, zElement.width, zElement.height), GraphicsUnit.Pixel); }
private static void DrawGraphic(Graphics zGraphics, string sFile, ProjectLayoutElement zElement) { string sPath = sFile; if (sPath.Equals("none", StringComparison.CurrentCultureIgnoreCase)) { return; } if (!File.Exists(sPath)) { sPath = ProjectManager.Instance.ProjectPath + sFile; } if (File.Exists(sPath)) { var zBmp = 255 != zElement.opacity ? LoadOpacityImageFromCache(sPath, zElement) : LoadImageFromCache(sPath); int nWidth = zElement.width; int nHeight = zElement.height; if (zElement.keeporiginalsize) { DrawGraphicOriginalSize(zGraphics, zBmp, zElement); return; } if (zElement.lockaspect) { var fAspect = (float)zBmp.Tag; var nTargetHeight = (int)((float)nWidth / fAspect); if (nTargetHeight < nHeight) { nHeight = (int)((float)nWidth / fAspect); } else { nWidth = (int)((float)nHeight * fAspect); } } int nX = 0; int nY = 0; // standard alignment adjustment UpdateAlignmentValue(zElement.GetHorizontalAlignment(), ref nX, zElement.width, nWidth); UpdateAlignmentValue(zElement.GetVerticalAlignment(), ref nY, zElement.height, nHeight); zGraphics.DrawImage(zBmp, nX, nY, nWidth, nHeight); } else { IssueManager.Instance.FireAddIssueEvent("Image file not found: " + sFile); } // draw nothing }
/// <summary> /// Updates the alignment of all alignable markups /// </summary> /// <param name="zElement"></param> /// <param name="listAllMarkups"></param> public static void UpdateAlignment(ProjectLayoutElement zElement, IEnumerable <MarkupBase> listAllMarkups) { var listAlignedMarkups = listAllMarkups.Where(x => x.Aligns).ToList(); if (0 == listAlignedMarkups.Count) { return; } var fVertAlignOffset = s_dictionaryVerticalAlignmentProcessors[zElement.GetVerticalAlignment()] .GetVerticalAlignOffset(zElement, listAlignedMarkups); // if the vertical alignment is so far negative that it is outside the bounds adjust it to chop off at the bottom if (0 > listAlignedMarkups[0].TargetRect.Y + fVertAlignOffset) { fVertAlignOffset = -listAlignedMarkups[0].TargetRect.Y; } // process horizontal alignment (and add the offset for the vertical alignment) // build a list of the index of the first markup of each line var listFirstMarkupIndexOfLine = new List <int>(); var nCurrentLineNumber = -1; for (var nMarkupIdx = 0; nMarkupIdx < listAlignedMarkups.Count; nMarkupIdx++) { if (nCurrentLineNumber != listAlignedMarkups[nMarkupIdx].LineNumber) { listFirstMarkupIndexOfLine.Add(nMarkupIdx); nCurrentLineNumber = listAlignedMarkups[nMarkupIdx].LineNumber; } } // iterate over the list of indices of the first markup of each line and align the entire line for (var nIdx = 0; nIdx < listFirstMarkupIndexOfLine.Count; nIdx++) { var bLastLine = nIdx + 1 >= listFirstMarkupIndexOfLine.Count; UpdateLineAlignment( listFirstMarkupIndexOfLine[nIdx], bLastLine ? listAlignedMarkups.Count - 1 : listFirstMarkupIndexOfLine[nIdx + 1] - 1, bLastLine, zElement, listAlignedMarkups, fVertAlignOffset, listAllMarkups); } }
public void DrawText(Graphics zGraphics, ProjectLayoutElement zElement, string sInput) { var zFont = zElement.GetElementFont(); var colorFont = zElement.GetElementColor(); if (null == zFont) // default to something! { // font will show up in red if it's not yet set zFont = FontLoader.DefaultFont; } var zFormat = new StringFormat { LineAlignment = zElement.GetVerticalAlignment(), Alignment = zElement.GetHorizontalAlignment() }; var zBrush = 255 == zElement.opacity ? new SolidBrush(colorFont) : new SolidBrush(Color.FromArgb(zElement.opacity, colorFont)); if (zElement.autoscalefont) { SizeF zSize = zGraphics.MeasureString(sInput, zFont, new SizeF(zElement.width, int.MaxValue), zFormat); if (zSize.Height > zElement.height || zSize.Width > zElement.width) { float newSizeRatio; if ((zSize.Height - zElement.height) > (zSize.Width - zElement.width)) { newSizeRatio = (float)zElement.height / (float)zSize.Height; } else { newSizeRatio = (float)zElement.width / (float)zSize.Width; } var scaledFont = FontLoader.GetFont(zFont.FontFamily, newSizeRatio * zFont.Size, zFont.Style); //Support.IO.Logger.AddLogLine(scaledFont.Size + " was [" + zFont.Size + "]"); zFont = scaledFont; #if true // the preprocessing above will get the font size close but not perfect, the slow code below further refines the size // slow mode - but perfect precision (well arguably with the Graphics.MeasureString) bool bUpscaled = false; if (0 < sInput.Trim().Length) { while (true) { zSize = zGraphics.MeasureString(sInput, zFont, new SizeF(zElement.width, int.MaxValue), zFormat); if (zSize.Height > zElement.height || zSize.Width > zElement.width) { if (zFont.Size == 1) { break; } zFont = FontLoader.GetFont(zFont.FontFamily, zFont.Size - 1, zFont.Style); if (bUpscaled) { break; } } else { zFont = FontLoader.GetFont(zFont.FontFamily, zFont.Size + 1, zFont.Style); bUpscaled = true; } } //Support.IO.Logger.AddLogLine("[" + zFont.Size + "]"); } #endif } // else -- font size is fine for this element } else { zFormat.Trimming = StringTrimming.EllipsisCharacter; } var fEmSize = zFont.Size; switch (zFont.Unit) { case GraphicsUnit.Point: fEmSize = zGraphics.DpiY * (zFont.Size / 72f); break; default: Logger.AddLogLine("This font is using the Unit: {0} (not currently supported)".FormatString(zFont.Unit.ToString())); break; } if (0 == zElement.outlinethickness) { try { zGraphics.DrawString(sInput, zFont, zBrush, new RectangleF(0, 0, zElement.width, zElement.height), zFormat); } catch (Exception) { Logger.AddLogLine("Unable to render text (font issue?)"); } } else { try { var zPath = new GraphicsPath(); zPath.AddString(sInput, zFont.FontFamily, (int)zFont.Style, fEmSize, new RectangleF(0, 0, zElement.width, zElement.height), zFormat); CardRenderer.DrawElementPath(zElement, zGraphics, zPath, zBrush); } catch (Exception) { Logger.AddLogLine("Unable to render text (font issue?)"); } } }
public void DrawGraphicFile(Graphics zGraphics, string sFile, ProjectLayoutElement zElement, int nXGraphicOffset = 0, int nYGraphicOffset = 0) { var sPath = sFile; if (string.IsNullOrEmpty(sFile) || sPath.Equals("none", StringComparison.CurrentCultureIgnoreCase)) { return; } if (sPath.StartsWith(APPLICATION_FOLDER_MARKER)) { sPath = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), sPath.Replace(APPLICATION_FOLDER_MARKER, string.Empty)); } if (!File.Exists(sPath)) { sPath = ProjectManager.Instance.ProjectPath + sFile; } if (!File.Exists(sPath)) { IssueManager.Instance.FireAddIssueEvent("Image file not found: " + sFile); return; } var zBmp = ImageCache.LoadCustomImageFromCache(sPath, zElement); var nWidth = zElement.width; var nHeight = zElement.height; // TODO: sub processor methods (at a minimum) if (!string.IsNullOrWhiteSpace(zElement.tilesize) && zElement.tilesize.Trim() != "-") { var zMatch = regexImageTile.Match(zElement.tilesize); if (zMatch.Success) { var nTileWidth = Math.Max(-1, ParseUtil.ParseDefault(zMatch.Groups[1].Value, -1)); var nTileHeight = Math.Max(-1, ParseUtil.ParseDefault(zMatch.Groups[3].Value, -1)); GetAspectRatioHeight(zBmp, nTileWidth, nTileHeight, out nTileWidth, out nTileHeight); // paranoia... nTileWidth = Math.Max(1, nTileWidth); nTileHeight = Math.Max(1, nTileHeight); zBmp = ImageCache.LoadCustomImageFromCache(sFile, zElement, nTileWidth, nTileHeight); } using (var zTextureBrush = new TextureBrush(zBmp, WrapMode.Tile)) { // backup the transform var zOriginalTransform = zGraphics.Transform; // need to translate so the tiling starts with a full image if offset zGraphics.TranslateTransform(nXGraphicOffset, nYGraphicOffset); zGraphics.FillRectangle(zTextureBrush, 0, 0, nWidth, nHeight); zGraphics.Transform = zOriginalTransform; } return; } if (zElement.keeporiginalsize) { DrawGraphicOriginalSize(zGraphics, zBmp, zElement); return; } if (zElement.lockaspect) { GetSizeFromAspectRatio((float)zBmp.Tag, nWidth, nHeight, out nWidth, out nHeight); } var nX = 0; var nY = 0; // standard alignment adjustment UpdateAlignmentValue(zElement.GetHorizontalAlignment(), ref nX, zElement.width, nWidth); UpdateAlignmentValue(zElement.GetVerticalAlignment(), ref nY, zElement.height, nHeight); zGraphics.DrawImage(zBmp, nX + nXGraphicOffset, nY + nYGraphicOffset, nWidth, nHeight); }
public void DrawText(Graphics zGraphics, ProjectLayoutElement zElement, string sInput) { var zFont = zElement.GetElementFont(); var colorFont = zElement.GetElementColor(); if (null == zFont) // default to something! { // font will show up in red if it's not yet set zFont = FontLoader.DefaultFont; } var zBrush = 255 == zElement.opacity ? new SolidBrush(colorFont) : new SolidBrush(Color.FromArgb(zElement.opacity, colorFont)); TextFormatFlags zFormatFlags = TextFormatFlags.WordBreak | TextFormatFlags.NoClipping; switch (zElement.GetVerticalAlignment()) { case StringAlignment.Center: zFormatFlags |= TextFormatFlags.VerticalCenter; break; case StringAlignment.Far: zFormatFlags |= TextFormatFlags.Bottom; break; } switch (zElement.GetHorizontalAlignment()) { case StringAlignment.Center: zFormatFlags |= TextFormatFlags.HorizontalCenter; break; case StringAlignment.Far: zFormatFlags |= TextFormatFlags.Right; break; } #warning TextRenderer apparently does not support opactiy?! Bitmap zOpacityBitmap = null; if (255 != zElement.opacity) { zOpacityBitmap = new Bitmap(zElement.width, zElement.height, PixelFormat.Format32bppArgb); zOpacityBitmap.SetResolution(zGraphics.DpiY, zGraphics.DpiY); } if (zElement.autoscalefont) { var zSize = TextRenderer.MeasureText(sInput, zFont, new Size(zElement.width, int.MaxValue), zFormatFlags); if (zSize.Height > zElement.height || zSize.Width > zElement.width) { float newSizeRatio; if ((zSize.Height - zElement.height) > (zSize.Width - zElement.width)) { newSizeRatio = (float)zElement.height / (float)zSize.Height; } else { newSizeRatio = (float)zElement.width / (float)zSize.Width; } //var scaledFont = new Font(zFont.FontFamily, newSizeRatio * zFont.Size, zFont.Style); var scaledFont = new Font(zFont.FontFamily, newSizeRatio * zFont.Size, zFont.Style); //Logger.AddLogLine(scaledFont.Size + " was [" + zFont.Size + "]"); zFont = scaledFont; #if true // the preprocessing above will get the font size close but not perfect, the slow code below further refines the size // slow mode - but perfect precision (well arguably with the Graphics.MeasureString) bool bUpscaled = false; const float FONT_SCALE_ADJUST = 0.25f; if (0 < sInput.Trim().Length) { while (true) { zSize = TextRenderer.MeasureText(sInput, zFont, new Size(zElement.width, int.MaxValue), zFormatFlags); if (zSize.Height > zElement.height || zSize.Width > zElement.width) { if (zFont.Size <= 1) { break; } zFont = new Font(zFont.FontFamily, zFont.Size - FONT_SCALE_ADJUST, zFont.Style); //Logger.AddLogLine("ADJ A [" + zFont.Size + "]"); if (bUpscaled) { break; } } else { zFont = new Font(zFont.FontFamily, zFont.Size + FONT_SCALE_ADJUST, zFont.Style); //Logger.AddLogLine("ADJ B [" + zFont.Size + "]"); bUpscaled = true; } } } #endif } // else -- font size is fine for this element } else { zFormatFlags |= TextFormatFlags.EndEllipsis; } Logger.AddLogLine("[" + zFont.Size + "]"); var arrayDrawLines = new string[] { sInput }; var nLineOffset = 0; var fEmSize = zFont.Size; switch (zFont.Unit) { case GraphicsUnit.Point: fEmSize = zGraphics.DpiY * (zFont.Size / 72f); break; default: Logger.AddLogLine("This font is using the Unit: {0} (not currently supported)".FormatString(zFont.Unit.ToString())); break; } foreach (var sLine in arrayDrawLines) { if (0 == zElement.outlinethickness) { try { // https://stackoverflow.com/questions/849531/textrenderer-drawtext-in-bitmap-vs-onpaintbackground/1578056#1578056 if (null != zOpacityBitmap) { zFont = new Font("SkyScrappers Regular", zFont.Size); // TODO: https://stackoverflow.com/questions/18838037/drawing-text-to-a-bitmap-with-textrenderer #warning too bad this makes the font look terrible #if false var image = new Bitmap(zElement.width, zElement.height, PixelFormat.Format32bppArgb); // create memory buffer from desktop handle that supports alpha channel IntPtr dib; var memoryHdc = CreateMemoryHdc(IntPtr.Zero, image.Width, image.Height, out dib); try { // create memory buffer graphics to use for HTML rendering using (var memoryGraphics = Graphics.FromHdc(memoryHdc)) { // must not be transparent background memoryGraphics.Clear(Color.White); TextRenderer.DrawText(memoryGraphics, sLine, zFont, new Rectangle(0, 0, zElement.width, zElement.height), colorFont, zFormatFlags); } // copy from memory buffer to image using (var imageGraphics = Graphics.FromImage(image)) { var imgHdc = imageGraphics.GetHdc(); BitBlt(imgHdc, 0, 0, image.Width, image.Height, memoryHdc, 0, 0, 0x00CC0020); imageGraphics.ReleaseHdc(imgHdc); } } finally { // release memory buffer DeleteObject(dib); DeleteDC(memoryHdc); } zGraphics.DrawImageUnscaled(image, 0, 0); #else #if false using (Bitmap buffer = new Bitmap(zElement.width, zElement.height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)) { using (Graphics graphics = Graphics.FromImage(buffer)) { graphics.FillRectangle(Brushes.Transparent, 0, 0, zElement.width, zElement.height); // Produces the result below //graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit; // Produces clean text, but I'd really like ClearType! graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit; TextRenderer.DrawText(graphics, sLine, zFont, new Rectangle(0, 0, zElement.width, zElement.height), colorFont, zFormatFlags); } zGraphics.DrawImageUnscaled(buffer, 0, 0); } #else var zGraphicsTemp = Graphics.FromImage(zOpacityBitmap); zGraphicsTemp.SmoothingMode = SmoothingMode.AntiAlias; zGraphicsTemp.TextRenderingHint = TextRenderingHint.AntiAlias; TextRenderer.DrawText(zGraphicsTemp, sLine, zFont, new Rectangle(0, 0, zElement.width, zElement.height), colorFont, zFormatFlags); var zColor = new ColorMatrix { Matrix33 = (float)zElement.opacity / 255.0f }; var zAttrib = new ImageAttributes(); zAttrib.SetColorMatrix(zColor); var zBitmap = new Bitmap(zOpacityBitmap.Width, zOpacityBitmap.Height); // target image var zGraphicsX = Graphics.FromImage(zBitmap); // draw the source image into the destination with the desired opacity zGraphicsX.DrawImage(zOpacityBitmap, new Rectangle(0, 0, zBitmap.Width, zBitmap.Height), 0, 0, zBitmap.Width, zBitmap.Height, GraphicsUnit.Pixel, zAttrib); /** * * var zImageAttributes = new ImageAttributes(); * if (255 != zElement.opacity) * { * var zColor = new ColorMatrix * { * Matrix33 = (float)zElement.opacity / 255.0f * }; * zImageAttributes.SetColorMatrix(zColor); * } * * zDestinationBitmap = new Bitmap(nTargetWidth, nTargetHeight); // target image * var zGraphics = Graphics.FromImage(zDestinationBitmap); * // draw the source image into the destination with the desired opacity * zGraphics.DrawImage(zSourceBitmap, new Rectangle(0, 0, nTargetWidth, nTargetHeight), 0, 0, zSourceBitmap.Width, zSourceBitmap.Height, GraphicsUnit.Pixel, * zImageAttributes); * */ zGraphics.DrawImageUnscaled(zBitmap, 0, 0); #endif #endif } else { TextRenderer.DrawText(zGraphics, sLine, zFont, new Rectangle((int)zGraphics.Transform.OffsetX, (int)zGraphics.Transform.OffsetY, zElement.width, zElement.height), colorFont, zFormatFlags); } } catch (Exception) { Logger.AddLogLine("Unable to render text (font issue?)"); } } else { // prepare to draw text var zPath = new GraphicsPath(); try { #warning is there a path based text renderer thing to use? var zFormat = new StringFormat { LineAlignment = zElement.GetVerticalAlignment(), Alignment = zElement.GetHorizontalAlignment(), Trimming = StringTrimming.None, FormatFlags = StringFormatFlags.NoClip }; zPath.AddString(sLine, zFont.FontFamily, (int)zFont.Style, fEmSize, new RectangleF(0, nLineOffset, zElement.width, zElement.height), zFormat); CardRenderer.DrawPathOutline(zElement, zGraphics, zPath); } catch (Exception) { Logger.AddLogLine("Unable to render text (font issue?)"); } // fill in the outline zGraphics.FillPath(zBrush, zPath); } nLineOffset += zElement.lineheight; } }