Skip to content

Commit

Permalink
webp decoder
Browse files Browse the repository at this point in the history
  • Loading branch information
nihui committed May 28, 2020
1 parent 923b833 commit adb3d86
Show file tree
Hide file tree
Showing 7 changed files with 145 additions and 21 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[submodule "src/ncnn"]
path = src/ncnn
url = https://github.com/Tencent/ncnn.git
[submodule "src/libwebp"]
path = src/libwebp
url = https://github.com/webmproject/libwebp.git
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Usage: waifu2x-ncnn-vulkan -i infile -o outfile [options]...

-h show this help
-v verbose output
-i input-path input image path (jpg/png) or directory
-i input-path input image path (jpg/png/webp) or directory
-o output-path output image path (png) or directory
-n noise-level denoise level (-1/0/1/2/3, default=0)
-s scale upscale ratio (1/2, default=2)
Expand Down
25 changes: 24 additions & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,29 @@ option(WITH_LAYER_statisticspooling "" OFF)

add_subdirectory(ncnn)

# build libwebp library
if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/libwebp/CMakeLists.txt")
message(FATAL_ERROR "The submodules were not downloaded! Please update submodules with \"git submodule update --init --recursive\" and try again.")
endif()

option(WEBP_ENABLE_SIMD "" ON)
option(WEBP_BUILD_ANIM_UTILS "" OFF)
option(WEBP_BUILD_CWEBP "" OFF)
option(WEBP_BUILD_DWEBP "" OFF)
option(WEBP_BUILD_GIF2WEBP "" OFF)
option(WEBP_BUILD_IMG2WEBP "" OFF)
option(WEBP_BUILD_VWEBP "" OFF)
option(WEBP_BUILD_WEBPINFO "" OFF)
option(WEBP_BUILD_WEBPMUX "" OFF)
option(WEBP_BUILD_EXTRAS "" OFF)
option(WEBP_BUILD_WEBP_JS "" OFF)
option(WEBP_NEAR_LOSSLESS "" OFF)
option(WEBP_ENABLE_SWAP_16BIT_CSP "" OFF)

add_subdirectory(libwebp)

include_directories(${CMAKE_CURRENT_SOURCE_DIR}/libwebp/src)

# look for vulkan compute shader and compile
set(SHADER_SPV_HEX_FILES)

Expand All @@ -176,7 +199,7 @@ add_executable(waifu2x-ncnn-vulkan main.cpp waifu2x.cpp)

add_dependencies(waifu2x-ncnn-vulkan generate-spirv)

set(WAIFU2X_LINK_LIBRARIES ncnn ${Vulkan_LIBRARY})
set(WAIFU2X_LINK_LIBRARIES ncnn webpdecoder ${Vulkan_LIBRARY})

if(USE_STATIC_MOLTENVK)
find_library(CoreFoundation NAMES CoreFoundation)
Expand Down
1 change: 1 addition & 0 deletions src/libwebp
Submodule libwebp added at e3c259
84 changes: 67 additions & 17 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@
#define STBI_NO_GIF
#define STBI_NO_HDR
#define STBI_NO_PIC
#define STBI_NO_STDIO
#include "stb_image.h"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
#endif // _WIN32
#include "webp_image.h"

