locked
Help with proper code on printing bitmap pages

    Question

  • Right now, I have some code that takes a snapshot of a grid and put them as bitmaps in a folder. Then I have some code that reads the bitmaps from that folder and prints it out. How do I change the code so that I can transfer the bitmap directly from the first set of code over to the second set of code?

    Here is the code that reads the pictures from the folder and then prints them out.

    int aa;
            string printingname;
            List<ImageData> _imageData;
    
            Windows.Graphics.Printing.PrintOrientation orientation;
    
            public PrintingPage()
            {
                aa = App.numberofgrids;
                printingname = App.printingname;
                
                //TimeSpan period = TimeSpan.FromMilliseconds(1000);
                
                this.InitializeComponent();
    
                this._itemsPerPage = 1;
    
                OnLoaded();
    
                OnRegister();
    
                orientation = App.orientation;
    
                
    
                InvokePrintButtonClick();
                initialize();
                SV2_Loaded();
                
            }
    
    
            public void SV2_Loaded()
            {
                TimeSpan period = TimeSpan.FromMilliseconds(1000);
    
                Windows.System.Threading.ThreadPoolTimer.CreateTimer(async (source) =>
                {
                    await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
                    {
                        page.ChangeView(0, 0, .3f);
                    });
                }
                , period);
            }
    
    
    
    
            private async void InvokePrintButtonClick()
            {
                try
                {
                    await Windows.Graphics.Printing.PrintManager.ShowPrintUIAsync();
                }
    
                catch
                {
                    return;
                }
            }
    
            public async void initialize()
            {
                
                try
                {
                    
    
                    int ii = 0;
                    while (ii < aa)
                    {
    
    
                        var assetsFolder = ApplicationData.Current.LocalFolder;
                        StorageFile myImage = await assetsFolder.GetFileAsync(printingname + ii + ".bmp");
    
                        if (myImage != null)
                        {
    
                            Windows.Storage.Streams.IRandomAccessStream fileStream = await myImage.OpenAsync(Windows.Storage.FileAccessMode.Read);
    
                            Windows.UI.Xaml.Media.Imaging.BitmapImage bitmapImage = new Windows.UI.Xaml.Media.Imaging.BitmapImage();
    
                            bitmapImage.SetSource(fileStream);
    
                            Image displayImage = new Image();
    
                            displayImage.Source = bitmapImage;
                            printingstackpanel.Children.Add(displayImage);
                        }
    
    
                        ii++;
                    }
                }
    
                catch { return; }
            }
    
    
    
            public void OnLoaded()
            {
    
                
                StorageFolder testfolder = ApplicationData.Current.LocalFolder;
                      
                
                this._imageData = Enumerable.Range(0, aa).Select(
                  i => new ImageData()
                  {
                      Title = string.Format(""),
                      ImageUri = string.Format("ms-appdata:///local/" + printingname + "{0}.bmp", i)
                  }
                ).ToList();
    
    
            }
            public void OnRegister()
            {
                // Note, this manager can also invoke the print UI for us.
                PrintManager manager = PrintManager.GetForCurrentView();
    
                manager.PrintTaskRequested += OnPrintTaskRequested;
    
            }
            void OnPrintTaskRequested(PrintManager sender, PrintTaskRequestedEventArgs args)
            {
                // If I need to be asynchronous, I can get a deferral. I don't *need*
                // to do this here, I'm just faking it.
                var deferral = args.Request.GetDeferral();
    
    
                PrintTask printTask = args.Request.CreatePrintTask(
                  "My Print Job",
                  OnPrintTaskSourceRequestedHandler);
    
                printTask.Options.Orientation = orientation;
    
                printTask.Completed += OnPrintTaskCompleted;
    
                this.AddCustomPrintOption(printTask);
    
                deferral.Complete();
            }
            void AddCustomPrintOption(PrintTask printTask)
            {
                /*PrintTaskOptionDetails details = PrintTaskOptionDetails.GetFromPrintTaskOptions(
                  printTask.Options);
    
                // Clear, string "optionId" needs to be in a constant etc.
                PrintCustomItemListOptionDetails formatOptions =
                details.CreateItemListOption("optionId", "Images Per Page");
    
                var options = new string[] { "1", "2", "4" };
    
                foreach (var item in options)
                {
                    formatOptions.AddItem(item, item);
                }*/
    
                PrintTaskOptionDetails details = PrintTaskOptionDetails.GetFromPrintTaskOptions(printTask.Options);
    
                PrintCustomItemListOptionDetails pageFormat = details.CreateItemListOption("PageRange", "Page Range");
                // Create a new list option
                pageFormat.AddItem("PrintAll", "Print all");
                //pageFormat.AddItem("PrintSelection", "Print Selection");
                //pageFormat.AddItem("PrintRange", "Print Range");
    
                /*details.DisplayedOptions.Add("optionId");
    
                details.OptionChanged += OnItemsPerPageChanged;*/
    
                details.DisplayedOptions.Clear();
    
                details.DisplayedOptions.Add(Windows.Graphics.Printing.StandardPrintTaskOptions.Copies);
                details.DisplayedOptions.Add(Windows.Graphics.Printing.StandardPrintTaskOptions.Orientation);
                details.DisplayedOptions.Add(Windows.Graphics.Printing.StandardPrintTaskOptions.ColorMode);
    
                // Add the custom option to the option list
                details.DisplayedOptions.Add("PageRange");
    
                // Create new edit option
                PrintCustomTextOptionDetails pageRangeEdit = details.CreateTextOption("PageRangeEdit", "Range");
    
                // Register the handler for the option change event
                details.OptionChanged += printDetailedOptions_OptionChanged;
            }
    
            private bool selectionMode;
            private bool pageRangeEditVisible = false;
            private int totalPages;
            async void printDetailedOptions_OptionChanged(PrintTaskOptionDetails sender, PrintTaskOptionChangedEventArgs args)
            {
                if (args.OptionId == null)
                    return;
    
                string optionId = args.OptionId.ToString();
    
                // Handle change in Page Range Option
    
                if (optionId == "PageRange")
                {
                    IPrintOptionDetails pageRange = sender.Options[optionId];
                    string pageRangeValue = pageRange.Value.ToString();
    
                    selectionMode = false;
    
                    switch (pageRangeValue)
                    {
                        case "PrintRange":
                            // Add PageRangeEdit custom option to the option list
                            sender.DisplayedOptions.Add("PageRangeEdit");
                            pageRangeEditVisible = true;
                            await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
                                                      () =>
                                                      {
                                                          //ShowContent(null);
                                                      });
                            break;
                        case "PrintSelection":
                            {
                                await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
                                                  () =>
                                                  {
                                                      //ScenarioOutput5 outputContent = (ScenarioOutput5)rootPage.OutputFrame.Content;
                                                      //ShowContent(outputContent.SelectedText);
                                                  });
                                //RemovePageRangeEdit(sender);
                            }
                            break;
                        default:
                            await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
                                                      () =>
                                                      {
                                                          //ShowContent(null);
                                                      });
                            //RemovePageRangeEdit(sender);
                            break;
                    }
    
                    //Refresh();
    
                }
                else if (optionId == "PageRangeEdit")
                {
                    IPrintOptionDetails pageRange = sender.Options[optionId];
                    // Expected range format (p1,p2...)*, (p3-p9)* ...
                    if (!Regex.IsMatch(pageRange.Value.ToString(), @"^\s*\d+\s*(\-\s*\d+\s*)?(\,\s*\d+\s*(\-\s*\d+\s*)?)*$"))
                    {
                        pageRange.ErrorText = "Invalid Page Range (eg: 1-3, 5)";
                    }
                    else
                    {
                        pageRange.ErrorText = string.Empty;
                        try
                        {
                            //GetPagesInRange(pageRange.Value.ToString());
                            //Refresh();
                        }
                        catch 
                        {
                            //pageRange.ErrorText = ipex.Message;
                        }
                    }
                }
            }
    
            
    
            
            void OnPrintTaskCompleted(PrintTask sender, PrintTaskCompletedEventArgs args)
            {
                this._itemsPerPage = 1;
                this._pageCount = 0;
                this._pageSize = null;
                this._imageableRect = null;
                this._document = null;
            }
            async void OnPrintTaskSourceRequestedHandler(PrintTaskSourceRequestedArgs args)
            {
                var deferral = args.GetDeferral();
    
                await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
                  () =>
                  {
                      this._document = new PrintDocument();
    
                      this._document.Paginate += OnPaginate;
                      this._document.GetPreviewPage += OnGetPreviewPage;
                      this._document.AddPages += OnAddPages;
    
                      // Tell the caller about it.
                      args.SetSource(this._document.DocumentSource);
                  }
                );
                deferral.Complete();
            }
            void OnAddPages(object sender, AddPagesEventArgs e)
            {
                // Note: this code does not take notice of any page range specified
                // by the user. It should.
                this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
                  async () =>
                  {
                      for (int i = 1; i <= this._pageCount; i++)
                      {
                          this._document.AddPage(await this.BuildPageAsync(i));
                      }
                      this._document.AddPagesComplete();
                  }
                );
            }
            void OnGetPreviewPage(object sender, GetPreviewPageEventArgs e)
            {
                this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
                  async () =>
                  {
                      // NB: No longer caching these in a dictionary.
                      UIElement page = await this.BuildPageAsync(e.PageNumber);
    
                      this._document.SetPreviewPage(e.PageNumber, page);
                  }
                );
            }
            async Task<UIElement> BuildPageAsync(int pageNumber)
            {
                // Account for pages going 1..N rather than 0..N-1
                int pageIndex = pageNumber - 1;
    
                // TBD: Unsure about DPI here.
                // Changed from a Canvas in the previous code.
                Grid parentGrid = new Grid();
                parentGrid.Width = this._pageSize.Value.Width;
                parentGrid.Height = this._pageSize.Value.Height;
    
                // Make a grid
                Grid grid = new Grid();
                grid.Margin = new Thickness(
                  this._imageableRect.Value.Left,
                  this._imageableRect.Value.Top,
                  this._pageSize.Value.Width - this._imageableRect.Value.Width - this._imageableRect.Value.Left,
                  this._pageSize.Value.Height - this._imageableRect.Value.Height - this._imageableRect.Value.Top);
    
                // How many squares?
                int squareCount = (int)(Math.Sqrt(this._itemsPerPage));
    
                // Make grid rows and cols
                GridLength length = new GridLength(1, GridUnitType.Star);
    
                for (int i = 0; i < squareCount; i++)
                {
                    grid.RowDefinitions.Add(new RowDefinition() { Height = length });
                    grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = length });
                }
    
                // Make items
                int startIndex = this._itemsPerPage * pageIndex;
                int endIndex =
                  Math.Min(startIndex + this._itemsPerPage, this._imageData.Count);
    
                int rowNo = 0;
                int colNo = 0;
                List<Task> imageLoadTasks = new List<Task>();
    
                for (int itemIndex = startIndex; itemIndex < endIndex; itemIndex++)
                {
                    ImageUserControl control = new ImageUserControl();
                    Binding binding = new Binding()
                    {
                        Path = new PropertyPath("ImageUri")
                    };
                    control.SetBinding(ImageUserControl.ImageUriProperty, binding);
                    control.DataContext = this._imageData[itemIndex];
    
                    imageLoadTasks.Add(control.LoadAsync());
    
                    Grid.SetRow(control, rowNo);
                    Grid.SetColumn(control, colNo);
    
                    colNo++;
    
                    if (colNo >= squareCount)
                    {
                        colNo = 0;
                        rowNo++;
                    }
                    grid.Children.Add(control);
                }
    
                // Offset it into the printable area
                Canvas.SetLeft(grid, this._imageableRect.Value.Left);
                Canvas.SetTop(grid, this._imageableRect.Value.Top);
    
                parentGrid.Children.Add(grid);
    
                // Wait for the images to load.
                await Task.WhenAll(imageLoadTasks);
    
                return (parentGrid);
            }
            void OnPaginate(object sender, PaginateEventArgs e)
            {
                this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
                  () =>
                  {
                      this.GetPageSize(e);
    
                      int itemCount = this._imageData.Count;
                      this._pageCount = itemCount / this._itemsPerPage;
    
                      if ((itemCount % this._itemsPerPage) > 0)
                      {
                          this._pageCount++;
                      }
                      this._document.SetPreviewPageCount(this._pageCount,
                        PreviewPageCountType.Final);
                  }
                );
            }
            void GetPageSize(PaginateEventArgs e)
            {
                if (this._pageSize == null)
                {
                    PrintPageDescription description = e.PrintTaskOptions.GetPageDescription(
                      (uint)e.CurrentPreviewPageNumber);
    
                    this._pageSize = description.PageSize;
                    this._imageableRect = description.ImageableRect;
                }
            }
            int _itemsPerPage;
            int _pageCount;
            Size? _pageSize;
            Rect? _imageableRect;
            PrintDocument _document;
    
            private async void button(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e)
            {
                if (sender == printbutton)
                {
                    await Windows.Graphics.Printing.PrintManager.ShowPrintUIAsync();
                }
    
                else if (sender == closebutton)
                {
                    CoreWindow.GetForCurrentThread().Close();
                }
            }

    Wednesday, April 9, 2014 11:11 PM

