gpt4 book ai didi

c# - XPS 文件中打印的重复图像

转载 作者:太空狗 更新时间:2023-10-29 21:49:46 29 4
gpt4 key购买 nike

首先,我想指出,我已将此问题作为一个错误提交给 Microsoft,但他们此时不愿修复它。我正在寻找一种解决方法或更好的方法来实现我正在尝试做的事情,因为我们的客户认为这是一个相当重要的问题。

代码

MainWindow.xaml

<Grid x:Name="mainGrid">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ListBox ItemsSource="{Binding Images}">
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

<Button Content="Print to file" Grid.Row="1" Click="PrintToFile_Click"/>
<Button Content="Print to device" Grid.Row="2" Click="PrintToDevice_Click"/>
</Grid>

MainWindow.xaml.cs

public partial class MainWindow : Window
{
public IList<byte[]> Images { get; set; }

public MainWindow()
{
InitializeComponent();

Assembly currentAssembly = Assembly.GetExecutingAssembly();

this.Images = new List<byte[]>
{
ReadToEnd(currentAssembly.GetManifestResourceStream("PrintingInvestigation.Images.Chrysanthemum.jpg")),
ReadToEnd(currentAssembly.GetManifestResourceStream("PrintingInvestigation.Images.Desert.jpg")),
ReadToEnd(currentAssembly.GetManifestResourceStream("PrintingInvestigation.Images.Hydrangeas.jpg")),
};

this.DataContext = this;
}

public static byte[] ReadToEnd(System.IO.Stream stream)
{
long originalPosition = 0;

if (stream.CanSeek)
{
originalPosition = stream.Position;
stream.Position = 0;
}

try
{
byte[] readBuffer = new byte[4096];

int totalBytesRead = 0;
int bytesRead;

while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0)
{
totalBytesRead += bytesRead;

if (totalBytesRead == readBuffer.Length)
{
int nextByte = stream.ReadByte();
if (nextByte != -1)
{
byte[] temp = new byte[readBuffer.Length * 2];
Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length);
Buffer.SetByte(temp, totalBytesRead, (byte)nextByte);
readBuffer = temp;
totalBytesRead++;
}
}
}

byte[] buffer = readBuffer;
if (readBuffer.Length != totalBytesRead)
{
buffer = new byte[totalBytesRead];
Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead);
}
return buffer;
}
finally
{
if (stream.CanSeek)
{
stream.Position = originalPosition;
}
}
}

private void PrintToDevice_Click(object sender, RoutedEventArgs e)
{
PrintDialog dialog = new PrintDialog();
if (dialog.ShowDialog() == true)
{
Thickness pageMargins;

if (dialog.PrintTicket.PageBorderless.HasValue == true)
{
if (dialog.PrintTicket.PageBorderless.Value == PageBorderless.Borderless)
{
pageMargins = new Thickness(0, 0, 0, 0);
}
else
{
pageMargins = new Thickness(20, 20, 20, 20);
}
}
else
{
pageMargins = new Thickness(20, 20, 20, 20);
}

int dpiX = 300;
int dpiY = 300;
if (dialog.PrintTicket.PageResolution != null &&
dialog.PrintTicket.PageResolution.X.HasValue &&
dialog.PrintTicket.PageResolution.Y.HasValue)
{
dpiX = dialog.PrintTicket.PageResolution.X.Value;
dpiY = dialog.PrintTicket.PageResolution.Y.Value;
}
else
{
dialog.PrintTicket.PageResolution = new PageResolution(dpiX, dpiY);
}

VisualDocumentPaginator paginator = new VisualDocumentPaginator(this.mainGrid, this.mainGrid.ActualWidth);
paginator.PageSize = new Size(dialog.PrintableAreaWidth, dialog.PrintableAreaHeight);

dialog.PrintDocument(paginator, "My first print");
GC.Collect();
}
}

private void PrintToFile_Click(object sender, RoutedEventArgs e)
{
string filePath = this.PrintToFile(null, this.mainGrid, "My first print", this.mainGrid.ActualHeight, this.mainGrid.ActualWidth);

Process.Start(filePath);
}

public string PrintToFile(Visual titleVisual, Visual contentVisual, string title, double bottomMost, double rightMost)
{
string printedFilePath = System.IO.Path.Combine(System.IO.Path.GetTempPath(), string.Format(CultureInfo.InvariantCulture, "{0}.xps", title));

XpsDocument printedDocument = new XpsDocument(printedFilePath, FileAccess.Write, System.IO.Packaging.CompressionOption.SuperFast);

VisualDocumentPaginator paginator = new VisualDocumentPaginator(contentVisual as FrameworkElement, rightMost);
paginator.PageSize = new Size(793.7, 1122.5);

XpsDocumentWriter writer = XpsDocument.CreateXpsDocumentWriter(printedDocument);
writer.Write(paginator, new PrintTicket
{
Collation = Collation.Collated,
CopyCount = 1,
DeviceFontSubstitution = DeviceFontSubstitution.On,
Duplexing = Duplexing.OneSided,
InputBin = InputBin.AutoSelect,
OutputColor = OutputColor.Color,
OutputQuality = OutputQuality.High,
PageMediaSize = new PageMediaSize(PageMediaSizeName.ISOA4),
PageOrientation = PageOrientation.Portrait,
PageResolution = new PageResolution(PageQualitativeResolution.High),
PagesPerSheet = 1,
TrueTypeFontMode = TrueTypeFontMode.Automatic
});

printedDocument.Close();

return printedFilePath;
}
}

