.NET 6: Transitioning from System.Drawing to SkiaSharp for Tiff to PDF conversion

1.7k Views Asked by At

I am trying several ways to remove System.Drawing due to the pending removal of the workaround in .NET 7. I am trying to use SkiaSharp to replace those calls but am having trouble.

The following is what I currently have, which processes Tiff data from a stream and passes it to PdfSharp to construct the final Pdf:

   System.Drawing.Image MyImage = System.Drawing.Image.FromStream(inStream);
   PdfDocument doc = new PdfDocument();

   for (int PageIndex = 0; PageIndex < MyImage.GetFrameCount(FrameDimension.Page); PageIndex++)
   {
     MyImage.SelectActiveFrame(FrameDimension.Page, PageIndex);
     XImage img = XImage.FromGdiPlusImage(MyImage);
     var page = new PdfPage();

     doc.Pages.Add(page);
     XGraphics xgr = XGraphics.FromPdfPage(doc.Pages[PageIndex]);
     xgr.DrawImage(img, 0, 0);
   }

   doc.Save(outStream);
   MyImage.Dispose();

I am not sure what the SkiaSharp equivalents would be and have tried searching for them in the docs.

If you have any questions, concerns, or comments, please let me know. Thanks!

1

There are 1 best solutions below

2
stefan.seeland On

SkiaSharp has no TIFF support, some resources recommend to add TIFF support using LibTiff.net. That works.

    public static async Task Main(string[] args)
    {
        GlobalFontSettings.FontResolver = new FontResolver();

        var document = new PdfDocument();
        var tempImageFiles = TiffToBitmap(args[0]);

        try
        {
            for (int pageIndex = 0; pageIndex < tempImageFiles.Count; pageIndex++)
            {
                var pageWithImage = new PdfPage();
                document.Pages.Add(pageWithImage);
                var xgr = XGraphics.FromPdfPage(document.Pages[pageIndex]);

                var xImage = XImage.FromStream(() => File.OpenRead(tempImageFiles[pageIndex]));
                xgr.DrawImage(xImage, 0, 0);
            }

            document.Save("helloworld.pdf");
        }
        finally
        {
            foreach (var tempImageFile in tempImageFiles)
            {
                File.Delete(tempImageFile);
            }
        }
    }

    private static List<string> TiffToBitmap(string tiffFilePath)
    {
        var tempPaths = new List<string>();
        using var tiff = Tiff.Open(tiffFilePath, "r");
        var numberIfTiffPages = GetNumberofTiffPages(tiff);

        for (short i = 0; i < numberIfTiffPages; i++)
        {
            tiff.SetDirectory(i);
            var width = tiff.GetField(TiffTag.IMAGEWIDTH)[0].ToInt();
            var height = tiff.GetField(TiffTag.IMAGELENGTH)[0].ToInt();
            var bitmap = new SKBitmap();
            var info = new SKImageInfo(width, height);
            var raster = new int[width * height];
            var ptr = GCHandle.Alloc(raster, GCHandleType.Pinned);
            bitmap.InstallPixels(info, ptr.AddrOfPinnedObject(), info.RowBytes, (addr, ctx) => ptr.Free(), null);

            if (!tiff.ReadRGBAImageOriented(width, height, raster, Orientation.TOPLEFT))
            {
                // not a valid TIF image.
                return null;
            }

            if (SKImageInfo.PlatformColorType == SKColorType.Bgra8888)
            {
                SKSwizzle.SwapRedBlue(ptr.AddrOfPinnedObject(), raster.Length);
            }

            var encodedData = bitmap.Encode(SKEncodedImageFormat.Png, 100);
            var tempPath = Path.Combine(Path.GetTempFileName() + ".png");
            using var bitmapImageStream = File.Open(tempPath, FileMode.Create, FileAccess.Write, FileShare.None);
            encodedData.SaveTo(bitmapImageStream);
            tempPaths.Add(tempPath);
        }
        return tempPaths;
    }

    public static int GetNumberofTiffPages(Tiff image)
    {
        int pageCount = 0;
        do
        {
            ++pageCount;
        } while (image.ReadDirectory());

        return pageCount;
    }

I found some hickups (e.g. using SKEncodedImageFormat.Bmp will break the POC... additionaly I want to point to a solution that is a bit less bumpy using ImageSharp.