Answers

  • UIElement is the base class for all displayed objects. Pages, grids, buttons, listviews, etc. Instead of saving to file, you take the UIElement (you can add the Page itself) that contains what you want to print and add it to the print document.  Then you print that instead of a file.

     async void OnPrintTaskSourceRequestedHandler(PrintTaskSourceRequestedArgs args)
            {
                
                await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
                {
                    MyPrintDocument = new PrintDocument();
                    MyPrintDocument.GetPreviewPage += MyPrintDocument_GetPreviewPage;
                    MyPrintDocument.AddPage(this);
                    MyPrintDocument.AddPagesComplete();
                    args.SetSource(MyPrintDocument.DocumentSource);
                });
            }

     MyPrintDocument.AddPage(this); <-- Refers to the content of the current displayed XAML page.  Instead of that, you could create in-memory grids, images, and other UIelements and just send the topmost parent to the to AddPage(UIElement) method, which would then be an entire page of just XAML content.


    Matt Small - Microsoft Escalation Engineer - Forum Moderator
    If my reply answers your question, please mark this post as answered.

    NOTE: If I ask for code, please provide something that I can drop directly into a project and run (including XAML), or an actual application project. I'm trying to help a lot of people, so I don't have time to figure out weird snippets with undefined objects and unknown namespaces.

    Friday, April 11, 2014 2:56 PM
    Moderator

