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!
Post Reply
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 » Fri Mar 07, 2014 8:02 pm

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: 5
Joined: Sun Apr 29, 2018 12:25 pm

Re: using libwebp with wxImage

Post by Hermann » Sun May 16, 2021 8:28 pm

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: 5154
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: using libwebp with wxImage

Post by ONEEYEMAN » Tue May 18, 2021 6:11 pm

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: 5
Joined: Sun Apr 29, 2018 12:25 pm

Re: using libwebp with wxImage

Post by Hermann » Wed May 19, 2021 11:37 pm

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: 5154
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: using libwebp with wxImage

Post by ONEEYEMAN » Thu May 20, 2021 12:39 am

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: 5
Joined: Sun Apr 29, 2018 12:25 pm

Re: using libwebp with wxImage

Post by Hermann » Thu May 20, 2021 10:00 am

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.

Post Reply