#if _WIN32
#include <wchar.h>
Expand Down Expand Up @@ -69,7 +71,7 @@ static void print_usage()
fprintf(stderr, "Usage: waifu2x-ncnn-vulkan -i infile -o outfile [options]...\n\n");
fprintf(stderr, " -h show this help\n");
fprintf(stderr, " -v verbose output\n");
fprintf(stderr, " -i input-path input image path (jpg/png) or directory\n");
fprintf(stderr, " -i input-path input image path (jpg/png/webp) or directory\n");
fprintf(stderr, " -o output-path output image path (png) or directory\n");
fprintf(stderr, " -n noise-level denoise level (-1/0/1/2/3, default=0)\n");
fprintf(stderr, " -s scale upscale ratio (1/2, default=2)\n");
Expand All @@ -84,6 +86,7 @@ class Task
{
public:
int id;
int webp;

path_t inpath;
path_t outpath;
Expand Down Expand Up @@ -163,36 +166,76 @@ void* load(void* args)
{
const path_t& imagepath = ltp->input_files[i];

int webp = 0;

unsigned char* pixeldata = 0;
int w;
int h;
int c;

#if _WIN32
pixeldata = wic_decode_image(imagepath.c_str(), &w, &h, &c);
#else // _WIN32
pixeldata = stbi_load(imagepath.c_str(), &w, &h, &c, 0);
if (pixeldata)
FILE* fp = _wfopen(imagepath.c_str(), L"rb");
#else
FILE* fp = fopen(imagepath.c_str(), "rb");
#endif
if (fp)
{
// stb_image auto channel
if (c == 1)
// read whole file
unsigned char* filedata = 0;
int length = 0;
{
// grayscale -> rgb
stbi_image_free(pixeldata);
pixeldata = stbi_load(imagepath.c_str(), &w, &h, &c, 3);
fseek(fp, 0, SEEK_END);
length = ftell(fp);
rewind(fp);
filedata = (unsigned char*)malloc(length);
if (filedata)
{
fread(filedata, 1, length, fp);
}
fclose(fp);
}
else if (c == 2)

if (filedata)
{
// grayscale + alpha -> rgba
stbi_image_free(pixeldata);
pixeldata = stbi_load(imagepath.c_str(), &w, &h, &c, 4);
pixeldata = webp_load(filedata, length, &w, &h, &c);
if (pixeldata)
{
webp = 1;
}
else
{
// not webp, try jpg png etc.
#if _WIN32
pixeldata = wic_decode_image(imagepath.c_str(), &w, &h, &c);
#else // _WIN32
pixeldata = stbi_load_from_memory(filedata, length, &w, &h, &c, 0);
if (pixeldata)
{
// stb_image auto channel
if (c == 1)
{
// grayscale -> rgb
stbi_image_free(pixeldata);
pixeldata = stbi_load_from_memory(filedata, length, &w, &h, &c, 3);
}
else if (c == 2)
{
// grayscale + alpha -> rgba
stbi_image_free(pixeldata);
pixeldata = stbi_load_from_memory(filedata, length, &w, &h, &c, 4);
}
}
#endif // _WIN32
}

free(filedata);
}
}
#endif // _WIN32
if (pixeldata)
{
Task v;
v.id = i;
v.webp = webp;
v.inpath = imagepath;
v.outpath = ltp->output_files[i];

Expand Down Expand Up @@ -265,11 +308,18 @@ void* save(void* args)
// free input pixel data
{
unsigned char* pixeldata = (unsigned char*)v.inimage.data;
if (v.webp == 1)
{
free(pixeldata);
}
else
{
#if _WIN32
free(pixeldata);
free(pixeldata);
#else
stbi_image_free(pixeldata);
stbi_image_free(pixeldata);
#endif
}
}

#if _WIN32
Expand Down
49 changes: 49 additions & 0 deletions src/webp_image.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#ifndef WEBP_IMAGE_H
#define WEBP_IMAGE_H

// webp image decoder with libwebp
#include <stdio.h>
#include <stdlib.h>
#include "webp/decode.h"

unsigned char* webp_load(const unsigned char* buffer, int len, int* w, int* h, int* c)
{
unsigned char* pixeldata = 0;

WebPDecoderConfig config;
WebPInitDecoderConfig(&config);

if (WebPGetFeatures(buffer, len, &config.input) != VP8_STATUS_OK)
return NULL;

int width = config.input.width;
int height = config.input.height;
int channels = config.input.has_alpha ? 4 : 3;

pixeldata = (unsigned char*)malloc(width * height * channels);

#if _WIN32
config.output.colorspace = channels == 4 ? MODE_BGRA : MODE_BGR;
#else
config.output.colorspace = channels == 4 ? MODE_RGBA : MODE_RGB;
#endif

config.output.u.RGBA.stride = width * channels;
config.output.u.RGBA.size = width * height * channels;
config.output.u.RGBA.rgba = pixeldata;
config.output.is_external_memory = 1;

if (WebPDecode(buffer, len, &config) != VP8_STATUS_OK)
{
free(pixeldata);
return NULL;
}

*w = width;
*h = height;
*c = channels;

return pixeldata;
}

#endif // WEBP_IMAGE_H
2 changes: 0 additions & 2 deletions src/wic_image.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ unsigned char* wic_decode_image(const wchar_t* filepath, int* w, int* h, int* c)
*h = height;
*c = channels;

fprintf(stderr, "decode %d %d %d\n", *w, *h, *c);
RETURN:
if (lock) lock->Release();
if (bitmap) bitmap->Release();
Expand All @@ -91,7 +90,6 @@ unsigned char* wic_decode_image(const wchar_t* filepath, int* w, int* h, int* c)

int wic_encode_image(const wchar_t* filepath, int w, int h, int c, void* bgrdata)
{
fprintf(stderr, "encode %d %d %d\n", w, h, c);
IWICImagingFactory* factory = 0;
IWICStream* stream = 0;
IWICBitmapEncoder* encoder = 0;
Expand Down

0 comments on commit adb3d86

Please sign in to comment.