Winnovative, PdfConverter Setting the Header and Footer height dynamicaly - asp.net

I am using the Winnovative's PdfConverter to convert my HTML page to a PDF, i am able to get the PDF with header footer and all. But i have a requirement where i need to set the height of the Header and footer dynamically based on the content of the text that needs to be added. Below is the code i tried to achieve this but was not successful. Please can you help on what would i be missing here, or is there any other method i need to follow.
The PdfFooterOptions.FooterHeight is initially set to default 40px.
PdfConverter pdfConverter = new PdfConverter();
// set the converter options
pdfConverter.PdfDocumentOptions.PdfPageSize = PdfPageSize.A4;
pdfConverter.PdfDocumentOptions.PdfCompressionLevel = PdfCompressionLevel.Normal;
pdfConverter.PdfDocumentOptions.PdfPageOrientation = PdfPageOrientation.Portrait;
// set header and footer
pdfConverter.PdfDocumentOptions.ShowHeader = true;
pdfConverter.PdfDocumentOptions.ShowFooter = true;
//Add header and footer text
AddHeaderElements(pdfConverter, text);
AddFooterElements(pdfConverter, text);
// set the HTML content
pdfConverter.PdfDocumentOptions.FitWidth = true;
// set the embedded fonts option
pdfConverter.PdfDocumentOptions.EmbedFonts = true;
// set the live HTTP links option
pdfConverter.PdfDocumentOptions.LiveUrlsEnabled = true;
// set the JavaScript
pdfConverter.JavaScriptEnabled = true;
// set the images in PDF are compressed with JPEG to reduce the PDF document size
pdfConverter.PdfDocumentOptions.JpegCompressionEnabled = true;
// enable auto-generated bookmarks for a specified list of tags (e.g. H1 and H2)
pdfConverter.PdfBookmarkOptions.HtmlElementSelectors = new string[] { "H1", "H2" };
// Performs the conversion and get the pdf document bytes that can be further
// saved to a file or sent as response to browser
// The baseURL parameter helps the converter to get the CSS files and images
// referenced by a relative URL in the HTML string.
byte[] pdfValue = null;
pdfValue = pdfConverter.GetPdfBytesFromHtmlString(htmlCodeToConvert);
private void AddFooterElements(PdfConverter pdfConverter, string title)
{
//write the page number
TextElement footerText = new TextElement(550, pdfConverter.PdfFooterOptions.FooterHeight - 20,
string.Format(uiContentController.GetText("Aanvarag_Page"), "&p;", "&P;"),
new System.Drawing.Font(new System.Drawing.FontFamily("Tahoma"),
7, System.Drawing.GraphicsUnit.Point));
footerText.EmbedSysFont = true;
footerText.TextAlign = HorizontalTextAlign.Left;
pdfConverter.PdfFooterOptions.AddElement(footerText);
// set the footer HTML area
HtmlToPdfElement footerHtml = new HtmlToPdfElement(10, 0, 0,
0,
title, null, 1024, 0);
footerHtml.NavigationCompletedEvent += OnFooterHtmlNavigationCompleted;
pdfConverter.PdfFooterOptions.AddElement(footerHtml);
}
void OnFooterHtmlNavigationCompleted(NavigationCompletedParams eventParams)
{
// Get the header HTML width and height from event parameters
float footerHtmlWidth = eventParams.HtmlContentWidthPt;
float footerHtmlHeight = eventParams.HtmlContentHeightPt;
// Calculate the header width from coverter settings
float footerWidth = pdfConverter.PdfDocumentOptions.PdfPageSize.Width - pdfConverter.PdfDocumentOptions.LeftMargin -
pdfConverter.PdfDocumentOptions.RightMargin;
// Calculate a resize factor to fit the header width
float resizeFactor = 1;
if (footerHtmlWidth > footerWidth)
resizeFactor = footerWidth / footerHtmlWidth;
// Calculate the header height to preserve the HTML aspect ratio
float footerHeight = footerHtmlHeight * resizeFactor;
// Set the calculated header height
pdfConverter.PdfFooterOptions.FooterHeight = footerHeight;
}

