2

I'm struggling getting images to appear in a FlowDocument that is printed to PDF, to XPS or to a printer.

I've studied this question, Missing images in FlowDocument saved as XPS document, but find the answer unsatisfying.

Here is my code...

        PrintDialog pd = new PrintDialog();
        if(pd.ShowDialog() == true)
        {
            FlowDocument fd = new FlowDocument();
            fd.Blocks.Add(new Paragraph(new Run("Line 1")));
            Uri uri = new Uri("Images/globe.png", UriKind.Relative);
//              Uri uri = new Uri(@"C:\...\Images\globe.png", UriKind.Absolute);
//              Uri uri = new Uri("pack://application:,,,/Images/globe.png", UriKind.Relative);
            BitmapImage bi = new BitmapImage(uri);
            Image i = new Image();
            i.Height = 20;
            i.Width = 20;
            i.Source = bi;
//                Image i = this.Resources["globeImage"] as Image;
            fd.Blocks.Add(new BlockUIContainer(i));
            fd.Blocks.Add(new Paragraph(new Run("Line 2")));
            pd.PrintDocument((fd as IDocumentPaginatorSource).DocumentPaginator, "A print document");
        }

Also, I have defined this resource...

    <Image x:Key="globeImage" Source="Images/globe.png" Height="20" Width="20"/>

So, the code as shown will not work. The place were the image should be in the printed document is blank.

Here is where it gets interesting...

If I use the absolute uri, the image will appear. If I use the image defined in the windows resource, the image will appear. If I use the relative uri with pack uri notation, I get an exception: "image not found", event though this formulation will work fine in the XAML.

So what is going on here? According to the question I referenced, the problem is that the image is not loaded until shown on the screen. If this is true, then why does the absolute URI path work? What is different about the way image sources work in XAML as opposed to programmatically.

Community
  • 1
  • 1
AQuirky
  • 4,691
  • 2
  • 32
  • 51
  • Did you try using: new Uri("pack://application:,,,/Images/globe.png", UriKind.Absolute); ?....the Relative doesn't seem right. – Colin Smith Apr 17 '17 at 03:29

2 Answers2

1

For the below form, the application is looking for the image in an "Images" folder relative to the current directory, which does not exist. (The current directory is the folder where the exe resides if you launched the application by double clicking the exe)

new Uri("Images/globe.png", UriKind.Relative);

For the Pack URI form

pack://application:,,,/Images/globe.png

this is absolute, not relative. Please refer to this.

kennyzx
  • 12,845
  • 6
  • 39
  • 83
1

As you were able to reference your image via your ResourceDirectonary that suggests your image is able to be located.

Will make the assumption that you used the BuildAction="Resource" to add your image to your project.

Looking at this particular line, I think you have used UriKind.Relative by mistake instead of UriKind.Absolute.

In fact, it's usually unnecessary to use that second UriKind parameter, as if your Uri string is of the "pack://" variety, then whether it is relative or absolute is encoded in the locator...or if your string has a "/" prefix this will imply "absolute" while anything else will typically be relative....you can be more obvious if you want by using "./", "../", etc.

