I am trying to create custom digital signatures using iText (sharp, version 5.5.13) where the user is able to set the image location from a set of four positions (top, bottom, left and right), as shown below:
Rigth:
Left:
Top:
Bottom:
So far I tried working on layer 0 of the signature but I think I doing it wrong because signature details are set in layer 2.
Nevertheless, this is just an initial sketch to set position of the images. In the following code I load the image and put it in a chunk (idea taken from this example)
PdfTemplate pdfTemplate = sap.GetLayer(0);
ColumnText c1 = new ColumnText(pdfTemplate);
Image img = Image.GetInstance(signatureImage);
Phrase elements = new Phrase();
elements.Add(new Chunk(img, 0, 0, true));
//c1.SetSimpleColumn(elements, 0, 0, rectangle.Width, rectangle.Height / 4, 0, Element.ALIGN_CENTER); // align bottom
//c1.SetSimpleColumn(elements, 0, rectangle.Height / 2, rectangle.Width, rectangle.Height, 0, Element.ALIGN_CENTER); // align top
c1.SetSimpleColumn(elements, rectangle.Width/2, 0, rectangle.Width, rectangle.Height, 0, Element.ALIGN_CENTER); // align right
//c1.SetSimpleColumn(elements, 0, 0, rectangle.Width/2, rectangle.Height, 0, Element.ALIGN_CENTER); // align left
c1.Go();
The result is more or less the expected, but there are two problems: the signature information takes over the whole rectangle (this is normal since I do not modify layer 2, and the image in layer 0 is not scaled as it should)
If I scale the image to fit the column, it goes to the top of rectangle:
Is there any way to do this "out of the box" or I need to overload the method that builds the signature appearance (like this) and how can I achieve this?
My initial concert was not to use iText (v7) because we do not have much time to migrate all the projects we have with iText (v5), but I went ahead and tried out with v7. But to be honest is does not seem to be very easy to achieve with v5.
On the other hand, in iText (v7) I was able to do this very quickly with this simple method:
private static void SetCustomSignature(PdfDocument doc, PdfSignatureAppearance sap, SignatureFormat signatureFormat, X509Certificate2 signerCertificate) {
string signatureFont = signatureFormat.Font;
float signatureFontSize = float.Parse(signatureFormat.FontSize);
Rectangle rect = new Rectangle(250, 100, 200, 80);
sap.SetPageRect(rect).SetPageNumber(1);
PdfFormXObject layer2 = sap.GetLayer2();
PdfCanvas canvas = new PdfCanvas(layer2, doc);
float MARGIN = 2;
PdfFont font = PdfFontFactory.CreateFont();
string signingText = GetSignatureInfo(signerCertificate, signatureFormat);
// Signature at left and image at right
//Rectangle dataRect = new Rectangle(rect.GetWidth() / 2 + MARGIN / 2, MARGIN, rect.GetWidth() / 2 - MARGIN, rect.GetHeight() - 2 * MARGIN);
//Rectangle signatureRect = new Rectangle(MARGIN, MARGIN, rect.GetWidth() / 2 - 2 * MARGIN, rect.GetHeight() - 2 * MARGIN);
// Signature at right and image at left
//Rectangle dataRect = new Rectangle(MARGIN, MARGIN, rect.GetWidth() / 2 - MARGIN, rect.GetHeight() - 2 * MARGIN);
//Rectangle signatureRect = new Rectangle(rect.GetWidth() / 2 + MARGIN / 2, MARGIN, rect.GetWidth() / 2 - 2 * MARGIN, rect.GetHeight() - 2 * MARGIN);
// Signature at top and image at bottom
//Rectangle dataRect = new Rectangle(MARGIN, MARGIN, rect.GetWidth() - 2 * MARGIN, rect.GetHeight() / 2 - MARGIN);
//Rectangle signatureRect = new Rectangle(MARGIN, rect.GetHeight() / 2 + MARGIN, rect.GetWidth() - 2 * MARGIN, rect.GetHeight() / 2 - MARGIN);
// Signature at bottom and image at top
Rectangle dataRect = new Rectangle(MARGIN, rect.GetHeight() / 2 + MARGIN, rect.GetWidth() - 2 * MARGIN, rect.GetHeight() / 2 - MARGIN);
Rectangle signatureRect = new Rectangle(MARGIN, MARGIN, rect.GetWidth() - 2 * MARGIN, rect.GetHeight() / 2 - MARGIN);
try {
Canvas signLayoutCanvas = new Canvas(canvas, doc, signatureRect);
Paragraph paragraph = new Paragraph(signingText).SetFont(font).SetMargin(0).SetMultipliedLeading(0.9f).SetFontSize(10);
Div div = new Div();
div.SetHeight(signatureRect.GetHeight());
div.SetWidth(signatureRect.GetWidth());
div.SetVerticalAlignment(iText.Layout.Properties.VerticalAlignment.MIDDLE);
div.SetHorizontalAlignment(iText.Layout.Properties.HorizontalAlignment.CENTER);
div.Add(paragraph);
signLayoutCanvas.Add(div);
Canvas dataLayoutCanvas = new Canvas(canvas, doc, dataRect);
Image image = new Image(ImageDataFactory.Create(signatureFormat.SignatureImage));
image.SetAutoScale(true);
Div dataDiv = new Div();
dataDiv.SetHeight(dataRect.GetHeight());
dataDiv.SetWidth(dataRect.GetWidth());
dataDiv.SetVerticalAlignment(iText.Layout.Properties.VerticalAlignment.MIDDLE);
dataDiv.SetHorizontalAlignment(iText.Layout.Properties.HorizontalAlignment.CENTER);
dataDiv.Add(image);
dataLayoutCanvas.Add(dataDiv);
}
catch {
throw;
}
}
This will result in the following signatures:
Of course, it still needs some improvements but it may serve as an example for others :-)
Related
I have a program that creates a specific number of rectangles according to how many I want. When I create 1 Rectangle the Height is 400 when I create 2 Rectangles then the height is 200 when I create 4 Rectangles the height is 100, I think you understand what I'm doing. Now I want to place them one under each other. I give you 3 examples.
This is how it looks like when I create 1 Rectangle
And when I want to create 2 Rectangles the height should get divided by 2. I already did that and that's working but I can't place them
like this under each other.
Only one more example if someone doesn't understand what I'm trying. This is how it should look like when I create 5 Rectangles.
I tried putting them under each other like that:
Canvas.SetLeft(MyRectangle[i], Width / 2.0 - MyRectangle[i].Width / 2.0);
Canvas.SetTop(MyRectangle[i], i * 120);
But that looks like this, it's not on top of the screen, and the other problem is that when I would want to create 2 it looks like this. So I tried around with using i from the loop but I can't figure anything out. This is my code:
Brush brush = new SolidColorBrush(Color.FromRgb((byte)_random.Next(1, 255), (byte)_random.Next(1, 255), (byte)_random.Next(1, 255)));
int howmanyrect = 3;
Rectangle[] MyRectangle = new Rectangle[howmanyrect];
if (howmanyrect == 1)
{
Rectangle OneRectangle = new Rectangle();
OneRectangle.Fill = brush;
OneRectangle.StrokeThickness = 2;
OneRectangle.Stroke = Brushes.Black;
OneRectangle.Width = 400;
OneRectangle.Height = 400;
Canvas.SetLeft(OneRectangle, Width / 2.0 - OneRectangle.Width / 2.0);
Canvas.SetTop(OneRectangle, 30);
myCanvas.Children.Add(OneRectangle);
Content = myCanvas;
}
for (int i = 1; i <= howmanyrect - 1; i++)
{
MyRectangle[i] = new Rectangle
{
Fill = brush,
StrokeThickness = 2,
Stroke = Brushes.Black,
Width = 400,
Height = 400 / howmanyrect
};
Canvas.SetLeft(MyRectangle[i], Width / 2.0 - MyRectangle[i].Width / 2.0);
Canvas.SetTop(MyRectangle[i], i * 120);
myCanvas.Children.Add(MyRectangle[i]);
Content = myCanvas;
}
I try to fix your code :
Brush brush = new SolidColorBrush(Color.FromRgb((byte)_random.Next(1, 255), (byte)_random.Next(1, 255), (byte)_random.Next(1, 255)));
int howmanyrect = 3;
Rectangle[] MyRectangle = new Rectangle[howmanyrect];
for (int i = 0; i < howmanyrect; i++)
{
var rectangle = new Rectangle
{
Fill = brush,
StrokeThickness = 2,
Stroke = Brushes.Black,
Width = 400,
Height = 400 / howmanyrect
};
MyRectangle[i] = rectangle;
Canvas.SetLeft(rectangle, Width / 2.0 - rectangle.Width / 2.0);
var distance = 10;
Canvas.SetTop(rectangle, 30 + i * (400 / howmanyrect) + distance );
myCanvas.Children.Add(rectangle);
}
Content = myCanvas;
I have a rectangular selection made programatically on an Image.The user is provided the option to set the size of the rectangle,on doing so the rectangle size should increase but the center point of the old rectangle should be maintained,so that the contents within the rectangle is not out of focus.
Is this a correct approach
objSmall.X = CInt(objBig.X + (Math.Round(((objBig.Width / 2) - (objSmall.Width / 2)), 0)))
objSmall.Y = CInt(objBig.Y + (Math.Round(((objBig.Height / 2) - (objSmall.Height / 2)), 0)))
The new rectangle can be larger or smaller than the old one.
The calculation is correct; it can be simplified using just one integer division:
(and translated to C#, because the source code is VB.Net)
An integer division (MSDN Docs) can be used because we're dividing by 2, it's like rounding down. But you should use floating point values (float) when drawing, especially moving objects (with values expressed in both degrees and, of course, radians): your positions will be off quite a bit if you don't.
objSmall.X = objBig.X + (objBig.Width - objSmall.Width) / 2;
objSmall.Y = objBig.Y + (objBig.Height - objSmall.Height) / 2;
Or (2):
objSmall.Location = new Point(objBig.X + (objBig.Width - objSmall.Width) / 2,
objBig.Y + (objBig.Height - objSmall.Height) / 2);
Or, using the relative Centre coordinates of the larger object:
Point BigRectCenter = new Point((objBig.Width / 2) + objBig.X, (objBig.Height / 2) + objBig.Y);
objSmall.Location = new Point(BigRectCenter.X - (objSmall.Width / 2),
BigRectCenter.Y - (objSmall.Height / 2));
The (2) method can be also used when you don't know which one of the Rectangles is the largest.
Assume you know your reference Rectangle's Location and Size and you let the User specify the new Size of the selection:
Rectangle OriginalRect = new Rectangle(30, 30, 120, 90);
Rectangle ResizedRect = new Rectangle(0, 0, 140, 140);
The ResizedRect has a Size (defined by the User) but its Location is unknown at this point.
The new selection Rectangle's (ResizedRect) Location can be calculated with:
ResizedRect.Location = new Point(OriginalRect.X + (OriginalRect.Width - ResizedRect.Width) / 2,
OriginalRect.Y + (OriginalRect.Height - ResizedRect.Height) / 2);
Original Selection (Green) Original Selection (Green)
(20, 20, 120, 120) (30, 30, 120, 90)
Resized Selection (Red) Resized Selection (Red)
( 0, 0, 95, 86) ( 0, 0, 140, 140)
Calculated Selection Calculated Selection
Rectangle Rectangle
(32, 37, 95, 86) (20, 5, 140, 140)
I use drawstring method to draw text inside rectangle ,.. i wanted to rotate the text 180 degree so i used this code
Rectangle displayRectangleh =
new Rectangle(new Point((int)posh.X, (int)posh.Y), new Size(rectwdh, recth));
StringFormat format1h = new StringFormat(StringFormatFlags.DirectionVertical);
format1h.LineAlignment = StringAlignment.Center;
format1h.Alignment = StringAlignment.Center;
b = new SolidBrush(Color.Black);
e.ChartGraphics.Graphics.TranslateTransform((float)rectwdh / 2 + posh.X, recth / 2 + posh.Y);
e.ChartGraphics.Graphics.RotateTransform(180);
e.ChartGraphics.Graphics.TranslateTransform(-((float)rectwdh / 2 + posh.X), -(recth / 2 + posh.Y));
Font boldFonth = new Font(FontFamily.GenericSansSerif, 16, FontStyle.Bold, GraphicsUnit.Pixel, 1, true);
e.ChartGraphics.Graphics.DrawRectangle(new Pen(Color.Black, 2), displayRectangleh);
e.ChartGraphics.Graphics.DrawString("This is rotated long text test ", boldFonth, b, (RectangleF)displayRectangleh, format1h);
e.ChartGraphics.Graphics.ResetTransform();
where posh.X and posh.Y (recatangle position) , rectwdh (rectangle width) and recth (rectangle height)
It works perfect for short text but for long text the new line will be above my old line see the next pic :
I even tried to add new line character \n but same result.
my question : how to rotate the text 180 inside rectangle and end up with proper alignment ??
Never having even used the StringFormat APIs before, I pounded at it randomly until I found this:
StringFormat format1h = new StringFormat(StringFormatFlags.DirectionVertical | StringFormatFlags.DirectionRightToLeft);
I have created a image button for my apps on windows mobile. There is a small problem though, when i have different screen resolutions,bigger for example, the image isn't automatic resized to fit in the control. How can this be done?
thanks in advance.
this is my code for the onPaint function
Dim gxOff As Graphics
'Offscreen graphics
Dim imgRect As Rectangle
'image rectangle
Dim backBrush As Brush
'brush for filling a backcolor
If m_bmpOffscreen Is Nothing Then
'Bitmap for doublebuffering
m_bmpOffscreen = New Bitmap(Me.Width, Me.Height)
End If
gxOff = Graphics.FromImage(m_bmpOffscreen)
gxOff.Clear(Me.BackColor)
If Not bPushed Then
backBrush = New SolidBrush(Parent.BackColor)
Else
backBrush = New SolidBrush(Color.Black)
'change the background when it's pressed
End If
gxOff.FillRectangle(backBrush, Me.ClientRectangle)
If m_image IsNot Nothing Then
'Center the image relativelly to the control
Dim imageLeft As Integer = (Me.Width - m_image.Width) / 2
Dim imageTop As Integer = (Me.Height - m_image.Height) / 2
If Not bPushed Then
imgRect = New Rectangle(imageLeft, imageTop, m_image.Width, m_image.Height)
Else
'The button was pressed
'Shift the image by one pixel
imgRect = New Rectangle(imageLeft + 1, imageTop + 1, m_image.Width, m_image.Height)
End If
'Set transparent key
Dim imageAttr As New Imaging.ImageAttributes()
imageAttr.SetColorKey(BackgroundImageColor(m_image), BackgroundImageColor(m_image))
'Draw image
gxOff.DrawImage(m_image, imgRect, 0, 0, m_image.Width, m_image.Height, GraphicsUnit.Pixel, imageAttr)
End If
If bPushed Then
'The button was pressed
'Prepare rectangle
Dim rc As Rectangle = Me.ClientRectangle
rc.Width -= 1
rc.Height -= 1
'Draw rectangle
gxOff.DrawRectangle(New Pen(Color.Black), rc)
End If
'Draw from the memory bitmap
e.Graphics.DrawImage(m_bmpOffscreen, 0, 0)
MyBase.OnPaint(e)
You need to scale image during OnPaint e.g.:
if (this._image != null)
{
int x = (this.Width - this._image.Width) / 2;
int y = (this.Height - this._image.Height) / 2;
var imgRect = new Rectangle(x, y, this._image.Width, this._image.Height);
var imageAttr = new ImageAttributes();
Color clr = this._image.GetPixel(0, 0);
imageAttr.SetColorKey(clr, clr);
gr2.DrawImage(this._image, imgRect, 0, 0, this._image.Width, this._image.Height, GraphicsUnit.Pixel, imageAttr);
}
Above example is how to draw image with transparent color based on first pixel. Now you need to ammend second 3 lines:
bool qvga = Screen.PrimaryScreen.Bounds.Height == 240 || Screen.PrimaryScreen.Bounds.Width == 240;
int x = (this.Width - (qvga ? this._image.Width : this._image.Width * 2)) / 2;
int y = (this.Height - (qvga ? this._image.Height : this._image.Height * 2)) / 2;
var imgRect = new Rectangle(x, y, (qvga ? this._image.Width : this._image.Width * 2), (qvga ? this._image.Height : this._image.Height * 2));
[Edit]
Seeing your code change is straight forward. Like I described in comment: For two main windows mobile resolutions, QVGA and VGA, we assuming that image is for QVGA size. Please convert my code to VB by yourself. So set qvga flag as I written:
bool qvga = Screen.PrimaryScreen.Bounds.Height == 240 || Screen.PrimaryScreen.Bounds.Width == 240;
now based on flag ammend following based on my above code:
Dim imageLeft As Integer = (Me.Width - m_image.Width) / 2
Dim imageTop As Integer = (Me.Height - m_image.Height) / 2
and then this ones:
If Not bPushed Then
imgRect = New Rectangle(imageLeft, imageTop, m_image.Width, m_image.Height)
Else
'The button was pressed
'Shift the image by one pixel
imgRect = New Rectangle(imageLeft + 1, imageTop + 1, m_image.Width, m_image.Height)
End If
I want to draw a custom TabControl with custom functionality.
To do this, i inherited the Panel class and overrided OnPaint method to draw with TabRenderer class.
The problem is that TabRenderer working only when visual styles enabled (can be checked with TabRenderer.IsSupported), but what should i do if visual styles disabled?
In this case, I thought using the ControlPaint class to draw tabs without visual styles, but it has no draw methods related to Tabs. I want it basically to behave visually like the regular TabControl.
You have to draw it by yourself, because there is not published API for this. Hopefully this is relatively easy to do it in non-visualstyles way.
You can draw pane border with ControlPaint.DrawBorder3D and use something like the following code for buttons:
int Top = bounds.Top;
int Bottom = bounds.Bottom - 1;
int Sign = 1;
if (tabStrip.EffectiveOrientation == TabOrientation.Bottom)
{
Top = bounds.Bottom - 1;
Bottom = bounds.Top;
Sign = -1;
}
using (Pen OuterLightBorderPen = new Pen(SystemColors.ControlLightLight))
{
e.Graphics.DrawLine(OuterLightBorderPen, bounds.Left, Bottom, bounds.Left, Top + 2 * Sign);
e.Graphics.DrawLine(OuterLightBorderPen, bounds.Left, Top + 2 * Sign, bounds.Left + 2, Top);
e.Graphics.DrawLine(OuterLightBorderPen, bounds.Left + 2, Top, bounds.Right - 3, Top);
}
using (Pen InnerLightBorderPen = new Pen(SystemColors.ControlLight))
{
e.Graphics.DrawLine(InnerLightBorderPen, bounds.Left + 1, Bottom, bounds.Left + 1, Top + 2 * Sign);
e.Graphics.DrawLine(InnerLightBorderPen, bounds.Left + 2, Top + 1 * Sign, bounds.Right - 3, Top + 1 * Sign);
}
using (Pen OuterDarkBorderPen = new Pen(SystemColors.ControlDarkDark))
{
e.Graphics.DrawLine(OuterDarkBorderPen, bounds.Right - 2, Top + 1 * Sign, bounds.Right - 1, Top + 2 * Sign);
e.Graphics.DrawLine(OuterDarkBorderPen, bounds.Right - 1, Top + 2 * Sign, bounds.Right - 1, Bottom);
}
using (Pen InnerDarkBorderPen = new Pen(SystemColors.ControlDark))
e.Graphics.DrawLine(InnerDarkBorderPen, bounds.Right - 2, Top + 2 * Sign, bounds.Right - 2, Bottom);
This is an "out there" answer but is it possible that you could use wpf? As you can see from the answer above it is a pain in the ear to customise controls in winforms where as in WPF each control is lookless. This means that you control what is rendered and how it looks completely.