There is a working example with source code for headers. For footers should be similar.
// Define the HTML to PDF converter object as a class member to make it accessible in the headerHtml_NavigationCompletedEvent handler
// where the header height will be automatically adjusted
private HtmlToPdfConverter htmlToPdfConverter;
// Indicates if a line should be drawn at the botom of the header
private bool drawHeaderLine = true;
protected void convertToPdfButton_Click(object sender, EventArgs e)
{
// Create a HTML to PDF converter object with default settings
htmlToPdfConverter = new HtmlToPdfConverter();
// Set license key received after purchase to use the converter in licensed mode
// Leave it not set to use the converter in demo mode
htmlToPdfConverter.LicenseKey = "fvDh8eDx4fHg4P/h8eLg/+Dj/+jo6Og=";
// Enable header in the generated PDF document
htmlToPdfConverter.PdfDocumentOptions.ShowHeader = true;
string headerHtmlUrl = Server.MapPath("~/DemoAppFiles/Input/HTML_Files/Header_HTML.html");
Document documentObject = null;
try
{
if (autoResizeHeaderRadioButton.Checked)
{
// Create a HTML element to be added in header
HtmlToPdfElement headerHtml = new HtmlToPdfElement(headerHtmlUrl);
// Install a handler where to set the automatically calculated header height
headerHtml.NavigationCompletedEvent += new NavigationCompletedDelegate(headerHtml_NavigationCompletedEvent);
// Add the HTML element to header
// When the element is rendered in header by converter, the headerHtml_NavigationCompletedEvent handler
// will be invoked and the header height will be automatically calculated
htmlToPdfConverter.PdfHeaderOptions.AddElement(headerHtml);
// Call the converter to produce a Document object
documentObject = htmlToPdfConverter.ConvertUrlToPdfDocumentObject(urlTextBox.Text);
// Uninstall the handler
headerHtml.NavigationCompletedEvent -= new NavigationCompletedDelegate(headerHtml_NavigationCompletedEvent);
// Draw a line at the header bottom
if (drawHeaderLine)
{
float headerWidth = documentObject.Header.Width;
float headerHeight = documentObject.Header.Height;
// Create a line element for the bottom of the header
LineElement headerLine = new LineElement(0, headerHeight - 1, headerWidth, headerHeight - 1);
// Set line color
headerLine.ForeColor = Color.Gray;
// Add line element to the bottom of the header
documentObject.Header.AddElement(headerLine);
}
// Save the PDF document in a memory buffer
byte[] outPdfBuffer = documentObject.Save();
// Send the PDF as response to browser
// Set response content type
Response.AddHeader("Content-Type", "application/pdf");
// Instruct the browser to open the PDF file as an attachment or inline
Response.AddHeader("Content-Disposition", String.Format("attachment; filename=Auto_Resize_Header_Footer.pdf; size={0}", outPdfBuffer.Length.ToString()));
// Write the PDF document buffer to HTTP response
Response.BinaryWrite(outPdfBuffer);
// End the HTTP response and stop the current page processing
Response.End();
}
else
{
// Create a HTML to PDF element to be added in header
HtmlToPdfElement headerHtml = new HtmlToPdfElement(headerHtmlUrl);
// Set a fixed header height in points
htmlToPdfConverter.PdfHeaderOptions.HeaderHeight = float.Parse(headerHeightTextBox.Text);
// Set the HTML element to fit the container height
headerHtml.FitHeight = true;
// Add HTML element to fit the fixed header height
htmlToPdfConverter.PdfHeaderOptions.AddElement(headerHtml);
// Draw a line at the header bottom
if (drawHeaderLine)
{
// Calculate the header width based on PDF page size and margins
float headerWidth = htmlToPdfConverter.PdfDocumentOptions.PdfPageSize.Width -
htmlToPdfConverter.PdfDocumentOptions.LeftMargin - htmlToPdfConverter.PdfDocumentOptions.RightMargin;
// Calculate header height
float headerHeight = htmlToPdfConverter.PdfHeaderOptions.HeaderHeight;
// Create a line element for the bottom of the header
LineElement headerLine = new LineElement(0, headerHeight - 1, headerWidth, headerHeight - 1);
// Set line color
headerLine.ForeColor = Color.Gray;
// Add line element to the bottom of the header
htmlToPdfConverter.PdfHeaderOptions.AddElement(headerLine);
}
// Convert the HTML page to a PDF document in a memory buffer
byte[] outPdfBuffer = htmlToPdfConverter.ConvertUrl(urlTextBox.Text);
// Send the PDF as response to browser
// Set response content type
Response.AddHeader("Content-Type", "application/pdf");
// Instruct the browser to open the PDF file as an attachment or inline
Response.AddHeader("Content-Disposition", String.Format("attachment; filename=Auto_Resize_Header_Footer.pdf; size={0}", outPdfBuffer.Length.ToString()));
// Write the PDF document buffer to HTTP response
Response.BinaryWrite(outPdfBuffer);
// End the HTTP response and stop the current page processing
Response.End();
}
}
finally
{
// Close the PDF document
if (documentObject != null)
documentObject.Close();
}
}
/// <summary>
/// This handler is called after the navigation to header HTML completed. The document header is resized in this event handler
/// </summary>
/// <param name="eventParams">The event parameter containing the HTML content size in pixels and points</param>
void headerHtml_NavigationCompletedEvent(NavigationCompletedParams eventParams)
{
// Get the header HTML width and height from event parameters
float headerHtmlWidth = eventParams.HtmlContentWidthPt;
float headerHtmlHeight = eventParams.HtmlContentHeightPt;
// Calculate the header width from coverter settings
float headerWidth = htmlToPdfConverter.PdfDocumentOptions.PdfPageSize.Width - htmlToPdfConverter.PdfDocumentOptions.LeftMargin -
htmlToPdfConverter.PdfDocumentOptions.RightMargin;
// Calculate a resize factor to fit the header width
float resizeFactor = 1;
if (headerHtmlWidth > headerWidth)
resizeFactor = headerWidth / headerHtmlWidth;
// Calculate the header height to preserve the HTML aspect ratio
float headerHeight = headerHtmlHeight * resizeFactor;
if (!(headerHeight < htmlToPdfConverter.PdfDocumentOptions.PdfPageSize.Height - htmlToPdfConverter.PdfDocumentOptions.TopMargin -
htmlToPdfConverter.PdfDocumentOptions.BottomMargin))
{
throw new Exception("The header height cannot be bigger than PDF page height");
}
// Set the calculated header height
htmlToPdfConverter.PdfDocumentOptions.DocumentObject.Header.Height = headerHeight;
}