(unless you tell it to interpret otherwise, which is what you seem to have done...which is why it's not working).

//              Uri uri = new Uri("pack://application:,,,/Images/globe.png", UriKind.Relative);

As a helper on using "pack://" uris to reference an image...I've come up with a matrix to show some of the different combinations in case you've hit one of the gotchas.

This shows some different combinations of referring to an image "resource" depending on how you provide that resource to your application and how you reference it (it's not all of the options).

4 images, were created, and added as: image1.bmp, image2.bmp, image3.bmp, image4.bmp, as files directly under the "Project" node. Build actions are set to 4 different values.

Then some of the different ways of referencing the "images" are explored.

enter image description here

<Window x:Class="WpfApplication4.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="600" Width="1200">
    <Window.Resources>
        <Style TargetType="{x:Type TextBlock}">
            <Setter Property="Margin" Value="4"/>
            <Setter Property="FontSize"  Value="14"/>
        </Style>
        <BitmapImage x:Key="bitmap1" UriSource="Image1.bmp"/>
        <BitmapImage x:Key="bitmap2" UriSource="Image2.bmp"/>
        <BitmapImage x:Key="bitmap3" UriSource="Image3.bmp"/>
        <BitmapImage x:Key="bitmap4" UriSource="Image4.bmp"/>
        <Image x:Key="image1" Source="Image1.bmp"/>
        <Image x:Key="image2" Source="Image2.bmp"/>
        <Image x:Key="image3" Source="Image3.bmp"/>
        <Image x:Key="image4" Source="Image4.bmp"/>
    </Window.Resources>
    <Grid ShowGridLines="True">
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <TextBlock Background="LightYellow"  Grid.Column="0" Grid.Row="1">BuildAction=<LineBreak/>"Resource"</TextBlock>
        <TextBlock Background="LightYellow" Grid.Column="0" Grid.Row="2">BuildAction=<LineBreak/>"Embedded Resource"</TextBlock>
        <TextBlock Background="LightYellow" Grid.Column="0" Grid.Row="3">BuildAction=<LineBreak/>"Content"</TextBlock>
        <TextBlock Background="LightYellow" Grid.Column="0" Grid.Row="4">BuildAction=<LineBreak/>"Content (copied to output)"</TextBlock>
        <TextBlock Background="PeachPuff"  Grid.Column="1" Grid.Row="0">pack://application:,,,/</TextBlock>
        <TextBlock Background="PeachPuff" Grid.Column="2" Grid.Row="0">pack://application:,,,/WpfApplication4;component/</TextBlock>
        <TextBlock Background="PeachPuff" Grid.Column="3" Grid.Row="0">pack://siteoforigin:,,,/</TextBlock>
        <TextBlock Background="PeachPuff" Grid.Column="4" Grid.Row="0">Image<LineBreak/>referencing BitmapImage<LineBreak/>via {StaticResource}<LineBreak/>referencing "Resource"</TextBlock>
        <TextBlock Background="PeachPuff" Grid.Column="5" Grid.Row="0">ContentPresenter<LineBreak/>referencing Image<LineBreak/>via {StaticResource}<LineBreak/>referencing "Resource"</TextBlock>
        <Image Grid.Column="1" Grid.Row="1" Source="pack://application:,,,/Image1.bmp"/>
        <Image Grid.Column="1" Grid.Row="2" Source="pack://application:,,,/Image2.bmp"/>
        <Image Grid.Column="1" Grid.Row="3" Source="pack://application:,,,/Image3.bmp"/>
        <Image Grid.Column="1" Grid.Row="4" Source="pack://application:,,,/Image4.bmp"/>
        <Image Grid.Column="2" Grid.Row="1" Source="pack://application:,,,/WpfApplication4;component/Image1.bmp"/>
        <Image Grid.Column="2" Grid.Row="2" Source="pack://application:,,,/WpfApplication4;component/Image2.bmp"/>
        <Image Grid.Column="2" Grid.Row="3" Source="pack://application:,,,/WpfApplication4;component/Image3.bmp"/>
        <Image Grid.Column="2" Grid.Row="4" Source="pack://application:,,,/WpfApplication4;component/Image4.bmp"/>
        <Image Grid.Column="3" Grid.Row="1" Source="pack://siteoforigin:,,,/Image1.bmp"/>
        <Image Grid.Column="3" Grid.Row="2" Source="pack://siteoforigin:,,,/Image2.bmp"/>
        <Image Grid.Column="3" Grid.Row="3" Source="pack://siteoforigin:,,,/Image3.bmp"/>
        <Image Grid.Column="3" Grid.Row="4" Source="pack://siteoforigin:,,,/Image4.bmp"/>
        <Image Grid.Column="4" Grid.Row="1" Source="{StaticResource bitmap1}"/>
        <Image Grid.Column="4" Grid.Row="2" Source="{StaticResource bitmap2}"/>
        <Image Grid.Column="4" Grid.Row="3" Source="{StaticResource bitmap3}"/>
        <Image Grid.Column="4" Grid.Row="4" Source="{StaticResource bitmap4}"/>
        <ContentPresenter Grid.Column="5" Grid.Row="1" Content="{StaticResource image1}"/>
        <ContentPresenter Grid.Column="5" Grid.Row="2" Content="{StaticResource image2}"/>
        <ContentPresenter Grid.Column="5" Grid.Row="3" Content="{StaticResource image3}"/>
        <ContentPresenter Grid.Column="5" Grid.Row="4" Content="{StaticResource image4}"/>
    </Grid>
</Window>
Colin Smith
  • 12,375
  • 4
  • 39
  • 47
  • This answer helped me, though for me worked only use of **pack://application:,,,/**. I'm adding Image to Flowdocument dynamically. And I'm stil not quite sure why other methods doesn't work for me. – LuckyLuke82 Mar 04 '20 at 08:52