VisualDocumentPaginator.cs

public class VisualDocumentPaginator : DocumentPaginator
{
#region Fields

private double desiredWidth;
private FrameworkElement element;

#endregion

#region Properties

public int Columns
{
get
{
return 1;// (int)Math.Ceiling(Element.ActualWidth / PageSize.Width);
}
}

public int Rows
{
get
{
return (int)Math.Ceiling(element.ActualHeight / PageSize.Height);
}
}

#endregion

#region Constructors

public VisualDocumentPaginator(FrameworkElement element, double desiredWidth)
{
this.desiredWidth = desiredWidth;
this.element = element;
}

#endregion

#region DocumentPaginator Members

public override DocumentPage GetPage(int pageNumber)
{
TransformGroup transforms = new TransformGroup();

double scaleRatio = this.PageSize.Width / this.desiredWidth;
int row = (pageNumber / Columns);

double pageHeight = -PageSize.Height * row / scaleRatio;
double pageWidth = -PageSize.Width * (pageNumber % Columns);

transforms.Children.Add(new TranslateTransform(pageWidth, pageHeight));

// Make sure the control is stretched to fit the page size.
if (scaleRatio != double.NaN)
{
ScaleTransform st = new ScaleTransform(scaleRatio, scaleRatio);
transforms.Children.Add(st);
}

element.RenderTransform = transforms;

Size elementSize = new Size(this.desiredWidth, element.ActualHeight);
element.Measure(elementSize);
element.Arrange(new Rect(new Point(0, 0), elementSize));

var page = new DocumentPage(element, this.PageSize, new Rect(), new Rect());
element.RenderTransform = null;

return page;
}

public override bool IsPageCountValid
{
get { return true; }
}

public override int PageCount
{
get
{
return Columns * Rows;
}
}

public override Size PageSize { set; get; }

public override IDocumentPaginatorSource Source
{
get { return null; }
}

#endregion
}

很抱歉发布了所有代码,但它涵盖了我遇到问题的所有领域。如果有帮助,这里是 Microsoft bug report其中附有一个示例项目,可以在其中重现问题。

问题
只有在写入 XPS 文件时才会出现此问题,其中只有第一张图像被打印 3 次,如果单击“打印到设备”按钮,则会打印正确的图像。

我绑定(bind)到 byte[] 的原因是因为我将我的图像保存在本地 SQL CE 数据库中。我们将它们存储在数据库中,因为它们每个只有 2KB 左右,而且我们允许用户将自己的图标导入系统中使用,我们需要一种机制来保证它们不会被意外删除。

注意
我注意到,如果我没有像上面提到的那样绑定(bind)到 byte[],那么我就看不到这个问题。考虑到系统目前不采用将图像存储在数据库中的方法,如果有解决方法,我宁愿坚持使用它,但我并不完全反对更换这些图像的存储机制。

最佳答案

我遇到过类似的问题,第一张图片被复制并替换了所有其他图片。就我而言,打印到设备、XPS 文档或 PDF 文档并不重要,问题仍然存在。

分析

我使用 .NET 程序集反编译器来弄清楚 System.Windows.Xps.XpsDocumentWriter 类如何处理图像,以确定问题是在我的代码中还是在框架的代码中。我发现该框架使用字典将图像等资源导入文档。即使在 XPS 文档中只导入一次图像,文档也可以多次引用它们。

就我而言,我能够确定问题出在 System.Windows.Xps.Serialization.ImageSourceTypeConverter.GetBitmapSourceFromImageTable 方法中。当从 System.Windows.Media.Imaging.BitmapFrame 构建图像时,转换器将使用键在其字典之一中查找资源。在这种情况下,键对应于 BitmapFrame.Decoder.ToString() 方法返回的字符串的哈希码。不幸的是,由于我的图像是从字节数组而不是 URI 构建的,因此解码器的 ToString 方法返回“image”。由于无论图像如何,该字符串始终会生成相同的哈希码,ImageSourceTypeConverter 将认为所有图像都已添加到 XPS 文档中,并将返回要使用的第一个也是唯一一个图像的 Uri .这解释了为什么第一张图像被复制并替换所有其他图像。

尝试

我第一次尝试解决这个问题是覆盖 System.Windows.Media.Imaging.BitmapDecoder.ToString() 方法。为此,我尝试将 BitmapFrameBitmapDecoder 包装到我自己的 BitmapFrameBitmapDecoder 中。不幸的是,BitmapDecoder 类包含一个我无法定义的internal abstract 方法。由于我无法创建自己的 BitmapDecoder,因此我无法实现该解决方法。

解决方法

如前所述,当 BitmapSource 时,System.Windows.Xps.Serialization.ImageSourceTypeConverter.GetBitmapSourceFromImageTable 方法将在字典中查找哈希码>位图框架。当它不是 BitmapFrame 时,它会根据图像二进制数据生成 CRC 值并在另一个字典中查找它。

在我的例子中,我决定将 System.Windows.Media.ImageSourceConverter 从字节数组生成的 BitmapFrame 包装到另一种类型的 BitmapSource 例如 System.Windows.Media.Imaging.CachedBitmap。因为我真的不想要缓存位图,所以我创建了 CachedBitmap 将以下选项:

var imageSource = new CachedBitmap( bitmapFrame, BitmapCreateOptions.None, BitmapCacheOption.None );

有了这些选项,CachedBitmap 主要是一个简单的BitmapSource 包装器。就我而言,此解决方法解决了我的问题。

关于c# - XPS 文件中打印的重复图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30523815/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com