Related

How to resize image from import image url in Wordpress?

This function can resize image when we upload at add new post and publish. When I try to use any import CSV plugin (Ultimate CSV Importer) for create multiple post and put my image url from other website, this function will not resize the image.
Can someone help to modified this function so can resize image during import?
// Hook the function to the upload handler
// https://developer.wordpress.org/reference/hooks/wp_handle_upload/
add_filter('wp_handle_upload', 'resize_image_after_upload');
function resize_image_after_upload($image_data){
// Set to null to disable that width/height resizing
$max_width = 800;
$max_height = 800;
// Check if there is a valid file
if(empty($image_data['file']) || empty($image_data['type'])) {
return $image_data;
}
// NOTE: We are not resizing any gifs, to avoid resizing animated gifs
// (which I think is the most common gif nowadays)
$valid_types = array('image/png','image/jpeg','image/jpg', 'image/webp');
if(!in_array($image_data['type'], $valid_types)) {
return $image_data;
}
// Get image image_editor
// https://developer.wordpress.org/reference/classes/wp_image_editor/
$image_editor = wp_get_image_editor($image_data['file']);
if(is_wp_error($image_editor)) {
return $image_data;
}
// Check if the image editor supports the image type
if(!$image_editor->supports_mime_type($image_data['type'])) {
return $image_data;
}
// Perform resizing
$sizes = $image_editor->get_size();
if((isset($sizes['width']) && $sizes['width'] > $max_width)
|| (isset($sizes['height']) && $sizes['height'] > $max_height)) {
// Resize, but do not crop
$image_editor->resize($max_width, $max_height, false);
// We will use the default recommended image quality
// Change, if you want to set a custom quality
//$image_editor->set_quality(90);
$image_editor->save($image_data['file']);
}
return $image_data;
}

