// draws a single Paper Wallet in to a PdfSharp XForm private PdfSharp.Drawing.XForm getSingleWallet(PdfDocument doc, WalletBundle b, XImage imgArtwork, string address, string privkey, int numberWithinBatch, bool layoutDebugging) { WalletTemplate t = b.template; double width = t.widthMM; double height = t.heightMM; XUnit walletSizeWide = XUnit.FromMillimeter(width); XUnit walletSizeHigh = XUnit.FromMillimeter(height); PdfSharp.Drawing.XForm form = new PdfSharp.Drawing.XForm(doc, walletSizeWide, walletSizeHigh); using (XGraphics formGfx = XGraphics.FromForm(form)) { XGraphicsState state = formGfx.Save(); bool interpolateArtwork = true; bool interpolateQRcodes = false; // XImage imgArtwork is now provided by caller, so this process only has to be done ONCE - because the artwork does not change between Wallets in a run! //XImage imgArtwork = XImage.FromGdiPlusImage(b.getArtworkImage()); imgArtwork.Interpolate = interpolateArtwork; formGfx.DrawImage(imgArtwork, new RectangleF(0f, 0f, (float)walletSizeWide.Point, (float)walletSizeHigh.Point)); // draw the QR codes and legible-text things // Address // QR Bitmap bmpAddress = BtcAddress.QR.EncodeQRCode(address); XImage imgAddress = XImage.FromGdiPlusImage(bmpAddress); imgAddress.Interpolate = interpolateQRcodes; XUnit addressQrLeft = XUnit.FromMillimeter(t.addressQrLeftMM); XUnit addressQrTop = XUnit.FromMillimeter(t.addressQrTopMM); XUnit addressQrSize = XUnit.FromMillimeter(t.addressQrSizeMM); // only print Address QR if called for if (t.addressQrSizeMM > 0.1) { XRect addressQrRect = new XRect(addressQrLeft.Point, addressQrTop.Point, addressQrSize.Point, addressQrSize.Point); formGfx.DrawImage(imgAddress, addressQrRect); } // text address string addressSplitForLines = addressOrReferencePrep(address, t.addressTextCharsPerLine, t.addressTextContentVariant, numberWithinBatch); XFont fontAddress = new XFont(t.addressTextFontName, t.addressTextFontSize, t.addressTextFontStyle); XTextFormatter tf = new XTextFormatter(formGfx); XUnit addressTxtLeft = XUnit.FromMillimeter(t.addressTextLeftMM); XUnit addressTxtTop = XUnit.FromMillimeter(t.addressTextTopMM); XUnit addressTxtWidth = XUnit.FromMillimeter(t.addressTextWidthMM); XUnit addressTxtHeight = XUnit.FromMillimeter(t.addressTextHeightMM); XRect addressRect = new XRect(addressTxtLeft.Point, addressTxtTop.Point, addressTxtWidth.Point, addressTxtHeight.Point); tf.Alignment = XParagraphAlignment.Center; TextRotation addressTxtRotation = t.addressTextRotation; double addressTxtRotationDegrees = RotationMarkerToDegrees(addressTxtRotation); if (layoutDebugging) { formGfx.DrawRectangle(XBrushes.PowderBlue, addressRect); } XPoint rotateCentre = new XPoint(addressTxtLeft + (addressTxtWidth / 2), addressTxtTop + (addressTxtHeight / 2)); XPoint matrixRotatePoint = new XPoint(addressRect.X + (addressRect.Width / 2), addressRect.Y + (addressRect.Height / 2)); XMatrix rotateMatrix = new XMatrix(); rotateMatrix.RotateAtAppend(addressTxtRotationDegrees, rotateCentre); addressRect.Transform(rotateMatrix); if (layoutDebugging) { // draw a little tracer dot for where the centre of rotation is going to be double rotateDotSize = 2.0; formGfx.DrawEllipse(XBrushes.Red, rotateCentre.X - (rotateDotSize / 2), rotateCentre.Y - (rotateDotSize / 2), rotateDotSize, rotateDotSize); } // maybe even do some rotation of the lovely text! formGfx.Save(); formGfx.RotateAtTransform(addressTxtRotationDegrees, rotateCentre); if (layoutDebugging) { formGfx.DrawRectangle(XPens.OrangeRed, addressRect); } if (t.addressTextWidthMM > 0.1) { tf.DrawString(addressSplitForLines, fontAddress, t.GetBrushAddress, addressRect); } formGfx.Restore(); // Privkey // QR Bitmap bmpPrivkey = BtcAddress.QR.EncodeQRCode(privkey); XImage imgPrivkey = XImage.FromGdiPlusImage(bmpPrivkey); imgPrivkey.Interpolate = interpolateQRcodes; XUnit privkeyQrLeft = XUnit.FromMillimeter(t.privkeyQrLeftMM); XUnit privkeyQrTop = XUnit.FromMillimeter(t.privkeyQrTopMM); XUnit privkeyQrSize = XUnit.FromMillimeter(t.privkeyQrSizeMM); XRect privkeyQrRect = new XRect(privkeyQrLeft.Point, privkeyQrTop.Point, privkeyQrSize.Point, privkeyQrSize.Point); // only print privkey QR if specified - but you'd have to be an UTTER IDIOT to want to exclude this. Still, user input comes first! if (t.privkeyQrSizeMM > 0.1) { formGfx.DrawImage(imgPrivkey, privkeyQrRect); } // legible string privkeySplitForLines = lineSplitter(privkey, t.privkeyTextCharsPerLine); XFont fontPrivkey = new XFont(t.privkeyTextFontName, t.privkeyTextFontSize, t.privkeyTextFontStyle); XUnit privkeyTxtLeft = XUnit.FromMillimeter(t.privkeyTextLeftMM); XUnit privkeyTxtTop = XUnit.FromMillimeter(t.privkeyTextTopMM); XUnit privkeyTxtWidth = XUnit.FromMillimeter(t.privkeyTextWidthMM); XUnit privkeyTxtHeight = XUnit.FromMillimeter(t.privkeyTextHeightMM); TextRotation privkeyTxtRotation = t.privkeyTextRotation; double privkeyTxtRotationDegrees = RotationMarkerToDegrees(privkeyTxtRotation); XRect privkeyRect = new XRect(privkeyTxtLeft.Point, privkeyTxtTop.Point, privkeyTxtWidth.Point, privkeyTxtHeight.Point); if (layoutDebugging) { // draw a tracer rectangle for the original un-rotated text rectangle formGfx.DrawRectangle(XBrushes.PowderBlue, privkeyRect); } // rotate that lovely text around its middle when drawing! rotateCentre = new XPoint(privkeyTxtLeft + (privkeyTxtWidth / 2), privkeyTxtTop + (privkeyTxtHeight / 2)); matrixRotatePoint = new XPoint(privkeyRect.X + (privkeyRect.Width / 2), privkeyRect.Y + (privkeyRect.Height / 2)); rotateMatrix = new XMatrix(); rotateMatrix.RotateAtAppend(privkeyTxtRotationDegrees, rotateCentre); privkeyRect.Transform(rotateMatrix); if (layoutDebugging) { // draw a little tracer dot for where the centre of rotation is going to be double rotateDotSize = 2.0; formGfx.DrawEllipse(XBrushes.Red, rotateCentre.X - (rotateDotSize / 2), rotateCentre.Y - (rotateDotSize / 2), rotateDotSize, rotateDotSize); } formGfx.Save(); formGfx.RotateAtTransform(privkeyTxtRotationDegrees, rotateCentre); if (layoutDebugging) { formGfx.DrawRectangle(XPens.OrangeRed, privkeyRect); } // only print privkey text if specified. if (t.privkeyTextWidthMM > 0.1) { tf.DrawString(privkeySplitForLines, fontPrivkey, t.GetBrushPrivkey, privkeyRect); } formGfx.Restore(); } return(form); }