using libwebp with wxImage

If you have a cool piece of software to share, but you are not hosting it officially yet, please dump it in here. If you have code snippets that are useful, please donate!
User avatar
khral
In need of some credit
In need of some credit
Posts: 1
Joined: Fri Mar 07, 2014 7:06 pm
Location: Black Citadel, Ascalon

using libwebp with wxImage

Post by khral »

Rawr! Hello!

Here is a code snippet/example of how to decode WebP image and send the image to wxImage.
You also need libwebp, which can be found at https://code.google.com/p/webp/, to able to use this code.

Compile with compiler that support C++11.

Since I'm C++ and wxWidgets beginner my self, any comment of this code will be appreciated. :)

Hope this will give you some ideas of convert WebP image (may be any image format) to wxImage.

*Note* require this https://github.com/kytulendu/Gw2Browser ... il/Array.h array template (GPLV3) ...
see https://github.com/kytulendu/Gw2Browser ... Reader.cpp for example.

Edit: add missing thing.
Edit2: fix NULL to nullptr, remove license.
Edit3: cleanup
Edit4: fix memory leak?

Code: Select all

/*
WebP to wxImage code snippet
by Khral Steelforge

usage: [WebP]->readWebP( );
return wxImage.
*/

struct RGBA {
	unsigned int r;
	unsigned int g;
	unsigned int b;
	unsigned int a;
};

struct RGB {
	unsigned int r;
	unsigned int g;
	unsigned int b;
};

wxImage foo::readWebP( ) const {
	// Create image
	wxImage image;

	auto data = reinterpret_cast<const uint8_t*>( m_data.GetPointer( ) );
	size_t data_size = m_data.GetSize( );
	po_colors = nullptr;
	po_alphas = nullptr;

	WebPDecoderConfig config;
	WebPBitstreamFeatures* bitstream = &config.input;

	VP8StatusCode status = VP8_STATUS_OK;

	status = WebPGetFeatures( reinterpret_cast<const uint8_t*>( data ), data_size, bitstream );

	if ( status != VP8_STATUS_OK ) {
		wxMessageBox( wxString( "This file isn't WebP!" ), _( "" ), wxOK | wxICON_EXCLAMATION );
		return image;
	}

	if ( bitstream->has_animation ) {
		wxMessageBox( wxString( "Not support Animation WebP." ), _( "" ), wxOK | wxICON_INFORMATION );
		return image;
	}

	uint numPixels = bitstream->width * bitstream->height;

	// Why it need to convert RGB to BGR?
	auto decoded_data = reinterpret_cast<BGRA*>( WebPDecodeRGBA( data, data_size, nullptr, nullptr ) );

	if ( decoded_data == nullptr ) {
		wxMessageBox( wxString( "Invalid WebP format." ), _( "ERROR" ), wxOK | wxICON_ERROR );
		return image;
	}

	//auto colors = allocate<RGB>( numPixels );
	auto colors = static_cast<RGB*>( ::malloc( numPixels * sizeof( RGB ) ) );
	//auto alphas = allocate<uint8_t>( numPixels );
	auto alphas = static_cast<uint8_t*>( ::malloc( numPixels * sizeof( uint8_t ) ) );

#pragma omp parallel for   // comment this out if it give you compile error or you don't want to use OpenMP
	for ( int y = 0; y < static_cast<int>( bitstream->height ); y++ ) {
		uint32 curPixel = ( y * bitstream->width );

		for ( uint x = 0; x < static_cast<unsigned int>( bitstream->width ); x++ ) {
			::memcpy( &po_colors[curPixel].b, &decoded_data[curPixel].b, sizeof( po_colors[curPixel].b ) );
			::memcpy( &po_colors[curPixel].g, &decoded_data[curPixel].g, sizeof( po_colors[curPixel].g ) );
			::memcpy( &po_colors[curPixel].r, &decoded_data[curPixel].r, sizeof( po_colors[curPixel].r ) );

			if ( bitstream->has_alpha ) {
				::memcpy( &po_alphas[curPixel], &decoded_data[curPixel].a, sizeof( po_alphas[curPixel] ) );
			}
			curPixel++;
		}
	}

	freePointer( decoded_data );

	image = wxImage( bitstream->width, bitstream->height, reinterpret_cast<uint8_t*>( colors ), false );
	// Set alpha if the format has any
	if ( output_buffer->colorspace == bitstream->has_alpha ) {
		image.SetAlpha( alphas );
	}

	return image;

}
Hermann
In need of some credit
In need of some credit
Posts: 6
Joined: Sun Apr 29, 2018 12:25 pm

Re: using libwebp with wxImage

Post by Hermann »

Nice work! 👍 Based on your code, I created a wxImage file format handler for a more wholesome integration into wxWidgets.

Depends on wxWidgets and libwebp, obviously. Tested on Ubuntu 20.04 with gcc 9 and Windows 10 with MSVC 142.

Please note: Updates will only be published at https://github.com/hoehermann/wxWEBPHandler. This is the code as of writing:

Declaration:

Code: Select all