Scrolling sets to top once new data is appended to wijmo-grid in virtual scrolling

While implementing virtual scrolling with wijmo grid, as per the below code, when the new data is appended to data array (once we scroll and reach to the last record of the grid), the scroll gets reset to the initial position.
Check this JSFiddle
scrollPositionChanged: function(s, e) {
// if we're close to the bottom, add 10 items
if (s.viewRange.bottomRow >= s.rows.length - 1) {
addData(data, 20);
s.collectionView.refresh();
}
}
Any idea how can we stop this behaviour? Other grids like slickgrid, ag-grid provides smooth behaviour - once the data is appended, the previous last record stays in the view. Can we achieve similar kind of behaviour for wijmo-grid?
You can save scroll postion before refreshing the grid and restore the same after scroll.
var pos;
var grid = new wijmo.grid.FlexGrid('#flex', {
itemsSource: data,
scrollPositionChanged: function (s, e) {
// if we're close to the bottom, add 10 items
if (s.viewRange.bottomRow >= s.rows.length - 1) {
addData(data, 20);
//save current scroll postion
pos = grid.scrollPosition;
s.collectionView.refresh();
}
//restore scroll position
if (pos) {
s.scrollPosition = Object.assign({}, pos);
pos = null;
}
}
});
Check the updated fiddle:- http://jsfiddle.net/797tjc5u/
You need to store scroll position before making http request and set back once items have been added to FlexGrid.
Please refer to the following updated fiddle with http service delay simulation:
[http://jsfiddle.net/hwr2ra1q/41/][1]

Glass Mapper breaking standard values for image field

Consider the template:
Company
Logo (Image field)
Company Name (Text field)
The Company template has standard values set on both fields. If we get a Company item and save it using Glass without making any changes, the Logo field no longer uses the standard value. (The Company Name field is untouched.)
The issue, it seems, is that the Glass.Mapper.Sc.DataMappers.SitecoreFieldImageMapper serializes the value of that field differently than Sitecore does. When it tries to save, it thinks it's a change to the field and no longer uses the standard value.
Standard Value:
<image mediaid="{GUID}" />
Glass-generated Value:
<image height="64" width="64" mediaid="{GUID}" alt="Alt text" />
Is there a way to make Glass generate the same output as Sitecore?
I think that problem is in a way how SitecoreFieldImageMapper map ImageField to Image. For getting Height, Width and Alt are used public properties. If we look on them via reflector we will see that values of it get not directly from field:
public string Alt
{
get
{
string text = base.GetAttribute("alt");
if (text.Length == 0)
{
Item item = this.MediaItem;
if (item != null)
{
MediaItem mediaItem = item;
text = mediaItem.Alt;
if (text.Length == 0)
{
text = item["Alt"];
}
}
}
return text;
}
set
{
base.SetAttribute("alt", value);
}
}
If field does not contain value(e.g. for "alt": if (text.Length == 0)) then value will be received from MediaItem that is linked. It cause adding Height, Width and Alt from media library item after saving of field.
To fix this problem you could try replace this code:
int height = 0;
int.TryParse(field.Height, out height);
int width = 0;
int.TryParse(field.Width, out width);
img.Alt = field.Alt;
img.Height = height;
img.Width = width;
with direct getting attributes rather than usage of properties:
int height = 0;
if(int.TryParse(field.GetAttribute("height"), out height))
{
img.Height = height;
}
int width = 0;
if(int.TryParse(field.GetAttribute("width"), out width))
{
img.Width = width;
}
img.Alt = field.GetAttribute("alt");
With Alt property everything should be ok. But there could be problems with Width and Height as they are not Nullable and I am not sure how GlassMapper will handle Image with Width and Height that you haven't set.

FlashBuilder 4.5 :: Render Text without lifecycle for upsampling

I need to find a way to "upsample" text from 72dpi (screen) to 300dpi (print) for rendered client generated text. This is a true WYSIWYG application and we're expecting a ton of traffic so client side rendering is a requirement. Our application has several fonts, font sizes, colors, alignments the user can modify in a textarea. The question is how to convert 72dpi to 300dpi. We have the editior complete, we just need to make 300dpi versions of the textarea.
MY IDEA
1) Get textarea and increase the height, width, and font size by 300/72. (if ints are needed on font size I may need to increase the font then down-sample to the height/width)
2) use BitmapUtil.getSnapshot on the textarea to get a rendered version of the text
THE QUESTION
How can I render text inside of a textarea without the component lifecycle? Imagine:
var textArea:TextArea = new TextArea();
textArea.text = "This is a test";
var bmd:BitmapData = textArea.render();
Like Flextras said, width/height has nothing to do with DPI, unless you actually zoom into the application by 4.16X. If your application all has vector based graphics, it shouldn't be a problem. Plus, the concept of DPI is lost in any web application until you're trying to save/print a bitmap.
It's definitely possible, but you'll have to figure it on your own.
To ask a question another way, it is possible to create a TextArea in
memory which I can use the BitmapUtil.getSnapshot() function to
generate a BitmapData object
Technically, all components are in memory. What you want to do, I believe, is render a component without adding it to a container.
We do exactly this for the watermark on Flextras components. Conceptually we created a method to render the instance; like this:
public function render(argInheritingStyles : Object):void{
this.createChildren();
this.childrenCreated();
this.initializationComplete();
this.inheritingStyles = argInheritingStyles;
this.commitProperties();
this.measure();
this.height = this.measuredHeight;
this.width = this.measuredWidth;
this.updateDisplayList(this.unscaledWidth,this.unscaledHeight);
}
The method must be explicitly called. Then you can use the 'standard' procedure for turning the component into a bitmap. I think we use a Label; but the same approach should work on any given component.
Here is the final method I used to solve the problem of creating a printable version of the text and style of a Spark TextArea component. I ended up placing the custom component TextAreaRenderer (see below) in the MXML and setting the visibility to false. Then using the reference to this component to process any text field (renderObject) and get back a BitmapData object.
public class TextAreaRenderer extends TextArea implements IAssetRenderer
{
public function render(renderObject:Object, dpi:int = 300):BitmapData{
// CAST THE OBJECT
//.................
var userTextArea:TextArea = TextArea(renderObject);
// SCALE IS THE DIVISION OF THE NEW DPI OVER THE SCREEN DPI 72
//............................................................
var scale:Number = dpi / 72;
// COPY THE USER'S TEXT AREA INTO THE OFFSCREEN TEXT AREA
//.......................................................
this.text = userTextArea.text; // the actual text
this.height = Math.floor(userTextArea.height * scale); // scaled height
this.width = Math.floor(userTextArea.width * scale); // scaled width
// GET THE LAYOUT FORMATS AND COPY TO OFFSCREEN
// - the user's format = userTextAreaLayoutFormat
// - the hidden format = thisLayoutFormat
//...............................................
var editableLayoutProperties:Array = ['fontSize', 'fontFamily', 'fontWeight', 'fontStyle', 'textAlign', 'textDecoration', 'color']
userTextArea.selectAll();
var userTextAreaLayoutFormat:TextLayoutFormat = userTextArea.getFormatOfRange();
this.selectAll();
var thisLayoutFormat:TextLayoutFormat = this.getFormatOfRange();
for each(var prop:String in editableLayoutProperties){
thisLayoutFormat[prop] = userTextAreaLayoutFormat[prop];
}
// SCALE THE FONT SIZE
//....................
thisLayoutFormat.fontSize = thisLayoutFormat.fontSize * scale;
// SET THE FORMAT BACK IN THE TEXT BOX
//...................................
this.setFormatOfRange(thisLayoutFormat);
// REDRAW THE OFFSCREEN
// RETURN THE BITMAP DATA
//.......................
this.validateNow();
return BitmapUtil.getSnapshot(this);
}
}
Then calling the TextAreaRenderer after the text area is changed to get a scaled up bitmap.
// COPY THE DATA INTO THE OFFSCREEN COMPONENT
//............................................
var renderableComponent:IAssetRenderer = view.offScreenTextArea;
return renderableComponent.render(userTextArea, 300);
Thanks to the advice from www.Flextras.com for working through the issue with me.

