New to Telerik Document Processing? Download free 30-day trial

Create Custom ImagePropertiesResolver in .Net Standard

Product Version Product Author
2023.1.315 RadPdfProcessing Yoan Karamanov

Description

.NET Standard specification does not define APIs for converting images or scaling their quality. That is why to export to PDF format a document containing images different than Jpeg and Jpeg2000 or ImageQuality different than High, you will need to provide an implementation of the ImagePropertiesResolver abstract class. This property enables you to set a resolver implementation that can parse the image raw data to separate its colors and alpha channel. This implementation should be passed to the ImagePropertiesResolver property of the of FixedExtensibilityManager.

Solution

The following code snippets demonstrates how to create a custom implementation of the ImagePropertiesResolver abstract class using the SixLabors.ImageSharp library and set it to the ImagePropertiesResolver property of the FixedExtensibilityManager.

Create a custom implementation inheriting the ImagePropertiesResolverBase abstract class

public class ImagePropertiesResolver : ImagePropertiesResolverBase 
{ 
    public override Telerik.Documents.Primitives.Size GetImageSize(byte[] imageData) 
    { 
        var size = Telerik.Documents.Primitives.Size.Empty; 
        try 
        { 
            using (ImageSharp image = ImageSharp.Load(imageData)) 
            { 
                size = new Telerik.Documents.Primitives.Size(image.Width, image.Height); 
            } 
        } 
        catch (UnknownImageFormatException ex) 
        { 
            // Image format not recognized. 
            throw new NotSupportedException("Unsupported image format.", ex); 
        } 
 
        return size; 
    } 
 
    public override bool TryGetRawImageData(byte[] imageData, out byte[] rawRgbData, out byte[] rawAlpha, out Telerik.Documents.Primitives.Size size) 
    { 
        try 
        { 
            IImageFormat imageFormat; 
            using (ImageSharp image = ImageSharp.Load(imageData, out imageFormat)) 
            { 
                size = new Telerik.Documents.Primitives.Size(image.Width, image.Height); 
 
                IImageDecoder decoder = null; 
                Dictionary<Type, Action> decoderSwitch = new Dictionary<Type, Action> 
                    { 
                        { typeof(PngFormat), () => decoder = new PngDecoder() }, 
                        { typeof(BmpFormat), () => decoder = new BmpDecoder() }, 
                        { typeof(GifFormat), () => decoder = new GifDecoder() }, 
                        { typeof(JpegFormat), () => decoder = new JpegDecoder() }, 
                        { typeof(PbmFormat), () => decoder = new PbmDecoder() }, 
                        { typeof(TgaFormat), () => decoder = new TgaDecoder() }, 
                        { typeof(TiffFormat), () => decoder = new TiffDecoder() }, 
                        { typeof(WebpFormat), () => decoder = new WebpDecoder() }, 
                    }; 
 
                if (decoderSwitch.ContainsKey(imageFormat.GetType())) 
                { 
                    decoderSwitchimageFormat.GetType(); 
                } 
                else 
                { 
                    rawRgbData = null; 
                    rawAlpha = null; 
 
                    return false; 
                } 
 
                Configuration configuration = new Configuration(); 
                ImageSharp decodedImage = decoder.Decode(configuration, new MemoryStream(imageData)); 
 
                ImageFrame frame = decodedImage.Frames[0]; 
 
                ImageFrame<Rgb24> frameRgb24 = frame as ImageFrame<Rgb24>; 
                if (frameRgb24 != null) 
                { 
                    GetRawDataFromRgbSource(frameRgb24, out rawRgbData); 
                    rawAlpha = null; 
 
                    return true; 
                } 
 
                ImageFrame<Rgba32> frameRgba32 = frame as ImageFrame<Rgba32>; 
                if (frameRgba32 != null) 
                { 
                    GetRawDataFromRgbaSource(frameRgba32, out rawRgbData, out rawAlpha); 
 
                    return true; 
                } 
 
                throw new NotSupportedException("Not supported image pixel format."); 
            } 
        } 
        catch (Exception ex) 
        { 
            if (ex is UnknownImageFormatException || ex is ImageProcessingException) 
            { 
                rawRgbData = null; 
                rawAlpha = null; 
                size = new Telerik.Documents.Primitives.Size(); 
 
                return false; 
            } 
            else 
            { 
                throw ex; 
            } 
        } 
    } 
 
    private static void GetRawDataFromRgbSource(ImageFrame<Rgb24> source, out byte[] data) 
    { 
        byte[] pixels = new byte[source.PixelBuffer.Width * source.PixelBuffer.Height * 3]; 
        Span<byte> span = new Span<byte>(pixels); 
        source.CopyPixelDataTo(span); 
        data = span.ToArray(); 
    } 
 
    private static void GetRawDataFromRgbaSource(ImageFrame<Rgba32> source, out byte[] data, out byte[] alpha) 
    { 
        byte[] pixels = new byte[source.PixelBuffer.Width * source.PixelBuffer.Height * 4]; 
        Span<byte> span = new Span<byte>(pixels); 
        source.CopyPixelDataTo(span); 
 
        data = new byte[source.PixelBuffer.Width * source.PixelBuffer.Height * 3]; 
        alpha = new byte[source.PixelBuffer.Width * source.PixelBuffer.Height]; 
        bool shouldExportAlpha = false; 
 
        for (int i = 0; i < pixels.Length; i += 4) 
        { 
            byte r = pixels[i]; 
            byte g = pixels[i + 1]; 
            byte b = pixels[i + 2]; 
            byte a = pixels[i + 3]; 
 
            data[3 * i / 4] = r; 
            data[3 * i / 4 + 1] = g; 
            data[3 * i / 4 + 2] = b; 
            alpha[i / 4] = a; 
 
            if (a != 255) 
            { 
                shouldExportAlpha = true; 
            } 
        } 
 
        if (!shouldExportAlpha) 
        { 
            alpha = null; 
        } 
    } 
} 

Set the custom implementation to the ImagePropertiesResolver property of the FixedExtensibilityManager

ImagePropertiesResolver customImagePropertiesResolver  = new ImagePropertiesResolver();  
FixedExtensibilityManager.ImagePropertiesResolver = customImagePropertiesResolver;  
In this article