#include "wx/image.h"
class wxWEBPHandler : public wxImageHandler 
{
public:
    inline wxWEBPHandler()
    {
        m_name = wxT("WebP file");
        m_extension = wxT("webp");
        //m_type = wxBITMAP_TYPE_INVALID; // no idea what to choose here
        m_mime = wxT("image/webp");
    }
    virtual bool LoadFile(wxImage *image, wxInputStream& stream, bool verbose=true, int index=-1);
    virtual bool SaveFile(wxImage *image, wxOutputStream& stream, bool verbose=true);
protected:
    virtual bool DoCanRead(wxInputStream& stream);
private:
    wxDECLARE_DYNAMIC_CLASS(wxWEBPHandler);
};
Implementation:

Code: Select all

#include "wx/imagwebp.hpp"
#include "webp/decode.h"
wxIMPLEMENT_DYNAMIC_CLASS(wxWEBPHandler, wxImageHandler);
#include <wx/mstream.h>
bool wxWEBPHandler::LoadFile(wxImage *image, wxInputStream& stream, bool verbose, int WXUNUSED(index)) {
    image->Destroy(); // all examples do this, so I do so as well
    // TODO: do not read entire file into memory
    wxMemoryOutputStream mos;
    stream.Read(mos);
    wxStreamBuffer * mosb = mos.GetOutputStreamBuffer();
    const uint8_t * data = reinterpret_cast<uint8_t *>(mosb->GetBufferStart());
    size_t data_size = mosb->GetBufferSize();
    WebPBitstreamFeatures features;
    VP8StatusCode status = WebPGetFeatures(data, data_size, &features);
    if (status != VP8_STATUS_OK) {
        if (verbose) {
           wxLogError("WebP: GetFeatures not OK.");
        }
        return false;
    }
    if (features.has_alpha) {
        wxLogWarning("WebP: Alpha channel not implemented.");
    }
    uint8_t * rgb = WebPDecodeRGB(data, data_size, &features.width, &features.height);
    bool static_data = false; // will call free() on rgb as needed. hopefully it is compatible with WebPFree
    image->Create(features.width, features.height, rgb, static_data);
    image->SetMask(false);
    return true;
}

bool wxWEBPHandler::SaveFile(wxImage *image, wxOutputStream& stream, bool WXUNUSED(verbose)) {
    // not implemented
    return false;
}

bool wxWEBPHandler::DoCanRead(wxInputStream& stream)
{
    const std::string riff = "RIFF";
    const std::string webp = "WEBP";
    const int buffer_size = 12;
    char buffer[buffer_size];
    stream.Read(buffer, buffer_size);
    if (stream.LastRead() != buffer_size) {
        return false;
    }
    return std::string(buffer, 4) == riff && std::string(&buffer[8], 4) == webp;
}
Last edited by Hermann on Wed May 19, 2021 11:39 pm, edited 2 times in total.
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7458
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: using libwebp with wxImage

Post by ONEEYEMAN »

Hi,
Can you guys clean it up and make it available for C++ 98?
Or libwebp is available for C++11 only?

Thank you.
Hermann
In need of some credit
In need of some credit
Posts: 6
Joined: Sun Apr 29, 2018 12:25 pm

Re: using libwebp with wxImage

Post by Hermann »

Thank you for your reply. Can you elaborate on your request?

The code won't become much more compact than posted here, I guess.

Do you mean "improve upon the things labelled as TODO"?
Or do you want more features (alpha-channel, streamed reading, saving, animations)?

I can replace the unnecessary "constexpr" with "const", then g++ compiles it with "--std=c++98" enabled.
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7458
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: using libwebp with wxImage

Post by ONEEYEMAN »

Hi,
What I mean is following:

wxWidgets does not have a requirements (yet) to have c++11 to be turn on by default.
Which means that every new inclusion will have to be compatible with c++98.

So if you want this code to be included in the library the code needs to be c++98 complaint.

Thank you.
Hermann
In need of some credit
In need of some credit
Posts: 6
Joined: Sun Apr 29, 2018 12:25 pm

Re: using libwebp with wxImage

Post by Hermann »

Thank you for the answer.

I need to educate myself on some of the wxWidgets implementation details (e.g. what to do with m_type, enable support for wxOVERRIDE and WXDLLIMPEXP_CORE). I should probably ask around at [email protected] for that, I suppose.

I can
  • adhere to the mandated code style,
  • write the documentation and create some tests,
  • compile on Linux with GCC and Windows with MSVC
.
I do not have access to MacOS, so I cannot run tests on that OS.

For a meaningful contribution, I should probably add a save feature and support alpha channels.

I have to admit, it looks rather tedious. Maybe one weekend I am bored and then do this.
vali29
In need of some credit
In need of some credit
Posts: 3
Joined: Thu Nov 15, 2012 11:03 am

Re: using libwebp with wxImage

Post by vali29 »

I am trying to download this image with wxWebRequest and to encode with Base64
Image

Code: Select all