Resizing Image from a decoded ByteArray

I am trying to display a bytearray as a resized image. The Image is displaying correctly, but the sizing is off. Let me explain.
First I have the image data encoded so I need to decode the image data
// Instantiate decoder
var decoder:Base64Decoder = new Base64Decoder();
// Decode image data
decoded.decode(picture.data);
// Export data as a byteArray
var byteArray:ByteArray = decoder.toByteArray();
// Display image
var img:Image = new Image();
img.load(byteArray);
This works. The image is displayed correctly. However, if I hardcode the image (img) height the resized image is shown correctly, but within a box with the original image's dimensions.
For example, if the original image has a height of 300px and a width of 200px and the img.height property is set to 75; the resized image with height of 75 is shown correctly. But the resized image is shown in the upper left corner of the img container that is still set to a height of 300px and a width of 200px. Why does it do that? And what is the fix?
The best way to illustrate the problem is by placing the image inside a VBox and show the borders of the VBox. From the code block above, if I change the image height and set the image to maintain aspect ratio (which by default is set to true but I add it here for completeness). the problem becomes clear.
// Display image
var img:Image = new Image();
img.height = 75; // Hardcode image height (thumbnail)
img.maintainAspectRatio = true;
img.load(byteArray);
// Encapsulate the image inside a VBox to illustrate the problem
var vb:VBox = new VBox();
vb.setStyle('borderStyle', 'solid');
vb.setStyle('borderColor', 'red');
vb.setStyle('borderThickness', 2);
vb.addChild(img);
I have been working on this problem for days and cannot come up with a solution. Any ideas? What am I missing?
The workaround I used is as follows:
I created an event listener for the img display object. Then after the img has loaded, I manually set the height and width of the image. I know what I want the height (preHeight) to be so that is hardcoded. I then calculate the width and set that as the image width. For some reason I had to use the explicitHeight and explicitWidth properties to finally get the sizing right.
I hope this helps someone.
img.addEventListener(FlexEvent.CREATION_COMPLETE, onCreationComplete);
private function onCreationComplete(event:FlexEvent) : void
{
img.addEventListener(Event.COMPLETE, onImageLoadComplete);
}
private function onImageLoadComplete(event:Event) : void
{
var image:Image = event.currentTarget as Image;
var preHeight:Number = 0;
var h:uint = Bitmap(image.content).bitmapData.height;
var w:uint = Bitmap(image.content).bitmapData.width;
// Check height
preHeight = h > 170 ? 170 : h;
// Set the width
img.explicitWidth = (preHeight * w)/h;
img.explicitHeight = preHeight;
}

Resources