Skip to content

Commit

Permalink
Add AVIF encoding support (#238)
Browse files Browse the repository at this point in the history
  • Loading branch information
kleisauke committed Dec 22, 2020
1 parent 630d625 commit ac3e355
Show file tree
Hide file tree
Showing 9 changed files with 108 additions and 2 deletions.
1 change: 1 addition & 0 deletions src/api/enums.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ enum class Output {
Jpeg,
Png,
Webp,
Avif,
Tiff,
Gif,
Json
Expand Down
2 changes: 2 additions & 0 deletions src/api/parsers/enumeration.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ inline enums::Output parse(const std::string &value) {
return enums::Output::Tiff;
} else if (value == "webp") {
return enums::Output::Webp;
} else if (value == "avif" || value == "av1") {
return enums::Output::Avif;
} else if (value == "json") {
return enums::Output::Json;
} else /*if (value == "origin")*/ {
Expand Down
26 changes: 26 additions & 0 deletions src/api/processors/stream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,29 @@ void Stream::append_save_options<Output::Webp>(vips::VOption *options) const {
options->set("alpha_q", 100);
}

template <>
void Stream::append_save_options<Output::Avif>(vips::VOption *options) const {
auto quality = query_->get_if<int>(
"q",
[](int q) {
// Quality needs to be in the range
// of 1 - 100
return q >= 1 && q <= 100;
},
static_cast<int>(config_.default_quality));

// Set quality (default is 85)
options->set("Q", quality);

// Set compression format to AV1
options->set("compression", VIPS_FOREIGN_HEIF_COMPRESSION_AV1);

#if VIPS_VERSION_AT_LEAST(8, 10, 2)
// Control the CPU effort spent on improving compression
options->set("speed", 6);
#endif
}

template <>
void Stream::append_save_options<Output::Tiff>(vips::VOption *options) const {
auto quality = query_->get_if<int>(
Expand Down Expand Up @@ -375,6 +398,9 @@ void Stream::append_save_options(const Output &output,
case Output::Webp:
append_save_options<Output::Webp>(options);
break;
case Output::Avif:
append_save_options<Output::Avif>(options);
break;
case Output::Tiff:
append_save_options<Output::Tiff>(options);
break;
Expand Down
7 changes: 6 additions & 1 deletion src/api/utils/utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ inline std::string determine_image_extension(const Output &output) {
return ".jpg";
case Output::Webp:
return ".webp";
case Output::Avif:
return ".avif";
case Output::Tiff:
return ".tiff";
case Output::Gif:
Expand All @@ -176,6 +178,8 @@ inline Output to_output(const ImageType &image_type) {
return Output::Jpeg;
case ImageType::Webp:
return Output::Webp;
case ImageType::Heif:
return Output::Avif;
case ImageType::Tiff:
return Output::Tiff;
case ImageType::Gif:
Expand Down Expand Up @@ -269,7 +273,8 @@ inline std::string image_type_id(const ImageType &image_type) {
*/
inline bool support_alpha_channel(const ImageType &image_type) {
return image_type == ImageType::Png || image_type == ImageType::Webp ||
image_type == ImageType::Tiff || image_type == ImageType::Gif;
image_type == ImageType::Heif || image_type == ImageType::Tiff ||
image_type == ImageType::Gif;
}

/**
Expand Down
2 changes: 2 additions & 0 deletions src/nginx/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ ngx_str_t extension_to_mime_type(const std::string &extension) {
return ngx_string("image/png");
} else if (extension == ".webp") {
return ngx_string("image/webp");
} else if (extension == ".avif") {
return ngx_string("image/avif");
} else if (extension == ".tiff") {
return ngx_string("image/tiff");
} else if (extension == ".gif") {
Expand Down
3 changes: 3 additions & 0 deletions test/api/fixtures.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,7 @@ struct Fixtures {

// http://www.anyhere.com/gward/pixformat/images/84y2.tif
std::string input_hdr{dir + "/84y2.hdr"};

// CC by-nc-nd https://github.com/AOMediaCodec/av1-avif/tree/master/testFiles/Netflix
std::string input_avif{dir + "/cosmos_frame12924_yuv420_10bpc_bt2020_pq_q50.avif"};
};
Binary file not shown.
69 changes: 68 additions & 1 deletion test/api/processors/unit-stream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,33 @@ TEST_CASE("output", "[stream]") {
CHECK(image.height() == 300);
}

SECTION("avif") {
if (vips_type_find("VipsOperation",
pre_8_11 ? "heifload_buffer" : "heifload_source") ==
0 ||
vips_type_find("VipsOperation",
pre_8_11 ? "heifsave_buffer" : "heifsave_target") ==
0) {
SUCCEED("no avif support, skipping test");
return;
}

auto test_image = fixtures->input_avif;
auto params = "w=300&h=300&fit=cover&output=avif";

VImage image = process_file<VImage>(test_image, params);

CHECK_THAT(image.get_string("vips-loader"), Equals("heifload_buffer"));

// "heif-compression" metadata added in vips 8.11
if (!pre_8_11) {
CHECK_THAT(image.get_string("heif-compression"), Equals("av1"));
}

CHECK(image.width() == 300);
CHECK(image.height() == 300);
}

SECTION("tiff") {
if (vips_type_find("VipsOperation",
pre_8_11 ? "tiffload_buffer" : "tiffload_source") ==
Expand Down Expand Up @@ -247,6 +274,30 @@ TEST_CASE("quality and compression", "[stream]") {
CHECK(buffer_85.size() < buffer_95.size());
}

SECTION("avif quality") {
if (vips_type_find("VipsOperation",
pre_8_11 ? "heifload_buffer" : "heifload_source") ==
0 ||
vips_type_find("VipsOperation",
pre_8_11 ? "heifsave_buffer" : "heifsave_target") ==
0) {
SUCCEED("no avif support, skipping test");
return;
}

auto test_image = fixtures->input_avif;
auto params_75 = "w=320&h=240&fit=cover&q=75";
auto params_95 = "w=320&h=240&fit=cover&q=95";

std::string buffer_75 =
process_file<std::string>(test_image, params_75);

std::string buffer_95 =
process_file<std::string>(test_image, params_95);

CHECK(buffer_75.size() < buffer_95.size());
}

SECTION("tiff quality") {
if (vips_type_find("VipsOperation",
pre_8_11 ? "tiffload_buffer" : "tiffload_source") ==
Expand Down Expand Up @@ -384,6 +435,22 @@ TEST_CASE("metadata", "[stream]") {
CHECK_THAT(buffer, Contains(R"("format":"webp")"));
}

SECTION("avif") {
if (vips_type_find("VipsOperation",
pre_8_11 ? "heifload_buffer" : "heifload_source") ==
0) {
SUCCEED("no avif support, skipping test");
return;
}

auto test_image = fixtures->input_avif;
auto params = "output=json";

std::string buffer = process_file<std::string>(test_image, params);

CHECK_THAT(buffer, Contains(R"("format":"heif")"));
}

SECTION("tiff") {
if (vips_type_find("VipsOperation",
pre_8_11 ? "tiffload_buffer" : "tiffload_source") ==
Expand Down Expand Up @@ -430,7 +497,7 @@ TEST_CASE("metadata", "[stream]") {
CHECK_THAT(buffer, Contains(R"("format":"pdf")"));
}

SECTION("heif") {
SECTION("heic") {
if (vips_type_find("VipsOperation",
pre_8_11 ? "heifload_buffer" : "heifload_source") ==
0) {
Expand Down
File renamed without changes.

0 comments on commit ac3e355

Please sign in to comment.