wxBitmapType image_type = online_image.GetType();
wxMemoryOutputStream mem;
online_image.SaveFile(mem, image_type); // error at line 740 in picture_csp_enc.c. NULL wxMemoryOutputStream mem
size_t sz = mem.GetSize();
wxString data = wxBase64Encode(mem.GetOutputStreamBuffer()->GetBufferStart(), sz);
but i have an error at line 740 in picture_csp_enc.c, libwebp v1.3.2

Code: Select all

static int Import(WebPPicture* const picture,
                  const uint8_t* rgb, int rgb_stride,
                  int step, int swap_rb, int import_alpha) {
...
if (abs(rgb_stride) < (import_alpha ? 4 : 3) * width) return 0;
...
}
Last edited by vali29 on Sat Dec 30, 2023 10:52 am, edited 1 time in total.
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: using libwebp with wxImage

Post by doublemax »

I assume "online_image" does not contain a valid image. Show the rest of the code and / or add some error handling.
Use the source, Luke!
vali29
In need of some credit
In need of some credit
Posts: 3
Joined: Thu Nov 15, 2012 11:03 am

Re: using libwebp with wxImage

Post by vali29 »

Code: Select all

    switch(evt.GetState()) {
        case wxWebRequest::State_Completed: {
                try {
                    wxWebResponse response = evt.GetResponse();
                    if (response.GetStatus() == 200) {
                        if (response.GetStream()->IsOk()) {

                            wxMemoryInputStream* stream = (wxMemoryInputStream*)response.GetStream();
                            wxImage logoImage(*stream);

                            if (logoImage.IsOk()) {
                                    wxString resp = response.GetURL();

                                    wxBitmapType type = logoImage.GetType(); // wxBITMAP_TYPE_WEBP OK defined in gdicmn.h
                                    m_OnlineImage = logoImage; // m_OnlineImage - copy image to pass to another class???. wxImage       m_OnlineImage;
                                    m_URL_Request = response.GetURL();
                                    TextCtrl_image_url->SetValue(resp);
                                    TextCtrl_image_url->SetInsertionPointEnd();
                                    m_ReqMIMEType = response.GetMimeType(); // No MIME Type
                                    m_redirected = true;
I'am cheking with `logoImage.IsOk('

It's working with other type of images, PNG, JPEG but not with WEBP.
Last edited by vali29 on Sat Dec 30, 2023 12:48 pm, edited 1 time in total.
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: using libwebp with wxImage

Post by doublemax »

Just to be clear: wxWidgets does not have webp support by default. But you installed the custom image handler from the top of this post?

That image handler does not have save() support though.

It's also unclear to me why you load the image data, decode it into a wxImage and then save it again. Can't you just base64 encode the original image file you received?
Use the source, Luke!
vali29
In need of some credit
In need of some credit
Posts: 3
Joined: Thu Nov 15, 2012 11:03 am

Re: using libwebp with wxImage

Post by vali29 »

doublemax wrote: Sat Dec 30, 2023 1:27 pm Just to be clear: wxWidgets does not have webp support by default. But you installed the custom image handler from the top of this post?

That image handler does not have save() support though.

It's also unclear to me why you load the image data, decode it into a wxImage and then save it again. Can't you just base64 encode the original image file you received?
Yes. I've modified only the gdicmn.h to add wxBITMAP_TYPE_WEBP and wxBITMAP_TYPE_WEBP_RESOURCE.

I need to display it in a wxPanel then encode to Base64 to insert into Markdown IMG format.

Code: Select all

![Alternative Text](data:image/webp;base64,UklGRhxRAABXRUJQVlA4I...)
screenshot.png
I used this https://github.com/hoehermann/wxWEBPHandler
Last edited by vali29 on Sat Dec 30, 2023 1:50 pm, edited 2 times in total.
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: using libwebp with wxImage

Post by doublemax »

That image (https://www.gstatic.com/webp/gallery/1.webp) does have an alpha buffer. The image handler does not support saving that.
Use the source, Luke!
vali29
In need of some credit
In need of some credit
Posts: 3
Joined: Thu Nov 15, 2012 11:03 am

Re: using libwebp with wxImage

Post by vali29 »

doublemax wrote: Sat Dec 30, 2023 2:50 pm That image (https://www.gstatic.com/webp/gallery/1.webp) does have an alpha buffer. The image handler does not support saving that.
Initially, that's what I thought too. Maybe someone implements alpha buffer decoding. Anyway, thanks for your time.
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: using libwebp with wxImage

Post by doublemax »

Here's another webp image handler which is supposed to support alpha. It doesn't support multiple images per files though (as the other handler does).

Maybe give it a try.
Attachments
imagwebp.h
(1.79 KiB) Downloaded 55 times
imagwebp.cpp
(6.27 KiB) Downloaded 63 times
Use the source, Luke!
vali29
In need of some credit
In need of some credit
Posts: 3
Joined: Thu Nov 15, 2012 11:03 am

Re: using libwebp with wxImage

Post by vali29 »

doublemax wrote: Sat Dec 30, 2023 3:28 pm Here's another webp image handler which is supposed to support alpha. It doesn't support multiple images per files though (as the other handler does).

Maybe give it a try.
Thank you soo much. It's working! :D
Post Reply