mirror of
https://github.com/webmproject/libwebp.git
synced 2024-12-26 21:58:22 +01:00
EXPERIMENTAL: add support for alpha channel
This is a (minor) bitstream change: if the 'color_space' bit is set to '1' (which is normally an undefined/invalid behaviour), we add extra data at the end of partition #0 (so-called 'extensions') Namely, we add the size of the extension data as 3 bytes (little-endian), followed by a set of bits telling which extensions we're incorporating. The data then _preceeds_ this trailing tags. This is all experimental, and you'll need to have '#define WEBP_EXPERIMENTAL_FEATURES' in webp/types.h to enable this code (at your own risk! :)) Still, this hack produces almost-valid WebP file for decoders that don't check this color_space bit. In particular, previous 'dwebp' (and for instance Chrome) will recognize this files and decode them, but without the alpha of course. Other decoder will just see random extra stuff at the end of partition #0. To experiment with the alpha-channel, you need to compile on Unix platform and use PNGs for input/output. If 'alpha.png' is a source with alpha channel, then you can try (on Unix): cwebp alpha.png -o alpha.webp dwebp alpha.webp -o test.png cwebp now has a '-noalpha' flag to ignore any alpha information from the source, if present. More hacking and experimenting welcome! Change-Id: I3c7b1fd8411c9e7a9f77690e898479ad85c52f3e
This commit is contained in:
parent
cfbf88a6c4
commit
2ab4b72f53
4
README
4
README
@ -112,6 +112,8 @@ options:
|
|||||||
-f <int> ............... filter strength (0=off..100)
|
-f <int> ............... filter strength (0=off..100)
|
||||||
-sharpness <int> ....... filter sharpness (0:most .. 7:least sharp)
|
-sharpness <int> ....... filter sharpness (0:most .. 7:least sharp)
|
||||||
-strong ................ use strong filter instead of simple.
|
-strong ................ use strong filter instead of simple.
|
||||||
|
-alpha_comp <int> ...... set the transparency-compression
|
||||||
|
-noalpha ............... discard any transparency information.
|
||||||
-pass <int> ............ analysis pass number (1..10)
|
-pass <int> ............ analysis pass number (1..10)
|
||||||
-partitions <int> ...... number of partitions to use (0..3)
|
-partitions <int> ...... number of partitions to use (0..3)
|
||||||
-crop <x> <y> <w> <h> .. crop picture with the given rectangle
|
-crop <x> <y> <w> <h> .. crop picture with the given rectangle
|
||||||
@ -120,6 +122,8 @@ options:
|
|||||||
|
|
||||||
-short ................. condense printed message
|
-short ................. condense printed message
|
||||||
-quiet ................. don't print anything.
|
-quiet ................. don't print anything.
|
||||||
|
-version ............... print version number and exit.
|
||||||
|
-noasm ................. disable all assembly optimizations.
|
||||||
-v ..................... verbose, e.g. print encoding/decoding times
|
-v ..................... verbose, e.g. print encoding/decoding times
|
||||||
|
|
||||||
Experimental Options:
|
Experimental Options:
|
||||||
|
@ -8,6 +8,10 @@ AC_ARG_WITH([pkgconfigdir], AS_HELP_STRING([--with-pkgconfigdir=PATH],
|
|||||||
[pkgconfigdir="$withval"], [pkgconfigdir='${libdir}/pkgconfig'])
|
[pkgconfigdir="$withval"], [pkgconfigdir='${libdir}/pkgconfig'])
|
||||||
AC_SUBST([pkgconfigdir])
|
AC_SUBST([pkgconfigdir])
|
||||||
|
|
||||||
|
dnl === Check libz is present
|
||||||
|
|
||||||
|
AC_CHECK_LIB(z, gzsetparams, [AC_CHECK_HEADER(zlib.h,,)], [AC_MSG_ERROR(zlib library not found)])
|
||||||
|
|
||||||
dnl === check for PNG support ===
|
dnl === check for PNG support ===
|
||||||
|
|
||||||
PNG_INCLUDES=""
|
PNG_INCLUDES=""
|
||||||
|
@ -4,8 +4,8 @@ bin_PROGRAMS = dwebp cwebp
|
|||||||
|
|
||||||
dwebp_SOURCES = dwebp.c stopwatch.h
|
dwebp_SOURCES = dwebp.c stopwatch.h
|
||||||
dwebp_CPPFLAGS = $(AM_CPPFLAGS) $(PNG_INCLUDES) $(JPEG_INCLUDES)
|
dwebp_CPPFLAGS = $(AM_CPPFLAGS) $(PNG_INCLUDES) $(JPEG_INCLUDES)
|
||||||
dwebp_LDADD = ../src/libwebp.la $(PNG_LIBS) $(JPEG_LIBS)
|
dwebp_LDADD = ../src/libwebp.la $(PNG_LIBS) $(JPEG_LIBS) -lz
|
||||||
|
|
||||||
cwebp_SOURCES = cwebp.c stopwatch.h
|
cwebp_SOURCES = cwebp.c stopwatch.h
|
||||||
cwebp_CPPFLAGS = $(AM_CPPFLAGS) $(PNG_INCLUDES) $(JPEG_INCLUDES)
|
cwebp_CPPFLAGS = $(AM_CPPFLAGS) $(PNG_INCLUDES) $(JPEG_INCLUDES)
|
||||||
cwebp_LDADD = ../src/libwebp.la $(PNG_LIBS) $(JPEG_LIBS)
|
cwebp_LDADD = ../src/libwebp.la $(PNG_LIBS) $(JPEG_LIBS) -lz
|
||||||
|
@ -162,7 +162,8 @@ static HRESULT ReadPictureWithWIC(const char* filename,
|
|||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ReadPicture(const char* const filename, WebPPicture* const pic) {
|
static int ReadPicture(const char* const filename, WebPPicture* const pic,
|
||||||
|
int keep_alpha) {
|
||||||
int ok;
|
int ok;
|
||||||
if (pic->width != 0 && pic->height != 0) {
|
if (pic->width != 0 && pic->height != 0) {
|
||||||
// If image size is specified, infer it as YUV format.
|
// If image size is specified, infer it as YUV format.
|
||||||
@ -282,10 +283,11 @@ static void PNGAPI error_function(png_structp png, png_const_charp dummy) {
|
|||||||
longjmp(png_jmpbuf(png), 1);
|
longjmp(png_jmpbuf(png), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ReadPNG(FILE* in_file, WebPPicture* const pic) {
|
static int ReadPNG(FILE* in_file, WebPPicture* const pic, int keep_alpha) {
|
||||||
png_structp png;
|
png_structp png;
|
||||||
png_infop info;
|
png_infop info;
|
||||||
int color_type, bit_depth, interlaced;
|
int color_type, bit_depth, interlaced;
|
||||||
|
int has_alpha;
|
||||||
int num_passes;
|
int num_passes;
|
||||||
int p;
|
int p;
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
@ -327,12 +329,16 @@ static int ReadPNG(FILE* in_file, WebPPicture* const pic) {
|
|||||||
if (png_get_valid(png, info, PNG_INFO_tRNS)) {
|
if (png_get_valid(png, info, PNG_INFO_tRNS)) {
|
||||||
png_set_tRNS_to_alpha(png);
|
png_set_tRNS_to_alpha(png);
|
||||||
}
|
}
|
||||||
|
has_alpha = !!(color_type & PNG_COLOR_MASK_ALPHA);
|
||||||
|
|
||||||
|
if (!keep_alpha) {
|
||||||
|
png_set_strip_alpha(png);
|
||||||
|
has_alpha = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(skal): Strip Alpha for now (till Alpha is supported).
|
|
||||||
png_set_strip_alpha(png);
|
|
||||||
num_passes = png_set_interlace_handling(png);
|
num_passes = png_set_interlace_handling(png);
|
||||||
png_read_update_info(png, info);
|
png_read_update_info(png, info);
|
||||||
stride = 3 * width * sizeof(*rgb);
|
stride = (has_alpha ? 4 : 3) * width * sizeof(*rgb);
|
||||||
rgb = (uint8_t*)malloc(stride * height);
|
rgb = (uint8_t*)malloc(stride * height);
|
||||||
if (rgb == NULL) goto Error;
|
if (rgb == NULL) goto Error;
|
||||||
for (p = 0; p < num_passes; ++p) {
|
for (p = 0; p < num_passes; ++p) {
|
||||||
@ -346,14 +352,15 @@ static int ReadPNG(FILE* in_file, WebPPicture* const pic) {
|
|||||||
|
|
||||||
pic->width = width;
|
pic->width = width;
|
||||||
pic->height = height;
|
pic->height = height;
|
||||||
ok = WebPPictureImportRGB(pic, rgb, stride);
|
ok = has_alpha ? WebPPictureImportRGBA(pic, rgb, stride)
|
||||||
|
: WebPPictureImportRGB(pic, rgb, stride);
|
||||||
free(rgb);
|
free(rgb);
|
||||||
|
|
||||||
End:
|
End:
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static int ReadPNG(FILE* in_file, WebPPicture* const pic) {
|
static int ReadPNG(FILE* in_file, WebPPicture* const pic, int keep_alpha) {
|
||||||
printf("PNG support not compiled. Please install the libpng development "
|
printf("PNG support not compiled. Please install the libpng development "
|
||||||
"package before building.\n");
|
"package before building.\n");
|
||||||
return 0;
|
return 0;
|
||||||
@ -385,7 +392,8 @@ static InputFileFormat GetImageType(FILE* in_file) {
|
|||||||
return format;
|
return format;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ReadPicture(const char* const filename, WebPPicture* const pic) {
|
static int ReadPicture(const char* const filename, WebPPicture* const pic,
|
||||||
|
int keep_alpha) {
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
FILE* in_file = fopen(filename, "rb");
|
FILE* in_file = fopen(filename, "rb");
|
||||||
if (in_file == NULL) {
|
if (in_file == NULL) {
|
||||||
@ -397,7 +405,7 @@ static int ReadPicture(const char* const filename, WebPPicture* const pic) {
|
|||||||
// If no size specified, try to decode it as PNG/JPEG (as appropriate).
|
// If no size specified, try to decode it as PNG/JPEG (as appropriate).
|
||||||
const InputFileFormat format = GetImageType(in_file);
|
const InputFileFormat format = GetImageType(in_file);
|
||||||
if (format == PNG) {
|
if (format == PNG) {
|
||||||
ok = ReadPNG(in_file, pic);
|
ok = ReadPNG(in_file, pic, keep_alpha);
|
||||||
} else if (format == JPEG) {
|
} else if (format == JPEG) {
|
||||||
ok = ReadJPEG(in_file, pic);
|
ok = ReadJPEG(in_file, pic);
|
||||||
}
|
}
|
||||||
@ -475,6 +483,10 @@ static void PrintExtraInfo(const WebPPicture* const pic, int short_output) {
|
|||||||
100.f * stats->header_bytes[0] / stats->coded_size,
|
100.f * stats->header_bytes[0] / stats->coded_size,
|
||||||
stats->header_bytes[1],
|
stats->header_bytes[1],
|
||||||
100.f * stats->header_bytes[1] / stats->coded_size);
|
100.f * stats->header_bytes[1] / stats->coded_size);
|
||||||
|
if (stats->alpha_data_size) {
|
||||||
|
fprintf(stderr, " transparency: %6d\n",
|
||||||
|
stats->alpha_data_size);
|
||||||
|
}
|
||||||
fprintf(stderr, " Residuals bytes "
|
fprintf(stderr, " Residuals bytes "
|
||||||
"|segment 1|segment 2|segment 3"
|
"|segment 1|segment 2|segment 3"
|
||||||
"|segment 4| total\n");
|
"|segment 4| total\n");
|
||||||
@ -590,6 +602,8 @@ static void HelpLong(void) {
|
|||||||
printf(" -sharpness <int> ....... "
|
printf(" -sharpness <int> ....... "
|
||||||
"filter sharpness (0:most .. 7:least sharp)\n");
|
"filter sharpness (0:most .. 7:least sharp)\n");
|
||||||
printf(" -strong ................ use strong filter instead of simple.\n");
|
printf(" -strong ................ use strong filter instead of simple.\n");
|
||||||
|
printf(" -alpha_comp <int> ...... set the transparency-compression\n");
|
||||||
|
printf(" -noalpha ............... discard any transparency information.\n");
|
||||||
printf(" -pass <int> ............ analysis pass number (1..10)\n");
|
printf(" -pass <int> ............ analysis pass number (1..10)\n");
|
||||||
printf(" -crop <x> <y> <w> <h> .. crop picture with the given rectangle\n");
|
printf(" -crop <x> <y> <w> <h> .. crop picture with the given rectangle\n");
|
||||||
printf(" -map <int> ............. print map of extra info.\n");
|
printf(" -map <int> ............. print map of extra info.\n");
|
||||||
@ -618,12 +632,15 @@ int main(int argc, const char *argv[]) {
|
|||||||
int c;
|
int c;
|
||||||
int short_output = 0;
|
int short_output = 0;
|
||||||
int quiet = 0;
|
int quiet = 0;
|
||||||
|
int keep_alpha = 0;
|
||||||
int crop = 0, crop_x = 0, crop_y = 0, crop_w = 0, crop_h = 0;
|
int crop = 0, crop_x = 0, crop_y = 0, crop_w = 0, crop_h = 0;
|
||||||
WebPPicture picture;
|
WebPPicture picture;
|
||||||
WebPConfig config;
|
WebPConfig config;
|
||||||
WebPAuxStats stats;
|
WebPAuxStats stats;
|
||||||
Stopwatch stop_watch;
|
Stopwatch stop_watch;
|
||||||
|
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||||
|
keep_alpha = 1;
|
||||||
|
#endif
|
||||||
if (!WebPPictureInit(&picture) || !WebPConfigInit(&config)) {
|
if (!WebPPictureInit(&picture) || !WebPConfigInit(&config)) {
|
||||||
fprintf(stderr, "Error! Version mismatch!\n");
|
fprintf(stderr, "Error! Version mismatch!\n");
|
||||||
goto Error;
|
goto Error;
|
||||||
@ -675,6 +692,10 @@ int main(int argc, const char *argv[]) {
|
|||||||
config.preprocessing = strtol(argv[++c], NULL, 0);
|
config.preprocessing = strtol(argv[++c], NULL, 0);
|
||||||
} else if (!strcmp(argv[c], "-segments") && c < argc - 1) {
|
} else if (!strcmp(argv[c], "-segments") && c < argc - 1) {
|
||||||
config.segments = strtol(argv[++c], NULL, 0);
|
config.segments = strtol(argv[++c], NULL, 0);
|
||||||
|
} else if (!strcmp(argv[c], "-alpha_comp") && c < argc - 1) {
|
||||||
|
config.alpha_compression = strtol(argv[++c], NULL, 0);
|
||||||
|
} else if (!strcmp(argv[c], "-noalpha")) {
|
||||||
|
keep_alpha = 0;
|
||||||
} else if (!strcmp(argv[c], "-map") && c < argc - 1) {
|
} else if (!strcmp(argv[c], "-map") && c < argc - 1) {
|
||||||
picture.extra_info_type = strtol(argv[++c], NULL, 0);
|
picture.extra_info_type = strtol(argv[++c], NULL, 0);
|
||||||
} else if (!strcmp(argv[c], "-crop") && c < argc - 4) {
|
} else if (!strcmp(argv[c], "-crop") && c < argc - 4) {
|
||||||
@ -734,7 +755,7 @@ int main(int argc, const char *argv[]) {
|
|||||||
// Read the input
|
// Read the input
|
||||||
if (verbose)
|
if (verbose)
|
||||||
StopwatchReadAndReset(&stop_watch);
|
StopwatchReadAndReset(&stop_watch);
|
||||||
if (!ReadPicture(in_file, &picture)) {
|
if (!ReadPicture(in_file, &picture, keep_alpha)) {
|
||||||
fprintf(stderr, "Error! Cannot read input picture\n");
|
fprintf(stderr, "Error! Cannot read input picture\n");
|
||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
|
@ -109,7 +109,8 @@ static HRESULT WriteUsingWIC(const char* out_file_name, REFGUID container_guid,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int WritePNG(const char* out_file_name, unsigned char* rgb, int stride,
|
static int WritePNG(const char* out_file_name, unsigned char* rgb, int stride,
|
||||||
uint32_t width, uint32_t height) {
|
uint32_t width, uint32_t height, int has_alpha) {
|
||||||
|
assert(!has_alpha); // TODO(mikolaj)
|
||||||
return SUCCEEDED(WriteUsingWIC(out_file_name,
|
return SUCCEEDED(WriteUsingWIC(out_file_name,
|
||||||
MAKE_REFGUID(GUID_ContainerFormatPng), rgb, stride, width,
|
MAKE_REFGUID(GUID_ContainerFormatPng), rgb, stride, width,
|
||||||
height));
|
height));
|
||||||
@ -122,7 +123,7 @@ static void PNGAPI error_function(png_structp png, png_const_charp dummy) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int WritePNG(FILE* out_file, unsigned char* rgb, int stride,
|
static int WritePNG(FILE* out_file, unsigned char* rgb, int stride,
|
||||||
png_uint_32 width, png_uint_32 height) {
|
png_uint_32 width, png_uint_32 height, int has_alpha) {
|
||||||
png_structp png;
|
png_structp png;
|
||||||
png_infop info;
|
png_infop info;
|
||||||
png_uint_32 y;
|
png_uint_32 y;
|
||||||
@ -142,7 +143,8 @@ static int WritePNG(FILE* out_file, unsigned char* rgb, int stride,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
png_init_io(png, out_file);
|
png_init_io(png, out_file);
|
||||||
png_set_IHDR(png, info, width, height, 8, PNG_COLOR_TYPE_RGB,
|
png_set_IHDR(png, info, width, height, 8,
|
||||||
|
has_alpha ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB,
|
||||||
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
|
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
|
||||||
PNG_FILTER_TYPE_DEFAULT);
|
PNG_FILTER_TYPE_DEFAULT);
|
||||||
png_write_info(png, info);
|
png_write_info(png, info);
|
||||||
@ -159,7 +161,7 @@ static int WritePNG(FILE* out_file, unsigned char* rgb, int stride,
|
|||||||
typedef uint32_t png_uint_32;
|
typedef uint32_t png_uint_32;
|
||||||
|
|
||||||
static int WritePNG(FILE* out_file, unsigned char* rgb, int stride,
|
static int WritePNG(FILE* out_file, unsigned char* rgb, int stride,
|
||||||
png_uint_32 width, png_uint_32 height) {
|
png_uint_32 width, png_uint_32 height, int has_alpha) {
|
||||||
printf("PNG support not compiled. Please install the libpng development "
|
printf("PNG support not compiled. Please install the libpng development "
|
||||||
"package before building.\n");
|
"package before building.\n");
|
||||||
printf("You can run with -ppm flag to decode in PPM format.\n");
|
printf("You can run with -ppm flag to decode in PPM format.\n");
|
||||||
@ -167,12 +169,28 @@ static int WritePNG(FILE* out_file, unsigned char* rgb, int stride,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int WritePPM(FILE* fout, unsigned char* rgb,
|
static int WritePPM(FILE* fout, const unsigned char* rgb,
|
||||||
uint32_t width, uint32_t height) {
|
uint32_t width, uint32_t height) {
|
||||||
fprintf(fout, "P6\n%d %d\n255\n", width, height);
|
fprintf(fout, "P6\n%d %d\n255\n", width, height);
|
||||||
return (fwrite(rgb, width * height, 3, fout) == 3);
|
return (fwrite(rgb, width * height, 3, fout) == 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int WriteAlphaPlane(FILE* fout, const unsigned char* rgba,
|
||||||
|
uint32_t width, uint32_t height) {
|
||||||
|
uint32_t y;
|
||||||
|
fprintf(fout, "P5\n%d %d\n255\n", width, height);
|
||||||
|
for (y = 0; y < height; ++y) {
|
||||||
|
const unsigned char* line = rgba + y * (width * 4);
|
||||||
|
uint32_t x;
|
||||||
|
for (x = 0; x < width; ++x) {
|
||||||
|
if (fputc(line[4 * x + 3], fout) == EOF) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int WritePGM(FILE* fout,
|
static int WritePGM(FILE* fout,
|
||||||
unsigned char* y_plane, unsigned char *u, unsigned char* v,
|
unsigned char* y_plane, unsigned char *u, unsigned char* v,
|
||||||
int y_stride, int uv_stride,
|
int y_stride, int uv_stride,
|
||||||
@ -202,6 +220,7 @@ typedef enum {
|
|||||||
PNG = 0,
|
PNG = 0,
|
||||||
PPM,
|
PPM,
|
||||||
PGM,
|
PGM,
|
||||||
|
ALPHA_PLANE_ONLY // this is for experimenting only
|
||||||
} OutputFileFormat;
|
} OutputFileFormat;
|
||||||
|
|
||||||
static void Help(void) {
|
static void Help(void) {
|
||||||
@ -222,6 +241,7 @@ int main(int argc, const char *argv[]) {
|
|||||||
const char *out_file = NULL;
|
const char *out_file = NULL;
|
||||||
|
|
||||||
int width, height, stride, uv_stride;
|
int width, height, stride, uv_stride;
|
||||||
|
int has_alpha = 0;
|
||||||
uint8_t* out = NULL, *u = NULL, *v = NULL;
|
uint8_t* out = NULL, *u = NULL, *v = NULL;
|
||||||
OutputFileFormat format = PNG;
|
OutputFileFormat format = PNG;
|
||||||
Stopwatch stop_watch;
|
Stopwatch stop_watch;
|
||||||
@ -232,6 +252,8 @@ int main(int argc, const char *argv[]) {
|
|||||||
return 0;
|
return 0;
|
||||||
} else if (!strcmp(argv[c], "-o") && c < argc - 1) {
|
} else if (!strcmp(argv[c], "-o") && c < argc - 1) {
|
||||||
out_file = argv[++c];
|
out_file = argv[++c];
|
||||||
|
} else if (!strcmp(argv[c], "-alpha")) {
|
||||||
|
format = ALPHA_PLANE_ONLY;
|
||||||
} else if (!strcmp(argv[c], "-ppm")) {
|
} else if (!strcmp(argv[c], "-ppm")) {
|
||||||
format = PPM;
|
format = PPM;
|
||||||
} else if (!strcmp(argv[c], "-version")) {
|
} else if (!strcmp(argv[c], "-version")) {
|
||||||
@ -284,8 +306,12 @@ int main(int argc, const char *argv[]) {
|
|||||||
case PNG:
|
case PNG:
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
out = WebPDecodeBGR((const uint8_t*)data, data_size, &width, &height);
|
out = WebPDecodeBGR((const uint8_t*)data, data_size, &width, &height);
|
||||||
|
stride = 3 * width;
|
||||||
|
has_alpha = 0;
|
||||||
#else
|
#else
|
||||||
out = WebPDecodeRGB((const uint8_t*)data, data_size, &width, &height);
|
out = WebPDecodeRGBA((const uint8_t*)data, data_size, &width, &height);
|
||||||
|
stride = 4 * width;
|
||||||
|
has_alpha = 1;
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
case PPM:
|
case PPM:
|
||||||
@ -295,6 +321,9 @@ int main(int argc, const char *argv[]) {
|
|||||||
out = WebPDecodeYUV((const uint8_t*)data, data_size, &width, &height,
|
out = WebPDecodeYUV((const uint8_t*)data, data_size, &width, &height,
|
||||||
&u, &v, &stride, &uv_stride);
|
&u, &v, &stride, &uv_stride);
|
||||||
break;
|
break;
|
||||||
|
case ALPHA_PLANE_ONLY:
|
||||||
|
out = WebPDecodeRGBA((const uint8_t*)data, data_size, &width, &height);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
free(data);
|
free(data);
|
||||||
return -1;
|
return -1;
|
||||||
@ -331,14 +360,16 @@ int main(int argc, const char *argv[]) {
|
|||||||
int ok = 1;
|
int ok = 1;
|
||||||
if (format == PNG) {
|
if (format == PNG) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
ok &= WritePNG(out_file, out, 3 * width, width, height);
|
ok &= WritePNG(out_file, out, stride, width, height, has_alpha);
|
||||||
#else
|
#else
|
||||||
ok &= WritePNG(fout, out, 3 * width, width, height);
|
ok &= WritePNG(fout, out, stride, width, height, has_alpha);
|
||||||
#endif
|
#endif
|
||||||
} else if (format == PPM) {
|
} else if (format == PPM) {
|
||||||
ok &= WritePPM(fout, out, width, height);
|
ok &= WritePPM(fout, out, width, height);
|
||||||
} else if (format == PGM) {
|
} else if (format == PGM) {
|
||||||
ok &= WritePGM(fout, out, u, v, stride, uv_stride, width, height);
|
ok &= WritePGM(fout, out, u, v, stride, uv_stride, width, height);
|
||||||
|
} else if (format == ALPHA_PLANE_ONLY) {
|
||||||
|
ok &= WriteAlphaPlane(fout, out, width, height);
|
||||||
}
|
}
|
||||||
if (fout)
|
if (fout)
|
||||||
fclose(fout);
|
fclose(fout);
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
# These flag assume you have libpng and libjpeg installed. If not, either
|
# These flag assume you have libpng and libjpeg installed. If not, either
|
||||||
# follow below install instructions or just comment out the next lines.
|
# follow below install instructions or just comment out the next lines.
|
||||||
EXTRA_FLAGS= -DWEBP_HAVE_PNG -DWEBP_HAVE_JPEG
|
EXTRA_FLAGS= -DWEBP_HAVE_PNG -DWEBP_HAVE_JPEG
|
||||||
EXTRA_LIBS= -lpng -ljpeg
|
EXTRA_LIBS= -lpng -ljpeg -lz
|
||||||
ifeq ("$(HOSTTYPE)", "intel-mac")
|
ifeq ("$(HOSTTYPE)", "intel-mac")
|
||||||
EXTRA_FLAGS += -I/opt/local/include
|
EXTRA_FLAGS += -I/opt/local/include
|
||||||
EXTRA_LIBS += -L/opt/local/lib
|
EXTRA_LIBS += -L/opt/local/lib
|
||||||
@ -46,13 +46,13 @@ CFLAGS = -O3 -DNDEBUG $(EXTRA_FLAGS)
|
|||||||
LDFLAGS = src/libwebp.a $(EXTRA_LIBS) -lm
|
LDFLAGS = src/libwebp.a $(EXTRA_LIBS) -lm
|
||||||
|
|
||||||
OBJS = src/enc/webpenc.o src/enc/bit_writer.o src/enc/syntax.o \
|
OBJS = src/enc/webpenc.o src/enc/bit_writer.o src/enc/syntax.o \
|
||||||
src/enc/dsp.o src/enc/dsp_sse2.o \
|
src/enc/dsp.o src/enc/dsp_sse2.o src/enc/alpha.o \
|
||||||
src/enc/tree.o src/enc/config.o src/enc/frame.o \
|
src/enc/tree.o src/enc/config.o src/enc/frame.o \
|
||||||
src/enc/quant.o src/enc/iterator.o src/enc/analysis.o \
|
src/enc/quant.o src/enc/iterator.o src/enc/analysis.o \
|
||||||
src/enc/cost.o src/enc/picture.o src/enc/filter.o \
|
src/enc/cost.o src/enc/picture.o src/enc/filter.o \
|
||||||
src/dec/bits.o src/dec/dsp.o src/dec/frame.o src/dec/webp.o \
|
src/dec/bits.o src/dec/dsp.o src/dec/frame.o src/dec/webp.o \
|
||||||
src/dec/quant.o src/dec/tree.o src/dec/vp8.o src/dec/yuv.o \
|
src/dec/quant.o src/dec/tree.o src/dec/vp8.o src/dec/yuv.o \
|
||||||
src/dec/idec.o
|
src/dec/idec.o src/dec/alpha.o
|
||||||
HDRS = src/webp/encode.h src/enc/vp8enci.h src/enc/bit_writer.h \
|
HDRS = src/webp/encode.h src/enc/vp8enci.h src/enc/bit_writer.h \
|
||||||
src/enc/cost.h src/dec/bits.h src/dec/vp8i.h src/dec/yuv.h
|
src/enc/cost.h src/dec/bits.h src/dec/vp8i.h src/dec/yuv.h
|
||||||
OUTPUT = examples/cwebp examples/dwebp src/libwebp.a
|
OUTPUT = examples/cwebp examples/dwebp src/libwebp.a
|
||||||
|
@ -6,7 +6,7 @@ lib_LTLIBRARIES = libwebp.la
|
|||||||
libwebp_la_SOURCES =
|
libwebp_la_SOURCES =
|
||||||
libwebp_la_LIBADD = dec/libwebpdecode.la \
|
libwebp_la_LIBADD = dec/libwebpdecode.la \
|
||||||
enc/libwebpencode.la
|
enc/libwebpencode.la
|
||||||
libwebp_la_LDFLAGS = -version-info 0:0:0
|
libwebp_la_LDFLAGS = -version-info 0:0:0 -lz
|
||||||
libwebpinclude_HEADERS = webp/types.h webp/decode.h webp/decode_vp8.h \
|
libwebpinclude_HEADERS = webp/types.h webp/decode.h webp/decode_vp8.h \
|
||||||
webp/encode.h
|
webp/encode.h
|
||||||
libwebpincludedir = $(includedir)/webp
|
libwebpincludedir = $(includedir)/webp
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
AM_CPPFLAGS = -I$(top_srcdir)/src
|
AM_CPPFLAGS = -I$(top_srcdir)/src
|
||||||
|
|
||||||
libwebpdecode_la_SOURCES = bits.h vp8i.h yuv.h bits.c dsp.c frame.c \
|
libwebpdecode_la_SOURCES = bits.h vp8i.h yuv.h bits.c dsp.c frame.c \
|
||||||
quant.c tree.c vp8.c webp.c yuv.c idec.c
|
quant.c tree.c vp8.c webp.c yuv.c idec.c alpha.c
|
||||||
libwebpdecode_la_LDFLAGS = -version-info 0:0:0
|
libwebpdecode_la_LDFLAGS = -version-info 0:0:0
|
||||||
libwebpdecodeinclude_HEADERS = ../webp/decode.h ../webp/decode_vp8.h ../webp/types.h
|
libwebpdecodeinclude_HEADERS = ../webp/decode.h ../webp/decode_vp8.h ../webp/types.h
|
||||||
libwebpdecodeincludedir = $(includedir)/webp
|
libwebpdecodeincludedir = $(includedir)/webp
|
||||||
|
69
src/dec/alpha.c
Normal file
69
src/dec/alpha.c
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
// Copyright 2011 Google Inc.
|
||||||
|
//
|
||||||
|
// This code is licensed under the same terms as WebM:
|
||||||
|
// Software License Agreement: http://www.webmproject.org/license/software/
|
||||||
|
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Alpha-plane decompression.
|
||||||
|
//
|
||||||
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "vp8i.h"
|
||||||
|
|
||||||
|
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||||
|
|
||||||
|
#include "zlib.h"
|
||||||
|
|
||||||
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
|
||||||
|
int row, int num_rows) {
|
||||||
|
uint8_t* output = dec->alpha_plane_;
|
||||||
|
const int stride = dec->pic_hdr_.width_;
|
||||||
|
if (row < 0 || row + num_rows > dec->pic_hdr_.height_) {
|
||||||
|
return NULL; // sanity check
|
||||||
|
}
|
||||||
|
if (row == 0) {
|
||||||
|
// TODO(skal): for now, we just decompress everything during the first call.
|
||||||
|
// Later, we'll decode progressively, but we need to store the
|
||||||
|
// z_stream state.
|
||||||
|
const uint8_t* data = dec->alpha_data_;
|
||||||
|
size_t data_size = dec->alpha_data_size_;
|
||||||
|
const size_t output_size = stride * dec->pic_hdr_.height_;
|
||||||
|
int ret = Z_OK;
|
||||||
|
z_stream strm;
|
||||||
|
|
||||||
|
memset(&strm, 0, sizeof(strm));
|
||||||
|
if (inflateInit(&strm) != Z_OK) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
strm.avail_in = data_size;
|
||||||
|
strm.next_in = (unsigned char*)data;
|
||||||
|
do {
|
||||||
|
strm.avail_out = output_size;
|
||||||
|
strm.next_out = output;
|
||||||
|
ret = inflate(&strm, Z_NO_FLUSH);
|
||||||
|
if (ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (strm.avail_out == 0);
|
||||||
|
|
||||||
|
inflateEnd(&strm);
|
||||||
|
if (ret != Z_STREAM_END) {
|
||||||
|
return NULL; // error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return output + row * stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // WEBP_EXPERIMENTAL_FEATURES
|
@ -33,10 +33,12 @@ int VP8InitFrame(VP8Decoder* const dec, VP8Io* io) {
|
|||||||
const int coeffs_size = 384 * sizeof(*dec->coeffs_);
|
const int coeffs_size = 384 * sizeof(*dec->coeffs_);
|
||||||
const int cache_height = (16 + kFilterExtraRows[dec->filter_type_]) * 3 / 2;
|
const int cache_height = (16 + kFilterExtraRows[dec->filter_type_]) * 3 / 2;
|
||||||
const int cache_size = top_size * cache_height;
|
const int cache_size = top_size * cache_height;
|
||||||
|
const int alpha_size =
|
||||||
|
dec->alpha_data_ ? (dec->pic_hdr_.width_ * dec->pic_hdr_.height_) : 0;
|
||||||
const int needed = intra_pred_mode_size
|
const int needed = intra_pred_mode_size
|
||||||
+ top_size + info_size
|
+ top_size + info_size
|
||||||
+ yuv_size + coeffs_size
|
+ yuv_size + coeffs_size
|
||||||
+ cache_size + ALIGN_MASK;
|
+ cache_size + alpha_size + ALIGN_MASK;
|
||||||
uint8_t* mem;
|
uint8_t* mem;
|
||||||
|
|
||||||
if (needed > dec->mem_size_) {
|
if (needed > dec->mem_size_) {
|
||||||
@ -84,6 +86,10 @@ int VP8InitFrame(VP8Decoder* const dec, VP8Io* io) {
|
|||||||
}
|
}
|
||||||
mem += cache_size;
|
mem += cache_size;
|
||||||
|
|
||||||
|
// alpha plane
|
||||||
|
dec->alpha_plane_ = alpha_size ? (uint8_t*)mem : NULL;
|
||||||
|
mem += alpha_size;
|
||||||
|
|
||||||
// note: left-info is initialized once for all.
|
// note: left-info is initialized once for all.
|
||||||
memset(dec->mb_info_ - 1, 0, (mb_w + 1) * sizeof(*dec->mb_info_));
|
memset(dec->mb_info_ - 1, 0, (mb_w + 1) * sizeof(*dec->mb_info_));
|
||||||
|
|
||||||
@ -100,6 +106,7 @@ int VP8InitFrame(VP8Decoder* const dec, VP8Io* io) {
|
|||||||
io->y_stride = dec->cache_y_stride_;
|
io->y_stride = dec->cache_y_stride_;
|
||||||
io->uv_stride = dec->cache_uv_stride_;
|
io->uv_stride = dec->cache_uv_stride_;
|
||||||
io->fancy_upscaling = 0; // default
|
io->fancy_upscaling = 0; // default
|
||||||
|
io->a = NULL;
|
||||||
|
|
||||||
// Init critical function pointers and look-up tables.
|
// Init critical function pointers and look-up tables.
|
||||||
VP8DspInitTables();
|
VP8DspInitTables();
|
||||||
@ -250,6 +257,16 @@ int VP8FinishRow(VP8Decoder* const dec, VP8Io* io) {
|
|||||||
}
|
}
|
||||||
io->mb_y = y_start;
|
io->mb_y = y_start;
|
||||||
io->mb_h = y_end - y_start;
|
io->mb_h = y_end - y_start;
|
||||||
|
io->a = NULL;
|
||||||
|
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||||
|
if (dec->alpha_data_) {
|
||||||
|
io->a = VP8DecompressAlphaRows(dec, y_start, y_end - y_start);
|
||||||
|
if (io->a == NULL) {
|
||||||
|
return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
|
||||||
|
"Could not decode alpha data.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (!io->put(io)) {
|
if (!io->put(io)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -305,6 +305,10 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
|
|||||||
return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA,
|
return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA,
|
||||||
"bad partition length");
|
"bad partition length");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dec->alpha_data_ = NULL;
|
||||||
|
dec->alpha_data_size_ = 0;
|
||||||
|
|
||||||
br = &dec->br_;
|
br = &dec->br_;
|
||||||
VP8InitBitReader(br, buf, buf + frm_hdr->partition_length_);
|
VP8InitBitReader(br, buf, buf + frm_hdr->partition_length_);
|
||||||
buf += frm_hdr->partition_length_;
|
buf += frm_hdr->partition_length_;
|
||||||
@ -323,6 +327,7 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
|
|||||||
return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
|
return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
|
||||||
"cannot parse filter header");
|
"cannot parse filter header");
|
||||||
}
|
}
|
||||||
|
|
||||||
status = ParsePartitions(dec, buf, buf_size);
|
status = ParsePartitions(dec, buf, buf_size);
|
||||||
if (status != VP8_STATUS_OK) {
|
if (status != VP8_STATUS_OK) {
|
||||||
return VP8SetError(dec, status, "cannot parse partitions");
|
return VP8SetError(dec, status, "cannot parse partitions");
|
||||||
@ -368,6 +373,32 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
|
|||||||
|
|
||||||
VP8ParseProba(br, dec);
|
VP8ParseProba(br, dec);
|
||||||
|
|
||||||
|
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||||
|
// Extensions
|
||||||
|
if (dec->pic_hdr_.colorspace_) {
|
||||||
|
const uint32_t EXT_SIZE = 4;
|
||||||
|
uint32_t ext_size;
|
||||||
|
uint8_t ext_bits;
|
||||||
|
const uint8_t* ext_bytes_end = buf - EXT_SIZE;
|
||||||
|
if (frm_hdr->partition_length_ <= EXT_SIZE) {
|
||||||
|
return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
|
||||||
|
"RIFF: Inconsistent extra information.");
|
||||||
|
}
|
||||||
|
ext_size = (ext_bytes_end[0] << 16) | (ext_bytes_end[1] << 8)
|
||||||
|
| (ext_bytes_end[2]);
|
||||||
|
ext_bits = ext_bytes_end[3];
|
||||||
|
ext_bytes_end -= ext_size;
|
||||||
|
if (!(ext_bits & 0x01) || (ext_size + EXT_SIZE > frm_hdr->partition_length_)) {
|
||||||
|
return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
|
||||||
|
"RIFF: Inconsistent extra information.");
|
||||||
|
}
|
||||||
|
if (!!(ext_bits & 0x02)) { // has alpha data
|
||||||
|
dec->alpha_data_size_ = ext_size;
|
||||||
|
dec->alpha_data_ = ext_bytes_end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// sanitized state
|
// sanitized state
|
||||||
dec->ready_ = 1;
|
dec->ready_ = 1;
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -246,6 +246,11 @@ struct VP8Decoder {
|
|||||||
// Filtering side-info
|
// Filtering side-info
|
||||||
int filter_type_; // 0=off, 1=simple, 2=complex
|
int filter_type_; // 0=off, 1=simple, 2=complex
|
||||||
uint8_t filter_levels_[NUM_MB_SEGMENTS]; // precalculated per-segment
|
uint8_t filter_levels_[NUM_MB_SEGMENTS]; // precalculated per-segment
|
||||||
|
|
||||||
|
// extensions
|
||||||
|
const uint8_t* alpha_data_; // compressed alpha data (if present)
|
||||||
|
size_t alpha_data_size_;
|
||||||
|
uint8_t* alpha_plane_; // output
|
||||||
};
|
};
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -274,6 +279,10 @@ int VP8FinishRow(VP8Decoder* const dec, VP8Io* io);
|
|||||||
// Decode one macroblock. Returns false if there is not enough data.
|
// Decode one macroblock. Returns false if there is not enough data.
|
||||||
int VP8DecodeMB(VP8Decoder* const dec, VP8BitReader* const token_br);
|
int VP8DecodeMB(VP8Decoder* const dec, VP8BitReader* const token_br);
|
||||||
|
|
||||||
|
// in alpha.c
|
||||||
|
const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
|
||||||
|
int row, int num_rows);
|
||||||
|
|
||||||
// in dsp.c
|
// in dsp.c
|
||||||
typedef void (*VP8Idct)(const int16_t* coeffs, uint8_t* dst);
|
typedef void (*VP8Idct)(const int16_t* coeffs, uint8_t* dst);
|
||||||
extern VP8Idct VP8Transform;
|
extern VP8Idct VP8Transform;
|
||||||
|
@ -139,10 +139,10 @@ static inline void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \
|
|||||||
}
|
}
|
||||||
|
|
||||||
// All variants implemented.
|
// All variants implemented.
|
||||||
UPSCALE_FUNC(UpscaleRgbLinePair, VP8YuvToRgb, 3)
|
UPSCALE_FUNC(UpscaleRgbLinePair, VP8YuvToRgb, 3)
|
||||||
UPSCALE_FUNC(UpscaleBgrLinePair, VP8YuvToBgr, 3)
|
UPSCALE_FUNC(UpscaleBgrLinePair, VP8YuvToBgr, 3)
|
||||||
UPSCALE_FUNC(UpscaleRgbaLinePair, VP8YuvToRgba, 4)
|
UPSCALE_FUNC(UpscaleRgbaLinePair, VP8YuvToRgb, 4)
|
||||||
UPSCALE_FUNC(UpscaleBgraLinePair, VP8YuvToBgra, 4)
|
UPSCALE_FUNC(UpscaleBgraLinePair, VP8YuvToBgr, 4)
|
||||||
|
|
||||||
// Main driver function.
|
// Main driver function.
|
||||||
static inline
|
static inline
|
||||||
@ -266,15 +266,42 @@ static int CustomPut(const VP8Io* io) {
|
|||||||
} else if (p->mode == MODE_BGR) {
|
} else if (p->mode == MODE_BGR) {
|
||||||
VP8YuvToBgr(y, u, v, dst + i * 3);
|
VP8YuvToBgr(y, u, v, dst + i * 3);
|
||||||
} else if (p->mode == MODE_RGBA) {
|
} else if (p->mode == MODE_RGBA) {
|
||||||
VP8YuvToRgba(y, u, v, dst + i * 4);
|
VP8YuvToRgb(y, u, v, dst + i * 4);
|
||||||
} else {
|
} else {
|
||||||
VP8YuvToBgra(y, u, v, dst + i * 4);
|
VP8YuvToBgr(y, u, v, dst + i * 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dst += p->stride;
|
dst += p->stride;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Alpha handling
|
||||||
|
if (p->mode == MODE_RGBA || p->mode == MODE_BGRA) {
|
||||||
|
int i, j;
|
||||||
|
uint8_t* dst = p->output + io->mb_y * p->stride + 3;
|
||||||
|
const uint8_t* alpha = io->a;
|
||||||
|
const int has_alpha = (alpha != NULL);
|
||||||
|
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||||
|
if (has_alpha) {
|
||||||
|
for (j = 0; j < mb_h; ++j) {
|
||||||
|
for (i = 0; i < w; ++i) {
|
||||||
|
dst[4 * i] = alpha[i];
|
||||||
|
}
|
||||||
|
alpha += io->width;
|
||||||
|
dst += p->stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (!has_alpha) { // fill-in with 0xFFs
|
||||||
|
for (j = 0; j < mb_h; ++j) {
|
||||||
|
for (i = 0; i < w; ++i) {
|
||||||
|
dst[4 * i] = 0xff;
|
||||||
|
}
|
||||||
|
dst += p->stride;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,11 +36,6 @@ inline static void VP8YuvToRgb(uint8_t y, uint8_t u, uint8_t v,
|
|||||||
rgb[2] = VP8kClip[y + b_off - YUV_RANGE_MIN];
|
rgb[2] = VP8kClip[y + b_off - YUV_RANGE_MIN];
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static void VP8YuvToRgba(int y, int u, int v, uint8_t* const rgba) {
|
|
||||||
VP8YuvToRgb(y, u, v, rgba);
|
|
||||||
rgba[3] = 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline static void VP8YuvToBgr(uint8_t y, uint8_t u, uint8_t v,
|
inline static void VP8YuvToBgr(uint8_t y, uint8_t u, uint8_t v,
|
||||||
uint8_t* const bgr) {
|
uint8_t* const bgr) {
|
||||||
const int r_off = VP8kVToR[v];
|
const int r_off = VP8kVToR[v];
|
||||||
|
@ -3,7 +3,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/src
|
|||||||
libwebpencode_la_SOURCES = analysis.c bit_writer.c bit_writer.h \
|
libwebpencode_la_SOURCES = analysis.c bit_writer.c bit_writer.h \
|
||||||
config.c cost.c cost.h dsp.c dsp_sse2.c filter.c \
|
config.c cost.c cost.h dsp.c dsp_sse2.c filter.c \
|
||||||
frame.c iterator.c picture.c quant.c \
|
frame.c iterator.c picture.c quant.c \
|
||||||
syntax.c tree.c vp8enci.h webpenc.c
|
syntax.c tree.c vp8enci.h webpenc.c alpha.c
|
||||||
libwebpencode_la_LDFLAGS = -version-info 0:0:0 -lm
|
libwebpencode_la_LDFLAGS = -version-info 0:0:0 -lm
|
||||||
libwebpencodeinclude_HEADERS = ../webp/encode.h ../webp/types.h
|
libwebpencodeinclude_HEADERS = ../webp/encode.h ../webp/types.h
|
||||||
libwebpencodeincludedir = $(includedir)/webp
|
libwebpencodeincludedir = $(includedir)/webp
|
||||||
|
98
src/enc/alpha.c
Normal file
98
src/enc/alpha.c
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
// Copyright 2011 Google Inc.
|
||||||
|
//
|
||||||
|
// This code is licensed under the same terms as WebM:
|
||||||
|
// Software License Agreement: http://www.webmproject.org/license/software/
|
||||||
|
// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Alpha-plane compression.
|
||||||
|
//
|
||||||
|
// Author: Skal (pascal.massimino@gmail.com)
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "vp8enci.h"
|
||||||
|
|
||||||
|
#include "zlib.h"
|
||||||
|
|
||||||
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static int CompressAlpha(const uint8_t* data, size_t data_size,
|
||||||
|
uint8_t** output, size_t* output_size,
|
||||||
|
int algo) {
|
||||||
|
int ret = Z_OK;
|
||||||
|
z_stream strm;
|
||||||
|
const int CHUNK_SIZE = 8192;
|
||||||
|
*output = NULL;
|
||||||
|
*output_size = 0;
|
||||||
|
memset(&strm, 0, sizeof(strm));
|
||||||
|
if (deflateInit(&strm, algo ? Z_BEST_SPEED : Z_BEST_COMPRESSION) != Z_OK) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
strm.next_in = (unsigned char*)data;
|
||||||
|
strm.avail_in = data_size;
|
||||||
|
do {
|
||||||
|
size_t size_out;
|
||||||
|
unsigned char chunk[CHUNK_SIZE];
|
||||||
|
strm.next_out = chunk;
|
||||||
|
strm.avail_out = CHUNK_SIZE;
|
||||||
|
ret = deflate(&strm, Z_FINISH);
|
||||||
|
if (ret == Z_STREAM_ERROR) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
size_out = CHUNK_SIZE - strm.avail_out;
|
||||||
|
if (size_out) {
|
||||||
|
size_t new_size = *output_size + size_out;
|
||||||
|
uint8_t* new_output = realloc(*output, new_size);
|
||||||
|
if (new_output == NULL) {
|
||||||
|
ret = Z_MEM_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
memcpy(new_output + *output_size, chunk, size_out);
|
||||||
|
*output_size = new_size;
|
||||||
|
*output = new_output;
|
||||||
|
}
|
||||||
|
} while (ret != Z_STREAM_END || strm.avail_out == 0);
|
||||||
|
|
||||||
|
deflateEnd(&strm);
|
||||||
|
if (ret != Z_STREAM_END) {
|
||||||
|
free(*output);
|
||||||
|
output_size = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* WEBP_EXPERIMENTAL_FEATURES */
|
||||||
|
|
||||||
|
int VP8EncProcessAlpha(VP8Encoder* enc) {
|
||||||
|
const WebPPicture* pic_ = enc->pic_;
|
||||||
|
enc->alpha_data_ = NULL;
|
||||||
|
enc->alpha_data_size_ = 0;
|
||||||
|
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||||
|
if (pic_->a == NULL) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (!CompressAlpha(pic_->a, pic_->width * pic_->height,
|
||||||
|
&enc->alpha_data_, &enc->alpha_data_size_,
|
||||||
|
enc->config_->alpha_compression)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* WEBP_EXPERIMENTAL_FEATURES */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VP8EncDeleteAlpha(VP8Encoder* enc) {
|
||||||
|
free(enc->alpha_data_);
|
||||||
|
enc->alpha_data_ = NULL;
|
||||||
|
enc->alpha_data_size_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
@ -168,6 +168,16 @@ uint8_t* VP8BitWriterFinish(VP8BitWriter* const bw) {
|
|||||||
return bw->buf_;
|
return bw->buf_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int VP8BitWriterAppend(VP8BitWriter* const bw,
|
||||||
|
const uint8_t* data, size_t size) {
|
||||||
|
assert(data);
|
||||||
|
if (bw->nb_bits_ != -8) return 0; // kFlush() must have been called
|
||||||
|
if (!BitWriterResize(bw, size)) return 0;
|
||||||
|
memcpy(bw->buf_ + bw->pos_, data, size);
|
||||||
|
bw->pos_ += size;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
|
@ -39,6 +39,8 @@ int VP8PutBit(VP8BitWriter* const bw, int bit, int prob);
|
|||||||
int VP8PutBitUniform(VP8BitWriter* const bw, int bit);
|
int VP8PutBitUniform(VP8BitWriter* const bw, int bit);
|
||||||
void VP8PutValue(VP8BitWriter* const bw, int value, int nb_bits);
|
void VP8PutValue(VP8BitWriter* const bw, int value, int nb_bits);
|
||||||
void VP8PutSignedValue(VP8BitWriter* const bw, int value, int nb_bits);
|
void VP8PutSignedValue(VP8BitWriter* const bw, int value, int nb_bits);
|
||||||
|
int VP8BitWriterAppend(VP8BitWriter* const bw,
|
||||||
|
const uint8_t* data, size_t size);
|
||||||
|
|
||||||
// return approximate write position (in bits)
|
// return approximate write position (in bits)
|
||||||
static inline uint64_t VP8BitWriterPos(const VP8BitWriter* const bw) {
|
static inline uint64_t VP8BitWriterPos(const VP8BitWriter* const bw) {
|
||||||
|
@ -41,6 +41,7 @@ int WebPConfigInitInternal(WebPConfig* const config,
|
|||||||
config->show_compressed = 0;
|
config->show_compressed = 0;
|
||||||
config->preprocessing = 0;
|
config->preprocessing = 0;
|
||||||
config->autofilter = 0;
|
config->autofilter = 0;
|
||||||
|
config->alpha_compression = 0;
|
||||||
|
|
||||||
// TODO(skal): tune.
|
// TODO(skal): tune.
|
||||||
switch (preset) {
|
switch (preset) {
|
||||||
@ -105,6 +106,8 @@ int WebPValidateConfig(const WebPConfig* const config) {
|
|||||||
return 0;
|
return 0;
|
||||||
if (config->partitions < 0 || config->partitions > 3)
|
if (config->partitions < 0 || config->partitions > 3)
|
||||||
return 0;
|
return 0;
|
||||||
|
if (config->alpha_compression < 0)
|
||||||
|
return 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,10 +46,30 @@ int WebPPictureAlloc(WebPPicture* const picture) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int WebPPictureAddAlphaPlane(WebPPicture* const picture) {
|
||||||
|
if (picture) {
|
||||||
|
const int width = picture->width;
|
||||||
|
const int height = picture->height;
|
||||||
|
const uint64_t a_size = (uint64_t)width * height;
|
||||||
|
// Security and validation checks
|
||||||
|
if (width <= 0 || height <= 0 || // check param error
|
||||||
|
a_size >= (1ULL << 40) || // check for reasonable global size
|
||||||
|
(size_t)a_size != a_size) { // check for overflow on 32bit
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
free(picture->a); // erase previous buffer
|
||||||
|
picture->a = (uint8_t*)malloc((size_t)a_size);
|
||||||
|
return (picture->a != NULL);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
void WebPPictureFree(WebPPicture* const picture) {
|
void WebPPictureFree(WebPPicture* const picture) {
|
||||||
if (picture) {
|
if (picture) {
|
||||||
free(picture->y);
|
free(picture->y);
|
||||||
picture->y = picture->u = picture->v = NULL;
|
picture->y = picture->u = picture->v = NULL;
|
||||||
|
free(picture->a);
|
||||||
|
picture->a = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,7 +218,7 @@ static inline int rgb_to_v(int r, int g, int b) {
|
|||||||
|
|
||||||
static int Import(WebPPicture* const picture,
|
static int Import(WebPPicture* const picture,
|
||||||
const uint8_t* const rgb, int rgb_stride,
|
const uint8_t* const rgb, int rgb_stride,
|
||||||
int step, int swap) {
|
int step, int swap, int alpha_offset) {
|
||||||
int x, y;
|
int x, y;
|
||||||
const uint8_t* const r_ptr = rgb + (swap ? 2 : 0);
|
const uint8_t* const r_ptr = rgb + (swap ? 2 : 0);
|
||||||
const uint8_t* const g_ptr = rgb + 1;
|
const uint8_t* const g_ptr = rgb + 1;
|
||||||
@ -227,6 +247,17 @@ static int Import(WebPPicture* const picture,
|
|||||||
RGB_TO_UV(x, y, SUM1);
|
RGB_TO_UV(x, y, SUM1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (alpha_offset >= 0) {
|
||||||
|
if (!WebPPictureAddAlphaPlane(picture)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for (y = 0; y < picture->height; ++y) {
|
||||||
|
for (x = 0; x < picture->width; ++x) {
|
||||||
|
picture->a[x + y * picture->width] =
|
||||||
|
rgb[step * x + y * rgb_stride + alpha_offset];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#undef SUM4
|
#undef SUM4
|
||||||
@ -238,25 +269,25 @@ static int Import(WebPPicture* const picture,
|
|||||||
int WebPPictureImportRGB(WebPPicture* const picture,
|
int WebPPictureImportRGB(WebPPicture* const picture,
|
||||||
const uint8_t* const rgb, int rgb_stride) {
|
const uint8_t* const rgb, int rgb_stride) {
|
||||||
if (!WebPPictureAlloc(picture)) return 0;
|
if (!WebPPictureAlloc(picture)) return 0;
|
||||||
return Import(picture, rgb, rgb_stride, 3, 0);
|
return Import(picture, rgb, rgb_stride, 3, 0, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int WebPPictureImportBGR(WebPPicture* const picture,
|
int WebPPictureImportBGR(WebPPicture* const picture,
|
||||||
const uint8_t* const rgb, int rgb_stride) {
|
const uint8_t* const rgb, int rgb_stride) {
|
||||||
if (!WebPPictureAlloc(picture)) return 0;
|
if (!WebPPictureAlloc(picture)) return 0;
|
||||||
return Import(picture, rgb, rgb_stride, 3, 1);
|
return Import(picture, rgb, rgb_stride, 3, 1, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int WebPPictureImportRGBA(WebPPicture* const picture,
|
int WebPPictureImportRGBA(WebPPicture* const picture,
|
||||||
const uint8_t* const rgba, int rgba_stride) {
|
const uint8_t* const rgba, int rgba_stride) {
|
||||||
if (!WebPPictureAlloc(picture)) return 0;
|
if (!WebPPictureAlloc(picture)) return 0;
|
||||||
return Import(picture, rgba, rgba_stride, 4, 0);
|
return Import(picture, rgba, rgba_stride, 4, 0, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
int WebPPictureImportBGRA(WebPPicture* const picture,
|
int WebPPictureImportBGRA(WebPPicture* const picture,
|
||||||
const uint8_t* const rgba, int rgba_stride) {
|
const uint8_t* const rgba, int rgba_stride) {
|
||||||
if (!WebPPictureAlloc(picture)) return 0;
|
if (!WebPPictureAlloc(picture)) return 0;
|
||||||
return Import(picture, rgba, rgba_stride, 4, 1);
|
return Import(picture, rgba, rgba_stride, 4, 1, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -264,7 +295,7 @@ int WebPPictureImportBGRA(WebPPicture* const picture,
|
|||||||
|
|
||||||
typedef int (*Importer)(WebPPicture* const, const uint8_t* const, int);
|
typedef int (*Importer)(WebPPicture* const, const uint8_t* const, int);
|
||||||
|
|
||||||
static size_t Encode(const uint8_t* rgb, int width, int height, int stride,
|
static size_t Encode(const uint8_t* rgba, int width, int height, int stride,
|
||||||
Importer import, float quality_factor, uint8_t** output) {
|
Importer import, float quality_factor, uint8_t** output) {
|
||||||
size_t output_size = 0;
|
size_t output_size = 0;
|
||||||
WebPPicture pic;
|
WebPPicture pic;
|
||||||
@ -286,7 +317,7 @@ static size_t Encode(const uint8_t* rgb, int width, int height, int stride,
|
|||||||
wrt.size = &output_size;
|
wrt.size = &output_size;
|
||||||
InitMemoryWriter(&wrt);
|
InitMemoryWriter(&wrt);
|
||||||
|
|
||||||
ok = import(&pic, rgb, stride) && WebPEncode(&config, &pic);
|
ok = import(&pic, rgba, stride) && WebPEncode(&config, &pic);
|
||||||
WebPPictureFree(&pic);
|
WebPPictureFree(&pic);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
free(*output);
|
free(*output);
|
||||||
|
@ -155,14 +155,46 @@ static int EmitPartitionsSize(const VP8Encoder* const enc,
|
|||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static int WriteExtensions(VP8Encoder* const enc) {
|
||||||
|
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||||
|
const int EXT_SIZE = 4;
|
||||||
|
VP8BitWriter* const bw = &enc->bw_;
|
||||||
|
uint8_t trailer[EXT_SIZE];
|
||||||
|
uint32_t ext_size = 0;
|
||||||
|
uint8_t ext_bits = 0x01;
|
||||||
|
if (enc->alpha_data_size_) {
|
||||||
|
if (!VP8BitWriterAppend(bw, enc->alpha_data_, enc->alpha_data_size_)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ext_size += enc->alpha_data_size_;
|
||||||
|
ext_bits |= 0x02;
|
||||||
|
}
|
||||||
|
trailer[0] = (ext_size >> 16) & 0xff;
|
||||||
|
trailer[1] = (ext_size >> 8) & 0xff;
|
||||||
|
trailer[2] = (ext_size >> 0) & 0xff;
|
||||||
|
trailer[EXT_SIZE - 1] = ext_bits;
|
||||||
|
if (!VP8BitWriterAppend(bw, trailer, EXT_SIZE)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
static size_t GeneratePartition0(VP8Encoder* const enc) {
|
static size_t GeneratePartition0(VP8Encoder* const enc) {
|
||||||
VP8BitWriter* const bw = &enc->bw_;
|
VP8BitWriter* const bw = &enc->bw_;
|
||||||
const int mb_size = enc->mb_w_ * enc->mb_h_;
|
const int mb_size = enc->mb_w_ * enc->mb_h_;
|
||||||
uint64_t pos1, pos2, pos3;
|
uint64_t pos1, pos2, pos3;
|
||||||
|
const int need_extensions = (enc->alpha_data_size_ > 0);
|
||||||
|
|
||||||
pos1 = VP8BitWriterPos(bw);
|
pos1 = VP8BitWriterPos(bw);
|
||||||
VP8BitWriterInit(bw, mb_size * 7 / 8); // ~7 bits per macroblock
|
VP8BitWriterInit(bw, mb_size * 7 / 8); // ~7 bits per macroblock
|
||||||
|
#ifdef WEBP_EXPERIMENTAL_FEATURES
|
||||||
|
VP8PutBitUniform(bw, need_extensions); // extensions
|
||||||
|
#else
|
||||||
VP8PutBitUniform(bw, 0); // colorspace
|
VP8PutBitUniform(bw, 0); // colorspace
|
||||||
|
#endif
|
||||||
VP8PutBitUniform(bw, 0); // clamp type
|
VP8PutBitUniform(bw, 0); // clamp type
|
||||||
|
|
||||||
PutSegmentHeader(bw, enc);
|
PutSegmentHeader(bw, enc);
|
||||||
@ -174,11 +206,17 @@ static size_t GeneratePartition0(VP8Encoder* const enc) {
|
|||||||
pos2 = VP8BitWriterPos(bw);
|
pos2 = VP8BitWriterPos(bw);
|
||||||
VP8CodeIntraModes(enc);
|
VP8CodeIntraModes(enc);
|
||||||
VP8BitWriterFinish(bw);
|
VP8BitWriterFinish(bw);
|
||||||
|
|
||||||
|
if (need_extensions && !WriteExtensions(enc)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
pos3 = VP8BitWriterPos(bw);
|
pos3 = VP8BitWriterPos(bw);
|
||||||
|
|
||||||
if (enc->pic_->stats) {
|
if (enc->pic_->stats) {
|
||||||
enc->pic_->stats->header_bytes[0] = (int)((pos2 - pos1 + 7) >> 3);
|
enc->pic_->stats->header_bytes[0] = (int)((pos2 - pos1 + 7) >> 3);
|
||||||
enc->pic_->stats->header_bytes[1] = (int)((pos3 - pos2 + 7) >> 3);
|
enc->pic_->stats->header_bytes[1] = (int)((pos3 - pos2 + 7) >> 3);
|
||||||
|
enc->pic_->stats->alpha_data_size = enc->alpha_data_size_;
|
||||||
}
|
}
|
||||||
return !bw->error_;
|
return !bw->error_;
|
||||||
}
|
}
|
||||||
|
@ -326,6 +326,10 @@ struct VP8Encoder {
|
|||||||
VP8BitWriter bw_; // part0
|
VP8BitWriter bw_; // part0
|
||||||
VP8BitWriter parts_[MAX_NUM_PARTITIONS]; // token partitions
|
VP8BitWriter parts_[MAX_NUM_PARTITIONS]; // token partitions
|
||||||
|
|
||||||
|
// transparency blob
|
||||||
|
uint8_t* alpha_data_;
|
||||||
|
size_t alpha_data_size_;
|
||||||
|
|
||||||
// quantization info (one set of DC/AC dequant factor per segment)
|
// quantization info (one set of DC/AC dequant factor per segment)
|
||||||
VP8SegmentInfo dqm_[NUM_MB_SEGMENTS];
|
VP8SegmentInfo dqm_[NUM_MB_SEGMENTS];
|
||||||
int base_quant_; // nominal quantizer value. Only used
|
int base_quant_; // nominal quantizer value. Only used
|
||||||
@ -414,6 +418,11 @@ void VP8SetSegmentParams(VP8Encoder* const enc, float quality);
|
|||||||
// Pick best modes and fills the levels. Returns true if skipped.
|
// Pick best modes and fills the levels. Returns true if skipped.
|
||||||
int VP8Decimate(VP8EncIterator* const it, VP8ModeScore* const rd, int rd_opt);
|
int VP8Decimate(VP8EncIterator* const it, VP8ModeScore* const rd, int rd_opt);
|
||||||
|
|
||||||
|
// in alpha.c
|
||||||
|
// Compress transparency information into enc->alpha_data_. Return true if ok.
|
||||||
|
int VP8EncProcessAlpha(VP8Encoder* enc);
|
||||||
|
void VP8EncDeleteAlpha(VP8Encoder* enc); // delete compressed data
|
||||||
|
|
||||||
// in dsp.c
|
// in dsp.c
|
||||||
// Transforms
|
// Transforms
|
||||||
// VP8Idct: Does one of two inverse transforms. If do_two is set, the transforms
|
// VP8Idct: Does one of two inverse transforms. If do_two is set, the transforms
|
||||||
|
@ -246,7 +246,12 @@ static VP8Encoder* InitEncoder(const WebPConfig* const config,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void DeleteEncoder(VP8Encoder* enc) {
|
static void DeleteEncoder(VP8Encoder* enc) {
|
||||||
free(enc);
|
if (enc) {
|
||||||
|
if (enc->alpha_data_) {
|
||||||
|
VP8EncDeleteAlpha(enc);
|
||||||
|
}
|
||||||
|
free(enc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -306,6 +311,7 @@ int WebPEncode(const WebPConfig* const config, WebPPicture* const pic) {
|
|||||||
ok = VP8EncAnalyze(enc)
|
ok = VP8EncAnalyze(enc)
|
||||||
&& VP8StatLoop(enc)
|
&& VP8StatLoop(enc)
|
||||||
&& VP8EncLoop(enc)
|
&& VP8EncLoop(enc)
|
||||||
|
&& VP8EncProcessAlpha(enc)
|
||||||
&& VP8EncWrite(enc);
|
&& VP8EncWrite(enc);
|
||||||
StoreStats(enc);
|
StoreStats(enc);
|
||||||
DeleteEncoder(enc);
|
DeleteEncoder(enc);
|
||||||
|
@ -178,11 +178,10 @@ VP8StatusCode WebPIAppend(WebPIDecoder* const idec, const uint8_t* data,
|
|||||||
VP8StatusCode WebPIUpdate(WebPIDecoder* const idec, const uint8_t* data,
|
VP8StatusCode WebPIUpdate(WebPIDecoder* const idec, const uint8_t* data,
|
||||||
uint32_t data_size);
|
uint32_t data_size);
|
||||||
|
|
||||||
// Returns the r/g/b/(a) image decoded so far. Returns NULL if output params
|
// Returns the RGB image decoded so far. Returns NULL if output params are not
|
||||||
// are not initialized yet. The r/g/b/(a) output type corresponds to the mode
|
// initialized yet. *last_y is the index of last decoded row in raster scan
|
||||||
// specified in WebPINew()/WebPINewRGB(). *last_y is the index of last decoded
|
// order. Some pointers (*last_y, *width etc.) can be NULL if corresponding
|
||||||
// row in raster scan order. Some pointers (*last_y, *width etc.) can be NULL if
|
// information is not needed.
|
||||||
// corresponding information is not needed.
|
|
||||||
uint8_t* WebPIDecGetRGB(const WebPIDecoder* const idec, int *last_y,
|
uint8_t* WebPIDecGetRGB(const WebPIDecoder* const idec, int *last_y,
|
||||||
int* width, int* height, int* stride);
|
int* width, int* height, int* stride);
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define WEBP_DECODER_ABI_VERSION 0x0001
|
#define WEBP_DECODER_ABI_VERSION 0x0002
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Lower-level API
|
// Lower-level API
|
||||||
@ -80,6 +80,9 @@ struct VP8Io {
|
|||||||
// of more visible blocking. Note that output will also be non-compliant
|
// of more visible blocking. Note that output will also be non-compliant
|
||||||
// with the VP8 specifications.
|
// with the VP8 specifications.
|
||||||
int bypass_filtering;
|
int bypass_filtering;
|
||||||
|
|
||||||
|
// pointer to the alpha data (if present) corresponding to the rows
|
||||||
|
const uint8_t* a;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Internal, version-checked, entry point
|
// Internal, version-checked, entry point
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define WEBP_ENCODER_ABI_VERSION 0x0001
|
#define WEBP_ENCODER_ABI_VERSION 0x0002
|
||||||
|
|
||||||
// Return the encoder's version number, packed in hexadecimal using 8bits for
|
// Return the encoder's version number, packed in hexadecimal using 8bits for
|
||||||
// each of major/minor/revision. E.g: v2.5.7 is 0x020507.
|
// each of major/minor/revision. E.g: v2.5.7 is 0x020507.
|
||||||
@ -32,7 +32,6 @@ int WebPGetEncoderVersion(void);
|
|||||||
// Returns the size of the compressed data (pointed to by *output), or 0 if
|
// Returns the size of the compressed data (pointed to by *output), or 0 if
|
||||||
// an error occurred. The compressed data must be released by the caller
|
// an error occurred. The compressed data must be released by the caller
|
||||||
// using the call 'free(*output)'.
|
// using the call 'free(*output)'.
|
||||||
// Currently, alpha values are discarded.
|
|
||||||
size_t WebPEncodeRGB(const uint8_t* rgb, int width, int height, int stride,
|
size_t WebPEncodeRGB(const uint8_t* rgb, int width, int height, int stride,
|
||||||
float quality_factor, uint8_t** output);
|
float quality_factor, uint8_t** output);
|
||||||
size_t WebPEncodeBGR(const uint8_t* bgr, int width, int height, int stride,
|
size_t WebPEncodeBGR(const uint8_t* bgr, int width, int height, int stride,
|
||||||
@ -66,6 +65,7 @@ typedef struct {
|
|||||||
int preprocessing; // preprocessing filter (0=none, 1=segment-smooth)
|
int preprocessing; // preprocessing filter (0=none, 1=segment-smooth)
|
||||||
int partitions; // log2(number of token partitions) in [0..3]
|
int partitions; // log2(number of token partitions) in [0..3]
|
||||||
// Default is set to 0 for easier progressive decoding.
|
// Default is set to 0 for easier progressive decoding.
|
||||||
|
int alpha_compression; // Algorithm for optimizing the alpha plane (0 = none)
|
||||||
} WebPConfig;
|
} WebPConfig;
|
||||||
|
|
||||||
// Enumerate some predefined settings for WebPConfig, depending on the type
|
// Enumerate some predefined settings for WebPConfig, depending on the type
|
||||||
@ -120,6 +120,8 @@ typedef struct {
|
|||||||
int segment_size[4]; // number of macroblocks in each segments
|
int segment_size[4]; // number of macroblocks in each segments
|
||||||
int segment_quant[4]; // quantizer values for each segments
|
int segment_quant[4]; // quantizer values for each segments
|
||||||
int segment_level[4]; // filtering strength for each segments [0..63]
|
int segment_level[4]; // filtering strength for each segments [0..63]
|
||||||
|
|
||||||
|
int alpha_data_size; // size of the transparency data
|
||||||
} WebPAuxStats;
|
} WebPAuxStats;
|
||||||
|
|
||||||
// Signature for output function. Should return 1 if writing was successful.
|
// Signature for output function. Should return 1 if writing was successful.
|
||||||
@ -134,7 +136,7 @@ struct WebPPicture {
|
|||||||
int width, height; // dimensions.
|
int width, height; // dimensions.
|
||||||
uint8_t *y, *u, *v; // pointers to luma/chroma planes.
|
uint8_t *y, *u, *v; // pointers to luma/chroma planes.
|
||||||
int y_stride, uv_stride; // luma/chroma strides.
|
int y_stride, uv_stride; // luma/chroma strides.
|
||||||
uint8_t *a; // pointer to the alpha plane (unused for now).
|
uint8_t *a; // pointer to the width x height alpha plane
|
||||||
|
|
||||||
// output
|
// output
|
||||||
WebPWriterFunction writer; // can be NULL
|
WebPWriterFunction writer; // can be NULL
|
||||||
@ -173,6 +175,10 @@ static inline int WebPPictureInit(WebPPicture* const picture) {
|
|||||||
// Returns 0 in case of memory error.
|
// Returns 0 in case of memory error.
|
||||||
int WebPPictureAlloc(WebPPicture* const picture);
|
int WebPPictureAlloc(WebPPicture* const picture);
|
||||||
|
|
||||||
|
// This function will add storage for a transparency plane to a picture, using
|
||||||
|
// its width and depth.
|
||||||
|
int WebPPictureAddAlphaPlane(WebPPicture* const picture);
|
||||||
|
|
||||||
// Release memory allocated by WebPPictureAlloc() or WebPPictureImport*()
|
// Release memory allocated by WebPPictureAlloc() or WebPPictureImport*()
|
||||||
// Note that this function does _not_ free the memory pointed to by 'picture'.
|
// Note that this function does _not_ free the memory pointed to by 'picture'.
|
||||||
void WebPPictureFree(WebPPicture* const picture);
|
void WebPPictureFree(WebPPicture* const picture);
|
||||||
@ -187,16 +193,17 @@ int WebPPictureCopy(const WebPPicture* const src, WebPPicture* const dst);
|
|||||||
int WebPPictureCrop(WebPPicture* const picture,
|
int WebPPictureCrop(WebPPicture* const picture,
|
||||||
int left, int top, int width, int height);
|
int left, int top, int width, int height);
|
||||||
|
|
||||||
// Colorspace conversion function. Previous buffer will be free'd, if any.
|
// Colorspace conversion function to import RGB samples.
|
||||||
|
// Previous buffer will be free'd, if any.
|
||||||
// *rgb buffer should have a size of at least height * rgb_stride.
|
// *rgb buffer should have a size of at least height * rgb_stride.
|
||||||
// Returns 0 in case of memory error.
|
// Returns 0 in case of memory error.
|
||||||
int WebPPictureImportRGB(WebPPicture* const picture,
|
int WebPPictureImportRGB(WebPPicture* const picture,
|
||||||
const uint8_t* const rgb, int rgb_stride);
|
const uint8_t* const rgb, int rgb_stride);
|
||||||
// Same, but for RGBA buffer. Alpha information is ignored.
|
// Same, but for RGBA buffer
|
||||||
int WebPPictureImportRGBA(WebPPicture* const picture,
|
int WebPPictureImportRGBA(WebPPicture* const picture,
|
||||||
const uint8_t* const rgba, int rgba_stride);
|
const uint8_t* const rgba, int rgba_stride);
|
||||||
|
|
||||||
// Variant of the above, but taking BGR input:
|
// Variant of the above, but taking BGR(A) input:
|
||||||
int WebPPictureImportBGR(WebPPicture* const picture,
|
int WebPPictureImportBGR(WebPPicture* const picture,
|
||||||
const uint8_t* const bgr, int bgr_stride);
|
const uint8_t* const bgr, int bgr_stride);
|
||||||
int WebPPictureImportBGRA(WebPPicture* const picture,
|
int WebPPictureImportBGRA(WebPPicture* const picture,
|
||||||
|
@ -12,6 +12,10 @@
|
|||||||
#ifndef WEBP_WEBP_TYPES_H_
|
#ifndef WEBP_WEBP_TYPES_H_
|
||||||
#define WEBP_WEBP_TYPES_H_
|
#define WEBP_WEBP_TYPES_H_
|
||||||
|
|
||||||
|
// This is for experimentation only! Bitstreams generated will surely
|
||||||
|
// be invalid, non-decodable ones! USE WITH CARE!
|
||||||
|
// #define WEBP_EXPERIMENTAL_FEATURES // activate alpha support, yuv444, etc.
|
||||||
|
|
||||||
#ifndef _MSC_VER
|
#ifndef _MSC_VER
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#ifdef ANSI
|
#ifdef ANSI
|
||||||
|
Loading…
Reference in New Issue
Block a user