All replies

  • According to the documentation, you can add a UIElement directly to the print document.  It seems this would be the way to go for you.  Is there a reason you're not already using this?

    Matt Small - Microsoft Escalation Engineer - Forum Moderator
    If my reply answers your question, please mark this post as answered.

    NOTE: If I ask for code, please provide something that I can drop directly into a project and run (including XAML), or an actual application project. I'm trying to help a lot of people, so I don't have time to figure out weird snippets with undefined objects and unknown namespaces.

    Thursday, April 10, 2014 12:45 PM
    Moderator
  • Can you please explain more?  What is UIElement?  Is it the bitmap of a grid?  If I can add the bitmap of a grid directly to print, is there a sample or how would I do this?  And please don't point to the printing sample from the MS website.  It doesn't do what I'm trying to accomplish.

    What I'm trying to accomplish is this.  I have bitmaps of grids.  I want to give the user the option to print what they see on the screen.  Right now, I'm accomplishing this by saving the bitmaps as bmp files in a folder, and then the app reads those bmp files via the code above and prints it out.  If there's a simpler way, please explain it to me.

    Thursday, April 10, 2014 7:43 PM
  • UIElement is the base class for all displayed objects. Pages, grids, buttons, listviews, etc. Instead of saving to file, you take the UIElement (you can add the Page itself) that contains what you want to print and add it to the print document.  Then you print that instead of a file.

     async void OnPrintTaskSourceRequestedHandler(PrintTaskSourceRequestedArgs args)
            {
                
                await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
                {
                    MyPrintDocument = new PrintDocument();
                    MyPrintDocument.GetPreviewPage += MyPrintDocument_GetPreviewPage;
                    MyPrintDocument.AddPage(this);
                    MyPrintDocument.AddPagesComplete();
                    args.SetSource(MyPrintDocument.DocumentSource);
                });
            }

     MyPrintDocument.AddPage(this); <-- Refers to the content of the current displayed XAML page.  Instead of that, you could create in-memory grids, images, and other UIelements and just send the topmost parent to the to AddPage(UIElement) method, which would then be an entire page of just XAML content.


    Matt Small - Microsoft Escalation Engineer - Forum Moderator
    If my reply answers your question, please mark this post as answered.

    NOTE: If I ask for code, please provide something that I can drop directly into a project and run (including XAML), or an actual application project. I'm trying to help a lot of people, so I don't have time to figure out weird snippets with undefined objects and unknown namespaces.

    Friday, April 11, 2014 2:56 PM
    Moderator
  • Before I ask my question, let me give you a thousand apologies. I know programmers/developers here are fed up with newbies like myself asking what you consider as very basic questions. I'm really sorry. I really am. I'm a structure engineer. And so is the other guy that works on an LOB app with me. Together, we have spent many many hours researching on our own and trying all kinds of different things.

    We have an app that allows our engineers to crank out calculations and reports on-the-go with a tablet.  The data syncs with other windows 8.1 devices like the laptops and such, so when our engineers get back to the office they can simply continue working on their laptops or desktops.  Here's the thing.   The reports that we print out have to look exactly like the approved format in the industry.  There is no other way around it.  We can make the "pages" on the screen look exactly like the forms that have been federally approved.  That's the easy part.

    For printing these reports and calculations, we have been using a sort of a hack.  What do I mean?  Well, the app would create a bitmap of the grids, save them as images in a pre-designated folder, and then read these images and print them out as pages.

    But how else can we print out the reports and calculations that would look exactly like how the standards look? 

    Having said that, before when we posted this question, professional devs and programmers like yourselves would give us very cryptic answers in programmer's lingo.  I work 60+ hours a week and so does the other guy.  We're not students.  We can't spend dozens of hours scavenger hunting based on the clues that you guys give.

    And no, the print sample doesn't help.  Again, we have spent dozens of hours with it. 

    Simply put, how do we simply print a grid as it appears?  Not print screen, because printscreen only shows what's on the screen.  I'm talking about a grid.

    Many thanks.


    Tuesday, April 29, 2014 12:32 AM
  • Please don't post multiple threads on the same question. That just loses context and makes it harder to provide a useful answer. If you aren't getting the answer you need then please clarify the question in the original thread. If the answer doesn't make sense then explain in what way it doesn't. Saying the sample doesn't help without explaining how it doesn't help isn't useful. If you've spend dozens of hours on it then show your work: what have you already tried and in what way did it fail?

    We can't read your mind and if you aren't clear on what you need and where you are confused then we cannot help.

    I'll merge this back to your previous thread for you.

    --Rob


    Tuesday, April 29, 2014 12:53 AM
    Owner
  • The sample shows how to print pictures. Is there a direct way to print a grid without turning it into a bitmap?
    Tuesday, April 29, 2014 1:26 AM
  • So here's a bunch of controls in XAML:

      <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
            <StackPanel>
                <Grid Background="Red" Width="300" Height="200" HorizontalAlignment="Left">
                    <TextBlock>This is a textblock inside a red grid control</TextBlock>
                </Grid>
                <Button Content="Hello this is a Button"/>
                <Image Source="kitten.jpg" Width="200" HorizontalAlignment="Left"/>
            </StackPanel>
        </Grid>


    This is what is looks like when it runs:

    When I add this code to your project:

    async void OnPrintTaskSourceRequestedHandler(PrintTaskSourceRequestedArgs args)
            {
                
                await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
                {
                    MyPrintDocument = new PrintDocument();
                    MyPrintDocument.GetPreviewPage += MyPrintDocument_GetPreviewPage;
                    MyPrintDocument.AddPage(this);
                    MyPrintDocument.AddPagesComplete();
                    args.SetSource(MyPrintDocument.DocumentSource);
                });
            }

    This line of code:
    MyPrintDocument.AddPage(this);

    Converts the content of the page into a printable page and places it into the print job. "this" refers to the page itself.  If you have just a grid that you want to add to a page, do this:

    MyPrintDocument.AddPage(<nameofgrid>);

    At this point, I can see it in the Print Preview:


    At this point, I have rendered the content of the screen, including a grid with text, a button, and an image, to a printable page in the print job. 

    I think this is what you're looking for.  Is there anything else that you need on this issue?


    Matt Small - Microsoft Escalation Engineer - Forum Moderator
    If my reply answers your question, please mark this post as answered.

    NOTE: If I ask for code, please provide something that I can drop directly into a project and run (including XAML), or an actual application project. I'm trying to help a lot of people, so I don't have time to figure out weird snippets with undefined objects and unknown namespaces.

    Friday, May 2, 2014 5:07 PM
    Moderator