最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C#使用PDFium實現(xiàn)預(yù)覽PDF文件

 更新時間:2025年10月24日 08:32:15   作者:luojin765  
這篇文章主要為大家詳細介紹了C#如何使用PDFium實現(xiàn)預(yù)覽PDF文件,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

本項目對PdfiumViewer庫進行了改寫,對其pdf解析部分的核心功能進行了分離和精簡,使其支持任意程序調(diào)用生成渲染后圖片,項目代碼已全部開源 (https://github.com/LdotJdot/LumPdfiumViewerSlim)。

同時我們還給出了一個用Avalonia簡單實現(xiàn)了渲染頁面的UI,改造后的庫是完全支持如Winform還有后端調(diào)用的。

下文將分享一下這個過程。

一、基于PDFium庫

需求來了,就得想辦法實現(xiàn)誒。要預(yù)覽PDF文件,需要先完成對PDF的解析,即將PDF中各類數(shù)據(jù)提取出來,然后再實現(xiàn)對解析數(shù)據(jù)的繪制渲染到軟件層面。在C#中關(guān)于PDF解析庫有很多,我們優(yōu)先考慮的主要為用C#對PDFium封裝庫。PDFium是基于由google維護的項目 (https://github.com/chromium/pdfium) (Apache-2.0 license),維護很頻繁(本文發(fā)出前2小時Pdfium倉庫還在更新),此外他的特點是采用動態(tài)鏈接庫,C++編譯體積很小5mb,兼容性較好,接口規(guī)范而且功能強大。

二、C#現(xiàn)有Pdf預(yù)覽庫PdfiumViewer的不便

為了不造輪子,我們找到了 PdfiumViewer (https://github.com/bezzad/PdfiumViewer,Apache-2.0 license), 是一個基于Pdfium封裝后實現(xiàn)了預(yù)覽效果的C#庫。

盡管PDFium預(yù)覽效果很好,但最大的問題是,PdfiumViewer中對渲染后頁面的創(chuàng)建深度依賴了WPF框架(true),而且是與解析渲染方法組合在一起的。由于很多內(nèi)部對象大量引用了WPF元素。因此在后端調(diào)用時或用于其他如Winform、Avalonia框架時非常不方便。如果想要單純集成至Winform或后端服務(wù)器調(diào)用那么還必須帶著WPF框架過去,非常不方便,只能自定義對PdfiumViewer進行改造了。

三、Pdf預(yù)覽原理檢視及修改

Pdf的預(yù)覽主要是由解析+渲染兩部分實現(xiàn)。PdfiumViewer中,解析和底層渲染都是基于Pdfium庫的封裝調(diào)用實現(xiàn)的。如:,

[DllImport("pdfium.dll")]
public static extern IntPtr FPDFBitmap_CreateEx(int width, int height, int format, IntPtr first_scan, int stride);

[DllImport("pdfium.dll")]
public static extern void FPDFBitmap_FillRect(IntPtr bitmapHandle, int left, int top, int width, int height, uint color);

[DllImport("pdfium.dll")]
public static extern void FPDF_RenderPageBitmap(IntPtr bitmapHandle, IntPtr page, int start_x, int start_y, int size_x, int size_y, int rotate, FPDF flags);

在PdfiumView封裝的方法中,將額外考慮:

  • 狀態(tài)檢查和DPI校正
  • 位圖對象管理及內(nèi)存鎖定
  • 原生PDF渲染 (Pdfium中渲染準(zhǔn)備)
  • 背景設(shè)置和頁面設(shè)置
  • 實際PDF渲染 (渲染到位圖)

PdfiumView封裝后的方法為:

public Image Render(int page, int width, int height, float dpiX, float dpiY, PdfRotation rotate, PdfRenderFlags flags)

基于這個方法僅需要傳入頁碼(從0開始)、寬度、高度、dpi、旋轉(zhuǎn)等參數(shù),就可以得到PDF文件中指定頁的渲染后圖片了。

四、精簡處理及Avalonia頁面實現(xiàn)

為了更加通用,我們對PdfiumViewer中依賴WPF的代碼進行了刪減,主要包括書簽相關(guān)的對象,滾動面板及動態(tài)渲染等,最后留下的只有指定PDF頁渲染圖片的功能。在大部分場景中已經(jīng)夠用了,而且是支持AOT發(fā)布的,也可以作為一個獨立進程工具供其他程序調(diào)用。

為了測試效果,我們選擇在Avalonia中創(chuàng)建一個可滾動的頁面,創(chuàng)建一個虛擬模式的ItemsControl,基于Image對象用于顯示最終渲染的圖片頁IImage:

<ScrollViewer>
	<ItemsControl  x:Name="pageList"
     IsTabStop="False"
		Focusable="False"
		IsHitTestVisible="True"

		ItemsSource="{Binding RenderedPages.DisplayedData, Mode=OneWay}" Background="Transparent">
		<ItemsControl.ItemsPanel>
			<ItemsPanelTemplate>
				<VirtualizingStackPanel/>
			</ItemsPanelTemplate>
		</ItemsControl.ItemsPanel>
		
		<ItemsControl.ItemTemplate>
			
			<DataTemplate>
				<Image 
					Source="{Binding Image}"
					   Stretch="Uniform"/>
			</DataTemplate>
		</ItemsControl.ItemTemplate>
	</ItemsControl >
</ScrollViewer>

綁定的ViewModel很簡單,主要是為了頁面的延遲渲染,即滾動到哪一頁,就調(diào)用上述組件的方法,實時渲染當(dāng)前頁圖片。

public interface IPageRender
{
    public int page { get; }

    public IImage Image {get;}
}

public class PageRender
{
    PdfDocument _pdfDocument;
    public PageRender(PdfDocument _pdfDocument, int pageNumber)
    {
        this._pdfDocument= _pdfDocument;
        this.page = pageNumber;
    }

    public IImage Image=>GetImage();

   IImage GetImage()
    {
        try
        {
            using var image = _pdfDocument.Render(page, 800, 1200, 192, 192);
                        
            return ConvertToAvaloniaBitmap(image);
        }
        catch
        {
            return null;
        }
    }


    private Avalonia.Media.Imaging.Bitmap ConvertToAvaloniaBitmap(System.Drawing.Image image)
    {
        using (var memoryStream = new MemoryStream())
        {                
            image.Save(memoryStream,ImageFormat.Png);
            memoryStream.Position = 0;
            return new Avalonia.Media.Imaging.Bitmap(memoryStream);
        }
    }

    public int page { get; }
}

public class PageViewModel: ReactiveObject,IDisposable
{
    private PdfDocument _pdfDocument;

    IEnumerable<PageRender> _displayedData=[];

    public IEnumerable<PageRender> DisplayedData
    {
        get => _displayedData;
        private set => this.RaiseAndSetIfChanged(ref _displayedData, value);
    }

    public void Load(string path)
    {
        _pdfDocument?.Dispose();
        _pdfDocument = PdfDocument.Load(path);
        Initialize(_pdfDocument);
    }

    private void Initialize(PdfDocument pdfDocument)
    {
        _pdfDocument = pdfDocument;

        // 頁面范圍
        DisplayedData = Enumerable.Range(0, pdfDocument.PageCount).Select(o=>new PageRender(_pdfDocument, o));

    }

    public void Dispose()
    {            
        _pdfDocument?.Dispose();
    }
}

實現(xiàn)效果如下:

五、最后

盡管AOT啟動速度快,但我們還是更偏向與單文件的壓縮發(fā)布,因為AOT發(fā)布后,加上非托管庫,體積會比較大。而單文件壓縮將非托管后一起打包后大小僅不到26Mb,一個小巧的PDF閱讀器就誕生了,是不是很棒。

到此這篇關(guān)于C#使用PDFium實現(xiàn)預(yù)覽PDF文件的文章就介紹到這了,更多相關(guān)C#預(yù)覽PDF內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論

永登县| 龙泉市| 洛浦县| 鹤峰县| 长子县| 威远县| 章丘市| 宁城县| 永寿县| 乌什县| 永善县| 大连市| 阳曲县| 乌兰浩特市| 荔浦县| 东山县| 山阴县| 卓尼县| 清新县| 太谷县| 滕州市| 二手房| 白城市| 湖北省| 东乌| 吐鲁番市| 大关县| 乡城县| 合川市| 星座| 连城县| 中宁县| 鲜城| 无极县| 吴旗县| 普洱| 滨海县| 长沙市| 宁德市| 寿阳县| 大英县|