Skip to content

Commit

Permalink
properly load and show alpha channel data, if it is present
Browse files Browse the repository at this point in the history
Before that, alpha channel data was ignored and images were
always treated as RGB, even if they contained RGBA data.
  • Loading branch information
striezel committed Jun 14, 2022
1 parent c0dec61 commit c2ce20b
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 16 deletions.
4 changes: 4 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Version history of webp-viewer

## Version 0.4.2 (2022-06-15)

WebP images with alpha channel will now be shown with alpha channel data.

## Version 0.4.1 (2022-03-26)

If the displayed image was scaled down to fit into the windows, then the scaling
Expand Down
6 changes: 6 additions & 0 deletions debian/changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
webp-viewer (0.4.2-1) UNRELEASED; urgency=medium

* WebP images with alpha channel will now be shown with alpha channel data.

-- Dirk Stolle <[email protected]> Wed, 15 Jun 2022 00:45:56 +0200

webp-viewer (0.4.1-1) UNRELEASED; urgency=medium

* If the displayed image was scaled down to fit into the windows, then the
Expand Down
15 changes: 11 additions & 4 deletions webp-viewer/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ const int rcAnimationsNotSupported = 4;

void showVersion()
{
std::cout << "webp-viewer, version 0.4.1, 2022-03-26\n"
std::cout << "webp-viewer, version 0.4.2, 2022-06-15\n"
<< "\n"
<< "Library versions:\n"
<< " * libwebp: " << webp_version() << "\n"
Expand Down Expand Up @@ -132,7 +132,9 @@ int main(int argc, char** argv)
return rcAnimationsNotSupported;
}

const auto data = get_rgb_data(buffer.value(), dims.value());
const bool has_alpha = has_alpha_channel(buffer.value()).value_or(false);
const colour_space cs = has_alpha ? colour_space::RGBA : colour_space::RGB;
const auto data = get_image_data(buffer.value(), dims.value(), cs);
if (!data.has_value())
{
std::cout << "Error: " << file << " could not be decoded as WebP file!\n";
Expand Down Expand Up @@ -175,8 +177,10 @@ int main(int argc, char** argv)
GLuint textureName = 0;
glGenTextures(1, &textureName);
glBindTexture(GL_TEXTURE_2D, textureName);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, dims.value().width, dims.value().height,
0, GL_RGB, GL_UNSIGNED_BYTE, data.value().data);
const GLint internal_format = has_alpha ? GL_RGBA8 : GL_RGB8;
const GLenum format = has_alpha ? GL_RGBA : GL_RGB;
glTexImage2D(GL_TEXTURE_2D, 0, internal_format, dims.value().width, dims.value().height,
0, format, GL_UNSIGNED_BYTE, data.value().data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
Expand All @@ -187,6 +191,8 @@ int main(int argc, char** argv)
while (!glfwWindowShouldClose(window))
{
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureName);
glBegin(GL_QUADS);
Expand All @@ -201,6 +207,7 @@ int main(int argc, char** argv)
glVertex2d(-1.0, 1.0);
glEnd();
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
glfwSwapBuffers(window);
glfwPollEvents();
}
Expand Down
21 changes: 11 additions & 10 deletions webp-viewer/webp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,27 +82,28 @@ std::optional<bool> has_animations(const buffer& data)
return features.has_animation != 0;
}

std::optional<image_data> get_rgb_data(const buffer& data, const dimensions& dims)
std::optional<bool> has_alpha_channel(const buffer& data)
{
/*image_data result { nullptr, 0, { -1, -1 } };
uint8_t* pixels = WebPDecodeRGB(data, data_size,
&result.size.width, &result.size.height);
if (pixels == nullptr)
WebPBitstreamFeatures features;
features.has_alpha = 0;
if (WebPGetFeatures(data.data(), data.size(), &features) != VP8StatusCode::VP8_STATUS_OK)
return std::nullopt;
result.data = pixels;
result.data_size = 3 * result.size.width * result.size.height;
return result;*/

return features.has_alpha != 0;
}

std::optional<image_data> get_image_data(const buffer& data, const dimensions& dims, const colour_space cs)
{
WebPDecoderConfig config;
if (!WebPInitDecoderConfig(&config))
return std::nullopt;

// Flip image vertically, because OpenGL expects it that way.
config.options.flip = 1;
config.output.colorspace = MODE_RGB;
config.output.colorspace = (cs == colour_space::RGB) ? MODE_RGB : MODE_RGBA;
// Set stride to multiple of four bytes, because OpenGL uses that internally
// for its textures. If this is not done, then the image is skewed.
const auto min_stride = dims.width * 3;
const auto min_stride = dims.width * ((cs == colour_space::RGB) ? 3 : 4);
const auto stride_mode = min_stride % 4;
const size_t actual_stride = min_stride + (stride_mode != 0) * (4 - stride_mode);
const size_t buffer_size = actual_stride * dims.height;
Expand Down
15 changes: 13 additions & 2 deletions webp-viewer/webp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ std::optional<dimensions> get_dimensions(const buffer& data);
*/
std::optional<bool> has_animations(const buffer& data);

/** \brief Checks whether image data contains an alpha channel.
*
* \param data contents read from the WebP file
* \return Returns a bool indicating whether the file contains an alpha channel
* in case of success. Returns an empty optional, if the data is invalid.
*/
std::optional<bool> has_alpha_channel(const buffer& data);

/** \brief Reads the whole file into a buffer.
*
* \param path the path of the file
Expand All @@ -57,13 +65,16 @@ std::optional<bool> has_animations(const buffer& data);
*/
nonstd::expected<buffer, std::string> read_file(const std::string& path);

/** \brief Decodes raw data into RGB data.
/// possible colour spaces to use for WebP decoding
enum class colour_space { RGB, RGBA };

/** \brief Decodes raw data into RGB or RGBA data.
*
* \param data contents read from the WebP file
* \param dims dimensions of the image
* \return Returns the decoded image data in case of success.
* Returns an empty optional on failure.
*/
std::optional<image_data> get_rgb_data(const buffer& data, const dimensions& dims);
std::optional<image_data> get_image_data(const buffer& data, const dimensions& dims, const colour_space cs);

#endif // WEBPVIEWER_WEBP_HPP

0 comments on commit c2ce20b

Please sign in to comment.