I have a simple wpf desktop application which prints a bitmap in landscape mode.
Under Windows 8/8.1 the printout is clipped on the bottom of the page while under Windows 7 it is printed correctly.
The code is really simple: load a bitmap, put it into an Image object, measure the printable area, arrange the image and print.
void printButton_Click(object sender, RoutedEventArgs e)
{
var pd = new PrintDialog();
if (!pd.ShowDialog().Value)
{
return;
}
pd.PrintTicket.PageOrientation = PageOrientation.Landscape;
pd.PrintTicket.PageBorderless = PageBorderless.None;
var printingCapabilities = pd.PrintQueue.GetPrintCapabilities(pd.PrintTicket);
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.UriSource = new Uri("D:\\printTest.bmp");
bitmapImage.EndInit();
var imageuiElement = new Image { Source = bitmapImage };
var desiredSize = new Size(printingCapabilities.PageImageableArea.ExtentWidth, printingCapabilities.PageImageableArea.ExtentHeight);
imageuiElement.Measure(desiredSize);
imageuiElement.Arrange(new Rect(new Point(printingCapabilities.PageImageableArea.OriginWidth, printingCapabilities.PageImageableArea.OriginHeight), imageuiElement.DesiredSize));
pd.PrintVisual(imageuiElement, "MyImage");
}
The bitmap size is 1518 x 1092 pixels, 96 DPI, which is 40.2 x 28.9 cm.
I have found the question Cannot print a document with landscape orientation under Windows 8 (WPF, .NET 4.0)
but there is no good response for my issue (additionally I have no problem with printing as landscape itself).
I have tested it with different printers of different vendors, the printouts are clipped in all of them. A software CutePDF writer prints it to PDF correctly.
Any help appreciated.
It seems that Windows 8 does not draw ui elements outside of their container bounds. This is why the printout was clipped at the bottom.
Anyway, I ended up with a code like this, which is able to print a centered bitmap on a landscape page:
printDialog.PrintTicket.PageOrientation = PageOrientation.Landscape;
printDialog.PrintTicket.PageBorderless = PageBorderless.None;
var printingCapabilities = printDialog.PrintQueue.GetPrintCapabilities(printDialog.PrintTicket);
if (printingCapabilities.PageImageableArea == null)
{
return;
}
var document = new FixedDocument();
document.DocumentPaginator.PageSize = new Size(printingCapabilities.PageImageableArea.ExtentWidth, printingCapabilities.PageImageableArea.ExtentHeight);
foreach (var imageStream in imageStreams)
{
document.Pages.Add(GeneratePageContent(imageStream, printingCapabilities, printDialog.PrintableAreaWidth, printDialog.PrintableAreaHeight));
}
try
{
printDialog.PrintDocument(document.DocumentPaginator, GlobalConstants.SoftwareName);
}
private PageContent GeneratePageContent(Stream imageStream, PrintCapabilities printingCapabilities, double paperWidth, double paperHeight)
{
imageStream.Seek(0, SeekOrigin.Begin);
var bmp = new BitmapImage();
bmp.BeginInit();
bmp.StreamSource = imageStream;
bmp.EndInit();
var margin = new Thickness();
var pageSize = new Size();
if (printingCapabilities.PageImageableArea != null)
{
margin = new Thickness(
printingCapabilities.PageImageableArea.OriginWidth,
printingCapabilities.PageImageableArea.OriginHeight,
printingCapabilities.PageImageableArea.OriginWidth,
printingCapabilities.PageImageableArea.OriginHeight);
pageSize = new Size(printingCapabilities.PageImageableArea.ExtentWidth, printingCapabilities.PageImageableArea.ExtentHeight);
}
var imageUiElement = new Image
{
Source = bmp,
Margin = margin
};
var canvas = new Grid { Width = paperWidth, Height = paperHeight };
canvas.Children.Add(imageUiElement);
var fixedPage = new FixedPage
{
Width = paperWidth,
Height = paperHeight
};
fixedPage.Children.Add(canvas);
var pageContent = new PageContent();
((IAddChild)pageContent).AddChild(fixedPage);
pageContent.Measure(pageSize);
pageContent.Arrange(new Rect(new Point(), pageSize));
pageContent.UpdateLayout();
return pageContent;
}
Related
I encountered strange behaviour when loading image from byte array aquired from stream. Most images are correct, I would say 99% of them. But i saw so far two times something like this below. Image in the middle is shown like a set of random pixels, not the real image.
Image can be loaded correctly in other client application (sliverlight) but i can't show that.
In WPF client i have something like that:
Does someone had issue like this? Or any idea what might cause it? Maybe i should look on server side (image is show in other, older client and code to load that is known to me).
Code looks like that:
public async Task<ImageCreatePictureBox> CreatePictureBox(IBaseObj pmIBaseObj, IObj pmObj)
{
var lcContainer = new Grid
{
Width = pmObj.PresObj.Width,
Height = pmObj.PresObj.Height
};
var gridBorder = new Border();
CustomImg imageControl = null;
FrameworkElement lcFrameworkElement = lcContainer;
if (!(pmIBaseObj is ImageBaseObj lcImageBaseObj))
return new ImageCreatePictureBox(null, lcContainer, lcFrameworkElement, pmObj);
if (!lcImageBaseObj.CustomBitMap)
{
try
{
var bitmapImage = BitmapImageHelper.ByteArrayToBitmapSource(lcImageBaseObj.Image, lcImageBaseObj.ImageWidth, lcImageBaseObj.ImageHeight);
imageControl = new CustomImg(pmIBaseObj.Width, pmIBaseObj.Height, pmObj)
{
Source = bitmapImage,
Height = lcImageBaseObj.Height,
Width = lcImageBaseObj.Width
};
}
catch (Exception e)
{
var src = new BitmapImage(new Uri(Helper.GetPathToImage("dummy")));
imageControl = new CustomImg(pmIBaseObj.Width, pmIBaseObj.Height, pmObj)
{
Source = src,
Height = lcImageBaseObj.Height,
Width = lcImageBaseObj.Width
};
Helper.WriteToDebug(e);
}
}
else
{
try
{
var bitmapImage = BitmapImageHelper.ByteArrayToBitmapSource(lcImageBaseObj.Image, lcImageBaseObj.ImageWidth, lcImageBaseObj.ImageHeight);
imageControl = new CustomImg(pmIBaseObj.Width, pmIBaseObj.Height, pmObj)
{
Source = bitmapImage,
Height = lcImageBaseObj.Height,
Width = lcImageBaseObj.Width
};
}
catch (Exception e)
{
if (imageControl == null)
imageControl = new CustomImg(pmIBaseObj.Width, pmIBaseObj.Height, pmObj);
var src = new BitmapImage(new Uri(Helper.GetPathToImage("dummy")));
imageControl = new CustomImg(pmIBaseObj.Width, pmIBaseObj.Height, pmObj)
{
Source = src,
Height = lcImageBaseObj.Height,
Width = lcImageBaseObj.Width
};
Helper.WriteToDebug(e);
}
}
(...)
return new ImageCreatePictureBox(imageControl, lcContainer, lcFrameworkElement, pmObj);
}
public static BitmapSource ByteArrayToBitmapSource(Byte[] BArray, int imgWidth, int imgHeight)
{
try
{
var width = imgWidth;
var height = imgHeight;
var dpiX = 90d;
var dpiY = 90d;
var pixelFormat = PixelFormats.Pbgra32;
var bytesPerPixel = (pixelFormat.BitsPerPixel + 7) / 8;
var stride = bytesPerPixel * width;
var bitmap = BitmapSource.Create(width, height, dpiX, dpiY, pixelFormat, null, BArray, stride);
return bitmap;
}
catch (Exception e)
{
return BytesToBitmapImage(BArray);
}
}
I want to show a lot of images in a form using User Control, but it's very slow and takes a lot of system memory.
How can I load image in Picture Box when User Control shows to user?
I wrote this sample code. It works fine for 700 images, but I am still looking for best solution.
Bitmap myBitmap;
Image myThumbnail;
foreach (var item in queryMatchingFiles)
{
Image.GetThumbnailImageAbort myCallback = new Image.GetThumbnailImageAbort(ThumbnailCallback);
myBitmap = new Bitmap(item);
myThumbnail = myBitmap.GetThumbnailImage(120, 183, myCallback, IntPtr.Zero);
flowLayoutPanel1.Controls.Add(new PictureBox {
Image = myThumbnail,
Width = 120,
Height = 183,
BackgroundImageLayout = ImageLayout.Stretch
});
count++;
myBitmap = null;
myThumbnail = null;
}
public bool ThumbnailCallback()
{
return false;
}
This code will only print one page but the height of the control exceeds the page height and therefore will need to be printed on a second page. I have been doing some investigation as to what will enable the control to proceed onto another page. I got as far as DocumentPaginator and fiddled with the size making it bigger and smaller than the sz variable but no difference. Any Ideas as to what controls a creation of a new page? does the size relate to pagination?
private void Print()
{
var pd = new PrintDialog();
var document = new FixedDocument();
var fixedPage = new FixedPage();
var pageContent = new PageContent();
System.Printing.PrintCapabilities capabilities = pd.PrintQueue.GetPrintCapabilities(pd.PrintTicket);
System.Windows.Size sz = new System.Windows.Size(capabilities.PageImageableArea.ExtentWidth, capabilities.PageImageableArea.ExtentHeight);
MarSheetReport mar = new MarSheetReport();
document.DocumentPaginator.PageSize = sz;
Transform originalScale = fixedPage.LayoutTransform;
//get selected printer capabilities
fixedPage.LayoutTransform = new ScaleTransform(0.2823293807641634 + 0.2498215560314061, 0.2823293807641634 + 0.2498215560314061);
fixedPage.Width = sz.Width;
fixedPage.Height = sz.Height;
// Add visual, measure/arrange page.
fixedPage.Children.Add(mar.o);
fixedPage.Measure(sz);
fixedPage.Arrange(new System.Windows.Rect(new System.Windows.Point(capabilities.PageImageableArea.OriginWidth, capabilities.PageImageableArea.OriginHeight), sz));
fixedPage.UpdateLayout();
//fixedPage.LayoutTransform = originalScale;
((IAddChild)pageContent).AddChild(fixedPage);
document.Pages.Add(pageContent);
pd.PrintDocument(document.DocumentPaginator, "My Document");
}
Here is one way of doing it i.e creating the bitmap from the visual and breaking it on multiple pages.
http://www.codeproject.com/Articles/339416/Printing-large-WPF-UserControls
An image (Image class) is placed above a SMFPlayer (both elements are created in code-behind). Z-index of the image is the Z-Index of SMFPlayer + 1. The image is resized (adjusting the width) according to the playing progress of SMFPlayer.
videoPlayer = new SMFPlayer();
videoPlayer.Width = 1920;
videoPlayer.Height = 1080;
videoPlayer.Margin = new Thickness(1920, 0, 0, 0);
PlaylistItem item = new PlaylistItem();
Random r = new Random();
item.MediaSource = new Uri("video.wmv");
item.DeliveryMethod = DeliveryMethods.ProgressiveDownload;
videoPlayer.Playlist.Add(item);
videoPlayer.AutoPlay = true;
videoPlayer.AutoLoad = true;
videoPlayer.IsControlStripVisible = false;
videoPlayer.PlaylistVisibility = FeatureVisibility.Disabled;
videoPlayer.MediaEnded += new EventHandler(player_MediaEnded);
LayoutRoot.Children.Add(videoPlayer);
bar_yellow3 = new Image();
bar_yellow3.Source = new BitmapImage(new Uri("/SMF_ProgressiveDownload1;component/assets/bar_y.png", UriKind.Relative));
bar_yellow3.Width = 775;
bar_yellow3.Height = 34;
bar_yellow3.Margin = new Thickness(2948,1034,0,0);
bar_yellow3.Stretch = Stretch.Fill;
bar_yellow3.VerticalAlignment = VerticalAlignment.Top;
bar_yellow3.HorizontalAlignment = HorizontalAlignment.Left;
LayoutRoot.Children.Add(bar_yellow3);
However, when the playing progress is less than 20%, the image blinks randomly. When the SMFPlayer is set to be invisible ( Visibility.Collapsed ) , the image is normal.
I have tried to call the update function of the Image, which is: bar_yellow3.UpdateLayout(); but the method does not solve the blinking issue.
Any solution?
Try use effects (Shazzam will help you) instead using Z order.
I would like to generate some images dynamicaly. For that, I intend to create a XAML View, populate it with Data (using DataBinding) and then generate an image from the rendering of that view (kind of a screenshot).
Is there a way to do this in Silverligth or WPF?
In WPF:
public static Image GetImage(Visual target)
{
if (target == null)
{
return null; // No visual - no image.
}
var bounds = VisualTreeHelper.GetDescendantBounds(target);
var bitmapHeight = 0;
var bitmapWidth = 0;
if (bounds != Rect.Empty)
{
bitmapHeight = (int)(Math.Floor(bounds.Height) + 1);
bitmapWidth = (int)(Math.Floor(bounds.Width) + 1);
}
const double dpi = 96.0;
var renderBitmap =
new RenderTargetBitmap(bitmapWidth, bitmapHeight, dpi, dpi, PixelFormats.Pbgra32);
var visual = new DrawingVisual();
using (var context = visual.RenderOpen())
{
var brush = new VisualBrush(target);
context.DrawRectangle(brush, null, new Rect(new Point(), bounds.Size));
}
renderBitmap.Render(visual);
return new Image
{
Source = renderBitmap,
Width = bitmapWidth,
Height = bitmapHeight
};
}
Use the WriteableBitmap and its Render function in Silverlight.
In WPF use this trick by using the RenderTargetBitmap and its Render function
You can add the controls (data after they are databound) that you want to capture to a ViewBox - http://www.wpftutorial.net/ViewBox.html
From there, you can create an image using WriteableBitmap - http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.writeablebitmap%28VS.95%29.aspx