Jump to content
A.M. Hoornweg

Creating webp files with Skia fails

Recommended Posts

Hello all,

 

I have a 32-bit Windows application (it is an Intraweb based ISAPI dll) and I try to write images in losslessly compressed webp format. 

The bitmap that I want to convert to webp is a 32-bit tBitmap containing some 2-D graphics.  

 

My problem:

 

The generated output image is totally broken when I use Delphi 12's SKIA routines for the conversion. Graphics programs render it only partially, then give up. 

This is the code that I wrote; The compression factor that I pass is 100. 

 

Did I do anything wrong?

... uses  system.skia,  vcl.skia;



procedure SaveAsWebP(aBitmap: tbitmap; aOutputfilename: string; Compressionfactor: integer;Out MimeContentType:String);
begin
  var skimage:=aBitmap.ToSKImage;
  skimage.encodetofile(aOutputfilename, tskEncodedImageFormat.WebP, compressionfactor);
  MimeContentType:='image/webp';
end ;


 

intact_pngfile.png

broken_webpfile.webp

Share this post


Link to post
1 hour ago, A.M. Hoornweg said:

The generated output image is totally broken

FWIW, this is what it looks like in Firefox, so not totally broken:

image.thumb.png.307e4776e2a96769e0d3fe0de0a417d3.png

Share this post


Link to post

I have a workaround that works:

 

procedure SaveAsWebP(aBitmap: tbitmap; aOutputfilename: string; Compressionfactor: integer; out MimeContentType: string);
var
  lStream: tMemorystream;
  skimage: iSkImage;
begin
  lStream := tMemorystream.Create;
  try
    aBitmap.SaveToStream(lStream);
    lStream.Position := 0;
    skimage := tskimage.MakeFromEncodedStream(lStream);
    skimage.encodetofile(aOutputfilename, tskEncodedImageFormat.WebP, Compressionfactor);
    MimeContentType := 'image/webp';
  finally
    lStream.Free;
  end;
end;

 

 

 

So it appears that it is really the following code that is broken:

var skimage:=aBitmap.ToSKImage;

 

 

Share this post


Link to post

Open your file in browser and clearly something went wrong and this foggy text is definitely AlphaChannel problem, i copied it by clicking copy the image then pasted it in our faithful Windows Paint, the copy is done by the browser itself (the one showing foggy image), and here is the result confirming my doubts

image.thumb.png.9907dffa4604213c23999fc12665772c.png

 

It is AlphaChennel multiplexed (premultiplied) in wrong way.

 

See VP8L which is the one responsible for lossless WebP encoding does support AlphaChennel in limited way, not sure i do recall reading a lot about this, but i remember that it is supported in specific modes and color space.

 

In all cases make sure you are encoding an image without Alpha or make sure to request Alpha dropping, ( don't know if there is setting for the encoder itself though), but if your image originally didn't have AlphaChannel then you should not have a problem, if there is alpha then and want to stick to 32bit images then overwrite the AlphaChannel to opaque.

Share this post


Link to post
16 minutes ago, Kas Ob. said:

It is AlphaChennel multiplexed (premultiplied) in wrong way.

 

See VP8L which is the one responsible for lossless WebP encoding does support AlphaChennel in limited way, not sure i do recall reading a lot about this, but i remember that it is supported in specific modes and color space. In all cases make sure you are encoding an image without Alpha or make sure to request Alpha dropping, ( don't know if there is setting for the encoder itself though), but if your image originally didn't have AlphaChannel then you should not have a problem, if there is alpha then and want to stick to 32bit images then overwrite the AlphaChannel to opaque.

The bitmap is created like this, the 32-bits is just for alignment (speed) reasons:     

      ResultBitmap := tbitmap.Create;
      ResultBitmap.pixelformat := pf32bit;  
      ResultBitmap.Alphaformat := TAlphaFormat.afIgnored;

and function TSkBitmapHelper.ToSkImage (found in Unit vcl.skia)  explicitly handles that 32bit/afIgnored case, so there's probably a bug there somewhere:

if PixelFormat = TPixelFormat.pf32bit then
  begin
    case AlphaFormat of
      TAlphaFormat.afIgnored: LAlphaType := TSkAlphaType.Opaque;
      TAlphaFormat.afDefined: LAlphaType := TSkAlphaType.Unpremul;
      TAlphaFormat.afPremultiplied: LAlphaType := TSkAlphaType.Premul;
    else
      LAlphaType := TSkAlphaType.Unknown;
    end;
......

Saving the tBitmap to a stream and then creating the tSkImage from that stream works, but this still seems a bug to me.

 

 

Share this post


Link to post

I never used Skia for images like that, so i can provide zero help with that (i mean code) 

 

But to emphasize what o wrote above, the generated WebP you attached is high quality mask of the image you need, is it a bug ? i don't think so, Skia can't have bugs like that, Skia is tested and vetted enough, is the Delphi/Pascal Helper wrong ?, i can't say.

 

What i am saying is just drop all Alpha operation if you performing any, and make sure it is not Premultiplied, switch to ignore or Opaque as they appear, also it could be a simple default value somewhere, something to do with most frequent operation for WebP which is SVG handling, and SVG by design is transparent by default.

Share this post


Link to post

I'm pretty sure Skia's BMP handling isn't bug-free but it's way more likely that this problem is caused by the Delphi side of things; The alpha handling in VCL's TBitmap is such a horrible mess that it should be deprecated and reimplemented from scratch.

See also:

 

 

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×