/// <summary> /// /// </summary> /// <param name="width"></param> /// <param name="height"></param> /// <param name="angle"></param> /// <returns></returns> /// <remarks> /// Code and logic from http://www.codeproject.com/KB/custom-controls/RotatedTextImageControl.aspx /// </remarks> protected RotationSize CalculateRotationSize(int width, int height, int angle) { int verticalOffset, horizontalOffset; int rotatedHeight, rotatedWidth; // convert the rotation angle to radians double radians = ((double)angle / 180) * Math.PI; // work out what the transalation offsets will need to be once the text is rotated // to make sure the containning rectangle fits on completely on the image if (angle <= 90) { verticalOffset = 0; horizontalOffset = (int)Math.Abs(Math.Ceiling((double)height * Math.Sin(radians))); } else if (angle <= 180) { horizontalOffset = (int)Math.Ceiling(Math.Abs(width * Math.Sin(radians - (Math.PI / 2))) + Math.Abs(height * Math.Cos(radians - (Math.PI / 2)))); verticalOffset = (int)Math.Ceiling(Math.Abs(height * Math.Sin(radians - (Math.PI / 2)))); } else if (angle <= 270) { verticalOffset = (int)Math.Ceiling(Math.Abs(width * Math.Sin(radians - (Math.PI))) + Math.Abs(height * Math.Cos(radians - (Math.PI)))); horizontalOffset = (int)Math.Ceiling(Math.Abs(width * Math.Cos(radians - (Math.PI)))); } else { verticalOffset = (int)Math.Ceiling(Math.Abs(width * Math.Cos(radians - (Math.PI * 1.5)))); horizontalOffset = 0; } // work out the size of the containing rectangle rotatedHeight = (int)Math.Ceiling(Math.Abs(height * Math.Cos(radians)) + (Math.Abs(width * Math.Sin(radians)))); rotatedWidth = (int)Math.Ceiling(Math.Abs(width * Math.Cos(radians)) + (Math.Abs(height * Math.Sin(radians)))); RotationSize rs = new RotationSize() { VerticalOffset = verticalOffset, HorizontalOffset = horizontalOffset, RotatedWidth = rotatedWidth, RotatedHeight = rotatedHeight }; return(rs); }
// TODO examine to add text to a transparent GIF image still works. public override Image ProcessImage(Image input, ProjectSetting ps) { try { if (ps.WatermarkCollection.Count < watermarkIndex) { return(input); } WatermarkText wt = ps.WatermarkCollection[this.watermarkIndex] as WatermarkText; if (wt == null) { return(input); } #if DEBUG Debug.WriteLine("Current Thread: " + Thread.CurrentThread.ManagedThreadId + "," + " Image File Name: " + this.ImageFileName + "," + " Watermark Text index: " + watermarkIndex); #endif int iHOffset = 0; int iVOffset = 0; int rotatedTextHeight = 0; int rotatedTextWidth = 0; int iBmpHeight = 0; int iBmpWidth = 0; float fHRes = 0; float fVRes = 0; int textWidth = 0; int textHeight = 0; int xAfterOffset = 0; int yAfterOffset = 0; string textToDraw = wt.Text; List <ExifContainerItem> tagsFound = this.FindExifTags(textToDraw); if (tagsFound != null && tagsFound.Count > 0 && !string.IsNullOrEmpty(this.ImageFileName)) { // at least one Exif tag is found textToDraw = ConvertExifTagsToText(textToDraw, tagsFound); } textToDraw = this.ConvertControlTagsToText(textToDraw); // create a bitmap we can use to work out the size of the text, // we will then create a new bitmap that is the right size. // we also use this to record the default resolution Bitmap bmp = new Bitmap(1, 1, PixelFormat.Format32bppArgb); fHRes = bmp.HorizontalResolution; fVRes = bmp.VerticalResolution; Graphics g = Graphics.FromImage(bmp); StringFormat format = new StringFormat(); format.Alignment = wt.WatermarkTextAlignment; SizeF sf = g.MeasureString(textToDraw, wt.WatermarkTextFont, Int32.MaxValue, format); g.Dispose(); bmp.Dispose(); // get the width and height of the text textWidth = Math.Max(2, (int)Math.Ceiling(sf.Width)); textHeight = Math.Max(2, (int)Math.Ceiling(sf.Height)); RotationSize rs = CalculateRotationSize(textWidth, textHeight, wt.WatermarkRotateAngle); iHOffset = rs.HorizontalOffset; iVOffset = rs.VerticalOffset; rotatedTextWidth = rs.RotatedWidth; rotatedTextHeight = rs.RotatedHeight; bmp = new Bitmap(input); iBmpWidth = bmp.Width; iBmpHeight = bmp.Height; g = Graphics.FromImage(bmp); // determine the offset needed to position the text in the right place // in the background if it is not the same size as we calculate was needed for the text // adding in the padding where necessary and // remembering to adjust for differences in padding between left/right top/bottom etc. switch (wt.WatermarkPosition) { case ContentAlignment.TopLeft: case ContentAlignment.TopCenter: case ContentAlignment.TopRight: //yAfterOffset = definition.TextPadding.Top; yAfterOffset = wt.Padding; break; case ContentAlignment.MiddleLeft: case ContentAlignment.MiddleCenter: case ContentAlignment.MiddleRight: //yAfterOffset = (bmp.Height - rotatedHeight) / 2 + definition.TextPadding.Top - definition.TextPadding.Bottom; yAfterOffset = (bmp.Height - rotatedTextHeight) / 2 + wt.Padding - wt.Padding; break; case ContentAlignment.BottomLeft: case ContentAlignment.BottomCenter: case ContentAlignment.BottomRight: //yAfterOffset = (bmp.Height - rotatedHeight) - definition.TextPadding.Bottom; yAfterOffset = (bmp.Height - rotatedTextHeight) - wt.Padding; break; } switch (wt.WatermarkPosition) { case ContentAlignment.TopLeft: case ContentAlignment.MiddleLeft: case ContentAlignment.BottomLeft: //xAfterOffset = definition.TextPadding.Left; xAfterOffset = wt.Padding; break; case ContentAlignment.TopCenter: case ContentAlignment.MiddleCenter: case ContentAlignment.BottomCenter: //xAfterOffset = (bmp.Width - rotatedWidth) / 2 + definition.TextPadding.Left - definition.TextPadding.Right; xAfterOffset = (bmp.Width - rotatedTextWidth) / 2 + wt.Padding - wt.Padding; break; case ContentAlignment.TopRight: case ContentAlignment.MiddleRight: case ContentAlignment.BottomRight: //xAfterOffset = (bmp.Width - rotatedWidth) - definition.TextPadding.Right; xAfterOffset = (bmp.Width - rotatedTextWidth) - wt.Padding; break; } // create a new transformation matrix to do the rotation and corresponding translation Matrix matrix = new Matrix(); // translation to position the text as required by HAlignment and VAlignment matrix.Translate(xAfterOffset, yAfterOffset); // translation to bring the rotation back to view matrix.Translate(iHOffset, iVOffset); // transformation to rotate the text matrix.Rotate(wt.WatermarkRotateAngle); if (wt.WatermarkTextAlignment == StringAlignment.Center) { // transformation to cope with non left aligned text matrix.Translate(textWidth / 2, 0); } else if (wt.WatermarkTextAlignment == StringAlignment.Far) { matrix.Translate(textWidth, 0); } // apply the transformation to the graphics object and write out the text g.Transform = matrix; g.SmoothingMode = SmoothingMode.HighQuality; g.TextRenderingHint = TextRenderingHint.AntiAlias; // draw a shadow with semi transparent black g.DrawString(textToDraw, wt.WatermarkTextFont, new SolidBrush(Color.FromArgb(153, 0, 0, 0)), 1, 1, format); // draw the sctual text g.DrawString(textToDraw, wt.WatermarkTextFont, new SolidBrush(wt.WatermarkTextColor), 0, 0, format); g.Transform = matrix; g.Dispose(); return(bmp); } catch (Exception ex) { Trace.TraceError(ex.ToString()); return(input); } }