mirror of
https://github.com/google/sandboxed-api.git
synced 2024-03-22 13:11:30 +08:00
Init guetzli sandbox
This commit is contained in:
parent
db0dfbb21f
commit
dc8cf90cb3
65
oss-internship-2020/guetzli/BUILD.bazel
Normal file
65
oss-internship-2020/guetzli/BUILD.bazel
Normal file
|
@ -0,0 +1,65 @@
|
|||
load("@rules_cc//cc:defs.bzl", "cc_proto_library")
|
||||
load("@rules_proto//proto:defs.bzl", "proto_library")
|
||||
load(
|
||||
"@com_google_sandboxed_api//sandboxed_api/bazel:proto.bzl",
|
||||
"sapi_proto_library",
|
||||
)
|
||||
load(
|
||||
"@com_google_sandboxed_api//sandboxed_api/bazel:sapi.bzl",
|
||||
"sapi_library",
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "guetzli_wrapper",
|
||||
srcs = ["guetzli_entry_points.cc"],
|
||||
hdrs = ["guetzli_entry_points.h"],
|
||||
deps = [
|
||||
"@guetzli//:guetzli_lib",
|
||||
"@com_google_sandboxed_api//sandboxed_api:lenval_core",
|
||||
"@com_google_sandboxed_api//sandboxed_api:vars",
|
||||
#"@com_google_sandboxed_api//sandboxed_api/sandbox2/util:temp_file", visibility error
|
||||
"@png_archive//:png"
|
||||
],
|
||||
visibility = ["//visibility:public"]
|
||||
)
|
||||
|
||||
sapi_library(
|
||||
name = "guetzli_sapi",
|
||||
#srcs = ["guetzli_transaction.cc"], // Error when try to place definitions insde .cc file
|
||||
hdrs = ["guetzli_sandbox.h", "guetzli_transaction.h"],
|
||||
functions = [
|
||||
"ProcessJPEGString",
|
||||
"ProcessRGBData",
|
||||
"ButteraugliScoreQuality",
|
||||
"ReadPng",
|
||||
"ReadJpegData",
|
||||
"ReadDataFromFd",
|
||||
"WriteDataToFd"
|
||||
],
|
||||
input_files = ["guetzli_entry_points.h"],
|
||||
lib = ":guetzli_wrapper",
|
||||
lib_name = "Guetzli",
|
||||
visibility = ["//visibility:public"],
|
||||
namespace = "guetzli::sandbox"
|
||||
)
|
||||
|
||||
# cc_library(
|
||||
# name = "guetzli_sapi_transaction",
|
||||
# #srcs = ["guetzli_transaction.cc"],
|
||||
# hdrs = ["guetzli_transaction.h"],
|
||||
# deps = [
|
||||
# ":guetzli_sapi"
|
||||
# ],
|
||||
# visibility = ["//visibility:public"]
|
||||
# )
|
||||
|
||||
cc_binary(
|
||||
name="guetzli_sandboxed",
|
||||
srcs=["guetzli_sandboxed.cc"],
|
||||
includes = ["."],
|
||||
visibility= [ "//visibility:public" ],
|
||||
deps = [
|
||||
#":guetzli_sapi_transaction"
|
||||
":guetzli_sapi"
|
||||
]
|
||||
)
|
79
oss-internship-2020/guetzli/WORKSPACE
Normal file
79
oss-internship-2020/guetzli/WORKSPACE
Normal file
|
@ -0,0 +1,79 @@
|
|||
# Copyright 2020 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
workspace(name = "guetzli_sandboxed")
|
||||
|
||||
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
|
||||
load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
|
||||
|
||||
# Include the Sandboxed API dependency if it does not already exist in this
|
||||
# project. This ensures that this workspace plays well with other external
|
||||
# dependencies that might use Sandboxed API.
|
||||
maybe(
|
||||
git_repository,
|
||||
name = "com_google_sandboxed_api",
|
||||
# This example depends on the latest master. In an embedding project, it
|
||||
# is advisable to pin Sandboxed API to a specific revision instead.
|
||||
# commit = "ba47adc21d4c9bc316f3c7c32b0faaef952c111e", # 2020-05-15
|
||||
branch = "master",
|
||||
remote = "https://github.com/google/sandboxed-api.git",
|
||||
)
|
||||
|
||||
# From here on, Sandboxed API files are available. The statements below setup
|
||||
# transitive dependencies such as Abseil. Like above, those will only be
|
||||
# included if they don't already exist in the project.
|
||||
load(
|
||||
"@com_google_sandboxed_api//sandboxed_api/bazel:sapi_deps.bzl",
|
||||
"sapi_deps",
|
||||
)
|
||||
|
||||
sapi_deps()
|
||||
|
||||
# Need to separately setup Protobuf dependencies in order for the build rules
|
||||
# to work.
|
||||
load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps")
|
||||
|
||||
protobuf_deps()
|
||||
|
||||
maybe(
|
||||
git_repository,
|
||||
name = "guetzli",
|
||||
remote = "https://github.com/google/guetzli.git",
|
||||
branch = "master"
|
||||
)
|
||||
|
||||
maybe(
|
||||
git_repository,
|
||||
name = "googletest",
|
||||
remote = "https://github.com/google/googletest",
|
||||
tag = "release-1.10.0"
|
||||
)
|
||||
|
||||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||
|
||||
http_archive(
|
||||
name = "png_archive",
|
||||
build_file = "png.BUILD",
|
||||
sha256 = "a941dc09ca00148fe7aaf4ecdd6a67579c293678ed1e1cf633b5ffc02f4f8cf7",
|
||||
strip_prefix = "libpng-1.2.57",
|
||||
url = "http://github.com/glennrp/libpng/archive/v1.2.57.zip",
|
||||
)
|
||||
|
||||
http_archive(
|
||||
name = "zlib_archive",
|
||||
build_file = "zlib.BUILD",
|
||||
sha256 = "8d7e9f698ce48787b6e1c67e6bff79e487303e66077e25cb9784ac8835978017",
|
||||
strip_prefix = "zlib-1.2.10",
|
||||
url = "http://zlib.net/fossils/zlib-1.2.10.tar.gz",
|
||||
)
|
33
oss-internship-2020/guetzli/external/png.BUILD
vendored
Normal file
33
oss-internship-2020/guetzli/external/png.BUILD
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
# Description:
|
||||
# libpng is the official PNG reference library.
|
||||
|
||||
licenses(["notice"]) # BSD/MIT-like license
|
||||
|
||||
cc_library(
|
||||
name = "png",
|
||||
srcs = [
|
||||
"png.c",
|
||||
"pngerror.c",
|
||||
"pngget.c",
|
||||
"pngmem.c",
|
||||
"pngpread.c",
|
||||
"pngread.c",
|
||||
"pngrio.c",
|
||||
"pngrtran.c",
|
||||
"pngrutil.c",
|
||||
"pngset.c",
|
||||
"pngtrans.c",
|
||||
"pngwio.c",
|
||||
"pngwrite.c",
|
||||
"pngwtran.c",
|
||||
"pngwutil.c",
|
||||
],
|
||||
hdrs = [
|
||||
"png.h",
|
||||
"pngconf.h",
|
||||
],
|
||||
includes = ["."],
|
||||
linkopts = ["-lm"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = ["@zlib_archive//:zlib"],
|
||||
)
|
36
oss-internship-2020/guetzli/external/zlib.BUILD
vendored
Normal file
36
oss-internship-2020/guetzli/external/zlib.BUILD
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"]) # BSD/MIT-like license (for zlib)
|
||||
|
||||
cc_library(
|
||||
name = "zlib",
|
||||
srcs = [
|
||||
"adler32.c",
|
||||
"compress.c",
|
||||
"crc32.c",
|
||||
"crc32.h",
|
||||
"deflate.c",
|
||||
"deflate.h",
|
||||
"gzclose.c",
|
||||
"gzguts.h",
|
||||
"gzlib.c",
|
||||
"gzread.c",
|
||||
"gzwrite.c",
|
||||
"infback.c",
|
||||
"inffast.c",
|
||||
"inffast.h",
|
||||
"inffixed.h",
|
||||
"inflate.c",
|
||||
"inflate.h",
|
||||
"inftrees.c",
|
||||
"inftrees.h",
|
||||
"trees.c",
|
||||
"trees.h",
|
||||
"uncompr.c",
|
||||
"zconf.h",
|
||||
"zutil.c",
|
||||
"zutil.h",
|
||||
],
|
||||
hdrs = ["zlib.h"],
|
||||
includes = ["."],
|
||||
)
|
245
oss-internship-2020/guetzli/guetzli_entry_points.cc
Normal file
245
oss-internship-2020/guetzli/guetzli_entry_points.cc
Normal file
|
@ -0,0 +1,245 @@
|
|||
#include "guetzli/jpeg_data_reader.h"
|
||||
#include "guetzli/quality.h"
|
||||
#include "guetzli_entry_points.h"
|
||||
#include "png.h"
|
||||
#include "sandboxed_api/sandbox2/util/fileops.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
inline uint8_t BlendOnBlack(const uint8_t val, const uint8_t alpha) {
|
||||
return (static_cast<int>(val) * static_cast<int>(alpha) + 128) / 255;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void CopyMemoryToLenVal(const T* data, size_t size,
|
||||
sapi::LenValStruct* out_data) {
|
||||
free(out_data->data); // Not sure about this
|
||||
out_data->size = size;
|
||||
T* new_out = static_cast<T*>(malloc(size));
|
||||
memcpy(new_out, data, size);
|
||||
out_data->data = new_out;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" bool ProcessJPEGString(const guetzli::Params* params,
|
||||
int verbose,
|
||||
sapi::LenValStruct* in_data,
|
||||
sapi::LenValStruct* out_data)
|
||||
{
|
||||
std::string in_data_temp(static_cast<const char*>(in_data->data),
|
||||
in_data->size);
|
||||
|
||||
guetzli::ProcessStats stats;
|
||||
if (verbose > 0) {
|
||||
stats.debug_output_file = stderr;
|
||||
}
|
||||
|
||||
std::string temp_out = "";
|
||||
auto result = guetzli::Process(*params, &stats, in_data_temp, &temp_out);
|
||||
|
||||
if (result) {
|
||||
CopyMemoryToLenVal(temp_out.data(), temp_out.size(), out_data);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
extern "C" bool ProcessRGBData(const guetzli::Params* params,
|
||||
int verbose,
|
||||
sapi::LenValStruct* rgb,
|
||||
int w, int h,
|
||||
sapi::LenValStruct* out_data)
|
||||
{
|
||||
std::vector<uint8_t> in_data_temp;
|
||||
in_data_temp.reserve(rgb->size);
|
||||
|
||||
auto* rgb_data = static_cast<uint8_t*>(rgb->data);
|
||||
std::copy(rgb_data, rgb_data + rgb->size, std::back_inserter(in_data_temp));
|
||||
|
||||
guetzli::ProcessStats stats;
|
||||
if (verbose > 0) {
|
||||
stats.debug_output_file = stderr;
|
||||
}
|
||||
|
||||
std::string temp_out = "";
|
||||
auto result =
|
||||
guetzli::Process(*params, &stats, in_data_temp, w, h, &temp_out);
|
||||
|
||||
//TODO: Move shared part of the code to another function
|
||||
if (result) {
|
||||
CopyMemoryToLenVal(temp_out.data(), temp_out.size(), out_data);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
extern "C" bool ReadPng(sapi::LenValStruct* in_data,
|
||||
int* xsize, int* ysize,
|
||||
sapi::LenValStruct* rgb_out)
|
||||
{
|
||||
std::string data(static_cast<const char*>(in_data->data), in_data->size);
|
||||
std::vector<uint8_t> rgb;
|
||||
|
||||
png_structp png_ptr =
|
||||
png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
|
||||
if (!png_ptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
png_infop info_ptr = png_create_info_struct(png_ptr);
|
||||
if (!info_ptr) {
|
||||
png_destroy_read_struct(&png_ptr, nullptr, nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (setjmp(png_jmpbuf(png_ptr)) != 0) {
|
||||
// Ok we are here because of the setjmp.
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::istringstream memstream(data, std::ios::in | std::ios::binary);
|
||||
png_set_read_fn(png_ptr, static_cast<void*>(&memstream), [](png_structp png_ptr, png_bytep outBytes, png_size_t byteCountToRead) {
|
||||
std::istringstream& memstream = *static_cast<std::istringstream*>(png_get_io_ptr(png_ptr));
|
||||
|
||||
memstream.read(reinterpret_cast<char*>(outBytes), byteCountToRead);
|
||||
|
||||
if (memstream.eof()) png_error(png_ptr, "unexpected end of data");
|
||||
if (memstream.fail()) png_error(png_ptr, "read from memory error");
|
||||
});
|
||||
|
||||
// The png_transforms flags are as follows:
|
||||
// packing == convert 1,2,4 bit images,
|
||||
// strip == 16 -> 8 bits / channel,
|
||||
// shift == use sBIT dynamics, and
|
||||
// expand == palettes -> rgb, grayscale -> 8 bit images, tRNS -> alpha.
|
||||
const unsigned int png_transforms =
|
||||
PNG_TRANSFORM_PACKING | PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_STRIP_16;
|
||||
|
||||
png_read_png(png_ptr, info_ptr, png_transforms, nullptr);
|
||||
|
||||
png_bytep* row_pointers = png_get_rows(png_ptr, info_ptr);
|
||||
|
||||
*xsize = png_get_image_width(png_ptr, info_ptr);
|
||||
*ysize = png_get_image_height(png_ptr, info_ptr);
|
||||
rgb.resize(3 * (*xsize) * (*ysize));
|
||||
|
||||
const int components = png_get_channels(png_ptr, info_ptr);
|
||||
switch (components) {
|
||||
case 1: {
|
||||
// GRAYSCALE
|
||||
for (int y = 0; y < *ysize; ++y) {
|
||||
const uint8_t* row_in = row_pointers[y];
|
||||
uint8_t* row_out = &(rgb)[3 * y * (*xsize)];
|
||||
for (int x = 0; x < *xsize; ++x) {
|
||||
const uint8_t gray = row_in[x];
|
||||
row_out[3 * x + 0] = gray;
|
||||
row_out[3 * x + 1] = gray;
|
||||
row_out[3 * x + 2] = gray;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
// GRAYSCALE + ALPHA
|
||||
for (int y = 0; y < *ysize; ++y) {
|
||||
const uint8_t* row_in = row_pointers[y];
|
||||
uint8_t* row_out = &(rgb)[3 * y * (*xsize)];
|
||||
for (int x = 0; x < *xsize; ++x) {
|
||||
const uint8_t gray = BlendOnBlack(row_in[2 * x], row_in[2 * x + 1]);
|
||||
row_out[3 * x + 0] = gray;
|
||||
row_out[3 * x + 1] = gray;
|
||||
row_out[3 * x + 2] = gray;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
// RGB
|
||||
for (int y = 0; y < *ysize; ++y) {
|
||||
const uint8_t* row_in = row_pointers[y];
|
||||
uint8_t* row_out = &(rgb)[3 * y * (*xsize)];
|
||||
memcpy(row_out, row_in, 3 * (*xsize));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
// RGBA
|
||||
for (int y = 0; y < *ysize; ++y) {
|
||||
const uint8_t* row_in = row_pointers[y];
|
||||
uint8_t* row_out = &(rgb)[3 * y * (*xsize)];
|
||||
for (int x = 0; x < *xsize; ++x) {
|
||||
const uint8_t alpha = row_in[4 * x + 3];
|
||||
row_out[3 * x + 0] = BlendOnBlack(row_in[4 * x + 0], alpha);
|
||||
row_out[3 * x + 1] = BlendOnBlack(row_in[4 * x + 1], alpha);
|
||||
row_out[3 * x + 2] = BlendOnBlack(row_in[4 * x + 2], alpha);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
|
||||
return false;
|
||||
}
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
|
||||
|
||||
CopyMemoryToLenVal(rgb.data(), rgb.size(), rgb_out);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" bool ReadJpegData(sapi::LenValStruct* in_data,
|
||||
int mode,
|
||||
int* xsize, int* ysize)
|
||||
{
|
||||
std::string data(static_cast<const char*>(in_data->data), in_data->size);
|
||||
guetzli::JPEGData jpg;
|
||||
|
||||
auto result = guetzli::ReadJpeg(data,
|
||||
static_cast<guetzli::JpegReadMode>(mode), &jpg);
|
||||
|
||||
if (result) {
|
||||
*xsize = jpg.width;
|
||||
*ysize = jpg.height;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
extern "C" double ButteraugliScoreQuality(double quality) {
|
||||
return guetzli::ButteraugliScoreForQuality(quality);
|
||||
}
|
||||
|
||||
extern "C" bool ReadDataFromFd(int fd, sapi::LenValStruct* out_data) {
|
||||
struct stat file_data;
|
||||
auto status = fstat(fd, &file_data);
|
||||
|
||||
if (status < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto fsize = file_data.st_size;
|
||||
|
||||
std::unique_ptr<char[]> buf(new char[fsize]);
|
||||
status = read(fd, buf.get(), fsize);
|
||||
|
||||
if (status < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CopyMemoryToLenVal(buf.get(), fsize, out_data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" bool WriteDataToFd(int fd, sapi::LenValStruct* data) {
|
||||
return sandbox2::file_util::fileops::WriteToFD(fd,
|
||||
static_cast<const char*>(data->data), data->size);
|
||||
}
|
29
oss-internship-2020/guetzli/guetzli_entry_points.h
Normal file
29
oss-internship-2020/guetzli/guetzli_entry_points.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
#include "guetzli/processor.h"
|
||||
#include "sandboxed_api/lenval_core.h"
|
||||
#include "sandboxed_api/vars.h"
|
||||
|
||||
extern "C" bool ProcessJPEGString(const guetzli::Params* params,
|
||||
int verbose,
|
||||
sapi::LenValStruct* in_data,
|
||||
sapi::LenValStruct* out_data);
|
||||
|
||||
extern "C" bool ProcessRGBData(const guetzli::Params* params,
|
||||
int verbose,
|
||||
sapi::LenValStruct* rgb,
|
||||
int w, int h,
|
||||
sapi::LenValStruct* out_data);
|
||||
|
||||
extern "C" bool ReadPng(sapi::LenValStruct* in_data,
|
||||
int* xsize, int* ysize,
|
||||
sapi::LenValStruct* rgb_out);
|
||||
|
||||
extern "C" bool ReadJpegData(sapi::LenValStruct* in_data,
|
||||
int mode, int* xsize, int* ysize);
|
||||
|
||||
extern "C" double ButteraugliScoreQuality(double quality);
|
||||
|
||||
extern "C" bool ReadDataFromFd(int fd, sapi::LenValStruct* out_data);
|
||||
|
||||
extern "C" bool WriteDataToFd(int fd, sapi::LenValStruct* data);
|
36
oss-internship-2020/guetzli/guetzli_sandbox.h
Normal file
36
oss-internship-2020/guetzli/guetzli_sandbox.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
#pragma once
|
||||
|
||||
#include <libgen.h>
|
||||
#include <syscall.h>
|
||||
|
||||
#include "guetzli_sapi.sapi.h"
|
||||
#include "sandboxed_api/sandbox2/policy.h"
|
||||
#include "sandboxed_api/sandbox2/policybuilder.h"
|
||||
#include "sandboxed_api/util/flag.h"
|
||||
|
||||
namespace guetzli {
|
||||
namespace sandbox {
|
||||
|
||||
class GuetzliSapiSandbox : public GuetzliSandbox {
|
||||
public:
|
||||
std::unique_ptr<sandbox2::Policy> ModifyPolicy(
|
||||
sandbox2::PolicyBuilder*) override {
|
||||
|
||||
return sandbox2::PolicyBuilder()
|
||||
.AllowStaticStartup()
|
||||
.AllowRead()
|
||||
.AllowSystemMalloc()
|
||||
.AllowWrite()
|
||||
.AllowExit()
|
||||
.AllowStat()
|
||||
.AllowSyscalls({
|
||||
__NR_futex,
|
||||
__NR_close,
|
||||
__NR_recvmsg // Seems like this one needed to work with remote file descriptors
|
||||
})
|
||||
.BuildOrDie();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace sandbox
|
||||
} // namespace guetzli
|
160
oss-internship-2020/guetzli/guetzli_sandboxed.cc
Normal file
160
oss-internship-2020/guetzli/guetzli_sandboxed.cc
Normal file
|
@ -0,0 +1,160 @@
|
|||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "guetzli_transaction.h"
|
||||
#include "sandboxed_api/sandbox2/util/fileops.h"
|
||||
#include "sandboxed_api/util/statusor.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr int kDefaultJPEGQuality = 95;
|
||||
constexpr int kDefaultMemlimitMB = 6000; // in MB
|
||||
//constexpr absl::string_view kMktempSuffix = "XXXXXX";
|
||||
|
||||
// sapi::StatusOr<std::pair<std::string, int>> CreateNamedTempFile(
|
||||
// absl::string_view prefix) {
|
||||
// std::string name_template = absl::StrCat(prefix, kMktempSuffix);
|
||||
// int fd = mkstemp(&name_template[0]);
|
||||
// if (fd < 0) {
|
||||
// return absl::UnknownError("Error creating temp file");
|
||||
// }
|
||||
// return std::pair<std::string, int>{std::move(name_template), fd};
|
||||
// }
|
||||
|
||||
void TerminateHandler() {
|
||||
fprintf(stderr, "Unhandled exception. Most likely insufficient memory available.\n"
|
||||
"Make sure that there is 300MB/MPix of memory available.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void Usage() {
|
||||
fprintf(stderr,
|
||||
"Guetzli JPEG compressor. Usage: \n"
|
||||
"guetzli [flags] input_filename output_filename\n"
|
||||
"\n"
|
||||
"Flags:\n"
|
||||
" --verbose - Print a verbose trace of all attempts to standard output.\n"
|
||||
" --quality Q - Visual quality to aim for, expressed as a JPEG quality value.\n"
|
||||
" Default value is %d.\n"
|
||||
" --memlimit M - Memory limit in MB. Guetzli will fail if unable to stay under\n"
|
||||
" the limit. Default limit is %d MB.\n"
|
||||
" --nomemlimit - Do not limit memory usage.\n", kDefaultJPEGQuality, kDefaultMemlimitMB);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, const char** argv) {
|
||||
std::set_terminate(TerminateHandler);
|
||||
|
||||
int verbose = 0;
|
||||
int quality = kDefaultJPEGQuality;
|
||||
int memlimit_mb = kDefaultMemlimitMB;
|
||||
|
||||
int opt_idx = 1;
|
||||
for(;opt_idx < argc;opt_idx++) {
|
||||
if (strnlen(argv[opt_idx], 2) < 2 || argv[opt_idx][0] != '-' || argv[opt_idx][1] != '-')
|
||||
break;
|
||||
|
||||
if (!strcmp(argv[opt_idx], "--verbose")) {
|
||||
verbose = 1;
|
||||
} else if (!strcmp(argv[opt_idx], "--quality")) {
|
||||
opt_idx++;
|
||||
if (opt_idx >= argc)
|
||||
Usage();
|
||||
quality = atoi(argv[opt_idx]);
|
||||
} else if (!strcmp(argv[opt_idx], "--memlimit")) {
|
||||
opt_idx++;
|
||||
if (opt_idx >= argc)
|
||||
Usage();
|
||||
memlimit_mb = atoi(argv[opt_idx]);
|
||||
} else if (!strcmp(argv[opt_idx], "--nomemlimit")) {
|
||||
memlimit_mb = -1;
|
||||
} else if (!strcmp(argv[opt_idx], "--")) {
|
||||
opt_idx++;
|
||||
break;
|
||||
} else {
|
||||
fprintf(stderr, "Unknown commandline flag: %s\n", argv[opt_idx]);
|
||||
Usage();
|
||||
}
|
||||
}
|
||||
|
||||
if (argc - opt_idx != 2) {
|
||||
Usage();
|
||||
}
|
||||
|
||||
sandbox2::file_util::fileops::FDCloser in_fd_closer(
|
||||
open(argv[opt_idx], O_RDONLY));
|
||||
|
||||
if (in_fd_closer.get() < 0) {
|
||||
fprintf(stderr, "Can't open input file: %s\n", argv[opt_idx]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// auto out_temp_file = CreateNamedTempFile("/tmp/" + std::string(argv[opt_idx + 1]));
|
||||
// if (!out_temp_file.ok()) {
|
||||
// fprintf(stderr, "Can't create temporary output file: %s\n",
|
||||
// argv[opt_idx + 1]);
|
||||
// return 1;
|
||||
// }
|
||||
// sandbox2::file_util::fileops::FDCloser out_fd_closer(
|
||||
// out_temp_file.value().second);
|
||||
|
||||
// if (unlink(out_temp_file.value().first.c_str()) < 0) {
|
||||
// fprintf(stderr, "Error unlinking temp out file: %s\n",
|
||||
// out_temp_file.value().first.c_str());
|
||||
// return 1;
|
||||
// }
|
||||
|
||||
sandbox2::file_util::fileops::FDCloser out_fd_closer(
|
||||
open(".", O_TMPFILE | O_RDWR, S_IRUSR | S_IWUSR));
|
||||
|
||||
if (out_fd_closer.get() < 0) {
|
||||
fprintf(stderr, "Can't create temporary output file: %s\n", argv[opt_idx]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// sandbox2::file_util::fileops::FDCloser out_fd_closer(open(argv[opt_idx + 1],
|
||||
// O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP));
|
||||
|
||||
// if (out_fd_closer.get() < 0) {
|
||||
// fprintf(stderr, "Can't open output file: %s\n", argv[opt_idx + 1]);
|
||||
// return 1;
|
||||
// }
|
||||
|
||||
guetzli::sandbox::TransactionParams params = {
|
||||
in_fd_closer.get(),
|
||||
out_fd_closer.get(),
|
||||
verbose,
|
||||
quality,
|
||||
memlimit_mb
|
||||
};
|
||||
|
||||
guetzli::sandbox::GuetzliTransaction transaction(std::move(params));
|
||||
auto result = transaction.Run();
|
||||
|
||||
if (result.ok()) {
|
||||
if (access(argv[opt_idx + 1], F_OK) != -1) {
|
||||
if (remove(argv[opt_idx + 1]) < 0) {
|
||||
fprintf(stderr, "Error deleting existing output file: %s\n",
|
||||
argv[opt_idx + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
std::stringstream path;
|
||||
path << "/proc/self/fd/" << out_fd_closer.get();
|
||||
linkat(AT_FDCWD, path.str().c_str(), AT_FDCWD, argv[opt_idx + 1],
|
||||
AT_SYMLINK_FOLLOW);
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "%s\n", result.ToString().c_str()); // Use cerr instead ?
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
160
oss-internship-2020/guetzli/guetzli_transaction.cc
Normal file
160
oss-internship-2020/guetzli/guetzli_transaction.cc
Normal file
|
@ -0,0 +1,160 @@
|
|||
#include "guetzli_transaction.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace guetzli {
|
||||
namespace sandbox {
|
||||
|
||||
absl::Status GuetzliTransaction::Init() {
|
||||
SAPI_RETURN_IF_ERROR(sandbox()->TransferToSandboxee(&in_fd_));
|
||||
SAPI_RETURN_IF_ERROR(sandbox()->TransferToSandboxee(&out_fd_));
|
||||
|
||||
if (in_fd_.GetRemoteFd() < 0) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Error receiving remote FD: remote input fd is set to -1");
|
||||
}
|
||||
if (out_fd_.GetRemoteFd() < 0) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Error receiving remote FD: remote output fd is set to -1");
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status GuetzliTransaction::ProcessPng(GuetzliAPi* api,
|
||||
sapi::v::Struct<Params>* params,
|
||||
sapi::v::LenVal* input,
|
||||
sapi::v::LenVal* output) const {
|
||||
sapi::v::Int xsize;
|
||||
sapi::v::Int ysize;
|
||||
sapi::v::LenVal rgb_in(0);
|
||||
|
||||
auto read_result = api->ReadPng(input->PtrBefore(), xsize.PtrBoth(),
|
||||
ysize.PtrBoth(), rgb_in.PtrBoth());
|
||||
|
||||
if (!read_result.value_or(false)) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Error reading PNG data from input file"
|
||||
);
|
||||
}
|
||||
|
||||
double pixels = static_cast<double>(xsize.GetValue()) * ysize.GetValue();
|
||||
if (params_.memlimit_mb != -1
|
||||
&& (pixels * kBytesPerPixel / (1 << 20) > params_.memlimit_mb
|
||||
|| params_.memlimit_mb < kLowestMemusageMB)) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Memory limit would be exceeded"
|
||||
);
|
||||
}
|
||||
|
||||
auto result = api->ProcessRGBData(params->PtrBefore(), params_.verbose,
|
||||
rgb_in.PtrBefore(), xsize.GetValue(),
|
||||
ysize.GetValue(), output->PtrBoth());
|
||||
if (!result.value_or(false)) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Guetzli processing failed"
|
||||
);
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status GuetzliTransaction::ProcessJpeg(GuetzliApi* api,
|
||||
sapi::v::Struct<Params>* params,
|
||||
sapi::v::LenVal* input,
|
||||
sapi::v::LenVal* output) const {
|
||||
::sapi::v::Int xsize;
|
||||
::sapi::v::Int ysize;
|
||||
auto read_result = api->ReadJpegData(input->PtrBefore(), 0, xsize.PtrBoth(),
|
||||
ysize.PtrBoth());
|
||||
|
||||
if (!read_result.value_or(false)) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Error reading JPG data from input file"
|
||||
);
|
||||
}
|
||||
|
||||
double pixels = static_cast<double>(xsize.GetValue()) * ysize.GetValue();
|
||||
if (params_.memlimit_mb != -1
|
||||
&& (pixels * kBytesPerPixel / (1 << 20) > params_.memlimit_mb
|
||||
|| params_.memlimit_mb < kLowestMemusageMB)) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Memory limit would be exceeded"
|
||||
);
|
||||
}
|
||||
|
||||
auto result = api->ProcessJPEGString(params->PtrBefore(), params_.verbose,
|
||||
input->PtrBefore(), output->PtrBoth());
|
||||
|
||||
if (!result.value_or(false)) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Guetzli processing failed"
|
||||
);
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status GuetzliTransaction::Main() {
|
||||
GuetzliApi api(sandbox());
|
||||
|
||||
sapi::v::LenVal input(0);
|
||||
sapi::v::LenVal output(0);
|
||||
sapi::v::Struct<Params> params;
|
||||
|
||||
auto read_result = api.ReadDataFromFd(in_fd_.GetRemoteFd(), input.PtrBoth());
|
||||
|
||||
if (!read_result.value_or(false)) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Error reading data inside sandbox"
|
||||
);
|
||||
}
|
||||
|
||||
auto score_quality_result = api.ButteraugliScoreQuality(params_.quality);
|
||||
|
||||
if (!score_quality_result.ok()) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Error calculating butteraugli score"
|
||||
);
|
||||
}
|
||||
|
||||
params.mutable_data()->butteraugli_target = score_quality_result.value();
|
||||
|
||||
static const unsigned char kPNGMagicBytes[] = {
|
||||
0x89, 'P', 'N', 'G', '\r', '\n', 0x1a, '\n',
|
||||
};
|
||||
|
||||
if (input.GetDataSize() >= 8 &&
|
||||
memcmp(input.GetData(), kPNGMagicBytes, sizeof(kPNGMagicBytes)) == 0) {
|
||||
auto process_status = ProcessPng(&api, ¶ms, &input, &output);
|
||||
|
||||
if (!process_status.ok()) {
|
||||
return process_status;
|
||||
}
|
||||
} else {
|
||||
auto process_status = ProcessJpeg(&api, ¶ms, &input, &output);
|
||||
|
||||
if (!process_status.ok()) {
|
||||
return process_status;
|
||||
}
|
||||
}
|
||||
|
||||
auto write_result = api.WriteDataToFd(out_fd_.GetRemoteFd(),
|
||||
output.PtrBefore());
|
||||
|
||||
if (!write_result.value_or(false)) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Error writing file inside sandbox"
|
||||
);
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
time_t GuetzliTransaction::CalculateTimeLimitFromImageSize(
|
||||
uint64_t pixels) const {
|
||||
return (pixels / kMpixPixels + 5) * 60;
|
||||
}
|
||||
|
||||
} // namespace sandbox
|
||||
} // namespace guetzli
|
216
oss-internship-2020/guetzli/guetzli_transaction.h
Normal file
216
oss-internship-2020/guetzli/guetzli_transaction.h
Normal file
|
@ -0,0 +1,216 @@
|
|||
#pragma once
|
||||
|
||||
#include <libgen.h>
|
||||
#include <syscall.h>
|
||||
|
||||
#include "guetzli_sandbox.h"
|
||||
#include "sandboxed_api/transaction.h"
|
||||
#include "sandboxed_api/vars.h"
|
||||
|
||||
namespace guetzli {
|
||||
namespace sandbox {
|
||||
|
||||
constexpr int kDefaultTransactionRetryCount = 1;
|
||||
constexpr uint64_t kMpixPixels = 1'000'000;
|
||||
|
||||
constexpr int kBytesPerPixel = 350;
|
||||
constexpr int kLowestMemusageMB = 100; // in MB
|
||||
|
||||
struct TransactionParams {
|
||||
int in_fd;
|
||||
int out_fd;
|
||||
int verbose;
|
||||
int quality;
|
||||
int memlimit_mb;
|
||||
};
|
||||
|
||||
//Add optional time limit/retry count as a constructors arguments
|
||||
//Use differenet status errors
|
||||
class GuetzliTransaction : public sapi::Transaction {
|
||||
public:
|
||||
GuetzliTransaction(TransactionParams&& params)
|
||||
: sapi::Transaction(std::make_unique<GuetzliSapiSandbox>())
|
||||
, params_(std::move(params))
|
||||
, in_fd_(params_.in_fd)
|
||||
, out_fd_(params_.out_fd)
|
||||
{
|
||||
sapi::Transaction::set_retry_count(kDefaultTransactionRetryCount);
|
||||
sapi::Transaction::SetTimeLimit(0);
|
||||
}
|
||||
|
||||
private:
|
||||
absl::Status Init() override;
|
||||
absl::Status Main() final;
|
||||
|
||||
absl::Status ProcessPng(GuetzliApi* api,
|
||||
sapi::v::Struct<Params>* params,
|
||||
sapi::v::LenVal* input,
|
||||
sapi::v::LenVal* output) const;
|
||||
|
||||
absl::Status ProcessJpeg(GuetzliApi* api,
|
||||
sapi::v::Struct<Params>* params,
|
||||
sapi::v::LenVal* input,
|
||||
sapi::v::LenVal* output) const;
|
||||
|
||||
// As guetzli takes roughly 1 minute of CPU per 1 MPix we need to calculate
|
||||
// approximate time for transaction to complete
|
||||
time_t CalculateTimeLimitFromImageSize(uint64_t pixels) const;
|
||||
|
||||
const TransactionParams params_;
|
||||
sapi::v::Fd in_fd_;
|
||||
sapi::v::Fd out_fd_;
|
||||
};
|
||||
|
||||
absl::Status GuetzliTransaction::Init() {
|
||||
SAPI_RETURN_IF_ERROR(sandbox()->TransferToSandboxee(&in_fd_));
|
||||
SAPI_RETURN_IF_ERROR(sandbox()->TransferToSandboxee(&out_fd_));
|
||||
|
||||
if (in_fd_.GetRemoteFd() < 0) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Error receiving remote FD: remote input fd is set to -1");
|
||||
}
|
||||
if (out_fd_.GetRemoteFd() < 0) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Error receiving remote FD: remote output fd is set to -1");
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status GuetzliTransaction::ProcessPng(GuetzliApi* api,
|
||||
sapi::v::Struct<Params>* params,
|
||||
sapi::v::LenVal* input,
|
||||
sapi::v::LenVal* output) const {
|
||||
sapi::v::Int xsize;
|
||||
sapi::v::Int ysize;
|
||||
sapi::v::LenVal rgb_in(0);
|
||||
|
||||
auto read_result = api->ReadPng(input->PtrBefore(), xsize.PtrBoth(),
|
||||
ysize.PtrBoth(), rgb_in.PtrBoth());
|
||||
|
||||
if (!read_result.value_or(false)) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Error reading PNG data from input file"
|
||||
);
|
||||
}
|
||||
|
||||
double pixels = static_cast<double>(xsize.GetValue()) * ysize.GetValue();
|
||||
if (params_.memlimit_mb != -1
|
||||
&& (pixels * kBytesPerPixel / (1 << 20) > params_.memlimit_mb
|
||||
|| params_.memlimit_mb < kLowestMemusageMB)) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Memory limit would be exceeded"
|
||||
);
|
||||
}
|
||||
|
||||
auto result = api->ProcessRGBData(params->PtrBefore(), params_.verbose,
|
||||
rgb_in.PtrBefore(), xsize.GetValue(),
|
||||
ysize.GetValue(), output->PtrBoth());
|
||||
if (!result.value_or(false)) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Guetzli processing failed"
|
||||
);
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status GuetzliTransaction::ProcessJpeg(GuetzliApi* api,
|
||||
sapi::v::Struct<Params>* params,
|
||||
sapi::v::LenVal* input,
|
||||
sapi::v::LenVal* output) const {
|
||||
sapi::v::Int xsize;
|
||||
sapi::v::Int ysize;
|
||||
auto read_result = api->ReadJpegData(input->PtrBefore(), 0, xsize.PtrBoth(),
|
||||
ysize.PtrBoth());
|
||||
|
||||
if (!read_result.value_or(false)) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Error reading JPG data from input file"
|
||||
);
|
||||
}
|
||||
|
||||
double pixels = static_cast<double>(xsize.GetValue()) * ysize.GetValue();
|
||||
if (params_.memlimit_mb != -1
|
||||
&& (pixels * kBytesPerPixel / (1 << 20) > params_.memlimit_mb
|
||||
|| params_.memlimit_mb < kLowestMemusageMB)) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Memory limit would be exceeded"
|
||||
);
|
||||
}
|
||||
|
||||
auto result = api->ProcessJPEGString(params->PtrBefore(), params_.verbose,
|
||||
input->PtrBefore(), output->PtrBoth());
|
||||
|
||||
if (!result.value_or(false)) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Guetzli processing failed"
|
||||
);
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status GuetzliTransaction::Main() {
|
||||
GuetzliApi api(sandbox());
|
||||
|
||||
sapi::v::LenVal input(0);
|
||||
sapi::v::LenVal output(0);
|
||||
sapi::v::Struct<Params> params;
|
||||
|
||||
auto read_result = api.ReadDataFromFd(in_fd_.GetRemoteFd(), input.PtrBoth());
|
||||
|
||||
if (!read_result.value_or(false)) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Error reading data inside sandbox"
|
||||
);
|
||||
}
|
||||
|
||||
auto score_quality_result = api.ButteraugliScoreQuality(params_.quality);
|
||||
|
||||
if (!score_quality_result.ok()) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Error calculating butteraugli score"
|
||||
);
|
||||
}
|
||||
|
||||
params.mutable_data()->butteraugli_target = score_quality_result.value();
|
||||
|
||||
static const unsigned char kPNGMagicBytes[] = {
|
||||
0x89, 'P', 'N', 'G', '\r', '\n', 0x1a, '\n',
|
||||
};
|
||||
|
||||
if (input.GetDataSize() >= 8 &&
|
||||
memcmp(input.GetData(), kPNGMagicBytes, sizeof(kPNGMagicBytes)) == 0) {
|
||||
auto process_status = ProcessPng(&api, ¶ms, &input, &output);
|
||||
|
||||
if (!process_status.ok()) {
|
||||
return process_status;
|
||||
}
|
||||
} else {
|
||||
auto process_status = ProcessJpeg(&api, ¶ms, &input, &output);
|
||||
|
||||
if (!process_status.ok()) {
|
||||
return process_status;
|
||||
}
|
||||
}
|
||||
|
||||
auto write_result = api.WriteDataToFd(out_fd_.GetRemoteFd(),
|
||||
output.PtrBefore());
|
||||
|
||||
if (!write_result.value_or(false)) {
|
||||
return absl::FailedPreconditionError(
|
||||
"Error writing file inside sandbox"
|
||||
);
|
||||
}
|
||||
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
time_t GuetzliTransaction::CalculateTimeLimitFromImageSize(
|
||||
uint64_t pixels) const {
|
||||
return (pixels / kMpixPixels + 5) * 60;
|
||||
}
|
||||
|
||||
} // namespace sandbox
|
||||
} // namespace guetzli
|
22
oss-internship-2020/guetzli/tests/BUILD.bazel
Normal file
22
oss-internship-2020/guetzli/tests/BUILD.bazel
Normal file
|
@ -0,0 +1,22 @@
|
|||
# cc_test(
|
||||
# name = "transaction_tests",
|
||||
# srcs = ["guetzli_transaction_test.cc"],
|
||||
# visibility=["//visibility:public"],
|
||||
# includes = ["."],
|
||||
# deps = [
|
||||
# "//:guetzli_sapi",
|
||||
# "@googletest//:gtest_main"
|
||||
# ],
|
||||
# )
|
||||
|
||||
# cc_test(
|
||||
# name = "sapi_lib_tests",
|
||||
# srcs = ["guetzli_sapi_test.cc"],
|
||||
# visibility=["//visibility:public"],
|
||||
# includes=[".."],
|
||||
# deps = [
|
||||
# "//:guetzli_sapi",
|
||||
# "@googletest//:gtest_main"
|
||||
# ],
|
||||
# data = glob(["testdata/*"])
|
||||
# )
|
165
oss-internship-2020/guetzli/tests/guetzli_sapi_test.cc
Normal file
165
oss-internship-2020/guetzli/tests/guetzli_sapi_test.cc
Normal file
|
@ -0,0 +1,165 @@
|
|||
#include "gtest/gtest.h"
|
||||
#include "guetzli_sandbox.h"
|
||||
#include "sandboxed_api/sandbox2/util/fileops.h"
|
||||
#include "sandboxed_api/vars.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sstream>
|
||||
|
||||
namespace guetzli {
|
||||
namespace sandbox {
|
||||
namespace tests {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr const char* IN_PNG_FILENAME = "bees.png";
|
||||
constexpr const char* IN_JPG_FILENAME = "landscape.jpg";
|
||||
|
||||
constexpr int IN_PNG_FILE_SIZE = 177'424;
|
||||
constexpr int IN_JPG_FILE_SIZE = 14'418;
|
||||
|
||||
constexpr int DEFAULT_QUALITY_TARGET = 95;
|
||||
|
||||
constexpr const char* RELATIVE_PATH_TO_TESTDATA =
|
||||
"/guetzli/guetzli-sandboxed/tests/testdata/";
|
||||
|
||||
std::string GetPathToInputFile(const char* filename) {
|
||||
return std::string(getenv("TEST_SRCDIR"))
|
||||
+ std::string(RELATIVE_PATH_TO_TESTDATA)
|
||||
+ std::string(filename);
|
||||
}
|
||||
|
||||
std::string ReadFromFile(const std::string& filename) {
|
||||
std::ifstream stream(filename, std::ios::binary);
|
||||
|
||||
if (!stream.is_open()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
std::stringstream result;
|
||||
result << stream.rdbuf();
|
||||
return result.str();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class GuetzliSapiTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
sandbox_ = std::make_unique<GuetzliSapiSandbox>();
|
||||
sandbox_->Init().IgnoreError();
|
||||
api_ = std::make_unique<GuetzliApi>(sandbox_.get());
|
||||
}
|
||||
|
||||
std::unique_ptr<GuetzliSapiSandbox> sandbox_;
|
||||
std::unique_ptr<GuetzliApi> api_;
|
||||
};
|
||||
|
||||
TEST_F(GuetzliSapiTest, ReadDataFromFd) {
|
||||
std::string input_file_path = GetPathToInputFile(IN_PNG_FILENAME);
|
||||
int fd = open(input_file_path.c_str(), O_RDONLY);
|
||||
ASSERT_TRUE(fd != -1) << "Error opening input file";
|
||||
sapi::v::Fd remote_fd(fd);
|
||||
auto send_fd_status = sandbox_->TransferToSandboxee(&remote_fd);
|
||||
ASSERT_TRUE(send_fd_status.ok()) << "Error sending fd to sandboxee";
|
||||
ASSERT_TRUE(remote_fd.GetRemoteFd() != -1) << "Error opening remote fd";
|
||||
sapi::v::LenVal data(0);
|
||||
auto read_status =
|
||||
api_->ReadDataFromFd(remote_fd.GetRemoteFd(), data.PtrBoth());
|
||||
ASSERT_TRUE(read_status.value_or(false)) << "Error reading data from fd";
|
||||
ASSERT_EQ(data.GetDataSize(), IN_PNG_FILE_SIZE) << "Wrong size of file";
|
||||
}
|
||||
|
||||
// TEST_F(GuetzliSapiTest, WriteDataToFd) {
|
||||
|
||||
// }
|
||||
|
||||
TEST_F(GuetzliSapiTest, ReadPng) {
|
||||
std::string data = ReadFromFile(GetPathToInputFile(IN_PNG_FILENAME));
|
||||
ASSERT_EQ(data.size(), IN_PNG_FILE_SIZE) << "Error reading input file";
|
||||
sapi::v::LenVal in_data(data.data(), data.size());
|
||||
sapi::v::Int xsize, ysize;
|
||||
sapi::v::LenVal rgb_out(0);
|
||||
|
||||
auto status = api_->ReadPng(in_data.PtrBefore(), xsize.PtrBoth(),
|
||||
ysize.PtrBoth(), rgb_out.PtrBoth());
|
||||
ASSERT_TRUE(status.value_or(false)) << "Error processing png data";
|
||||
ASSERT_EQ(xsize.GetValue(), 444) << "Error parsing width";
|
||||
ASSERT_EQ(ysize.GetValue(), 258) << "Error parsing height";
|
||||
}
|
||||
|
||||
TEST_F(GuetzliSapiTest, ReadJpeg) {
|
||||
std::string data = ReadFromFile(GetPathToInputFile(IN_JPG_FILENAME));
|
||||
ASSERT_EQ(data.size(), IN_JPG_FILE_SIZE) << "Error reading input file";
|
||||
sapi::v::LenVal in_data(data.data(), data.size());
|
||||
sapi::v::Int xsize, ysize;
|
||||
|
||||
auto status = api_->ReadJpegData(in_data.PtrBefore(), 0,
|
||||
xsize.PtrBoth(), ysize.PtrBoth());
|
||||
ASSERT_TRUE(status.value_or(false)) << "Error processing jpeg data";
|
||||
ASSERT_EQ(xsize.GetValue(), 180) << "Error parsing width";
|
||||
ASSERT_EQ(ysize.GetValue(), 180) << "Error parsing height";
|
||||
}
|
||||
|
||||
// This test can take up to few minutes depending on your hardware
|
||||
TEST_F(GuetzliSapiTest, ProcessRGB) {
|
||||
std::string data = ReadFromFile(GetPathToInputFile(IN_PNG_FILENAME));
|
||||
ASSERT_EQ(data.size(), IN_PNG_FILE_SIZE) << "Error reading input file";
|
||||
sapi::v::LenVal in_data(data.data(), data.size());
|
||||
sapi::v::Int xsize, ysize;
|
||||
sapi::v::LenVal rgb_out(0);
|
||||
|
||||
auto status = api_->ReadPng(in_data.PtrBefore(), xsize.PtrBoth(),
|
||||
ysize.PtrBoth(), rgb_out.PtrBoth());
|
||||
ASSERT_TRUE(status.value_or(false)) << "Error processing png data";
|
||||
ASSERT_EQ(xsize.GetValue(), 444) << "Error parsing width";
|
||||
ASSERT_EQ(ysize.GetValue(), 258) << "Error parsing height";
|
||||
auto quality =
|
||||
api_->ButteraugliScoreQuality(static_cast<double>(DEFAULT_QUALITY_TARGET));
|
||||
ASSERT_TRUE(quality.ok()) << "Error calculating butteraugli quality";
|
||||
sapi::v::Struct<Params> params;
|
||||
sapi::v::LenVal out_data(0);
|
||||
params.mutable_data()->butteraugli_target = quality.value();
|
||||
|
||||
status = api_->ProcessRGBData(params.PtrBefore(), 0, rgb_out.PtrBefore(),
|
||||
xsize.GetValue(), ysize.GetValue(), out_data.PtrBoth());
|
||||
ASSERT_TRUE(status.value_or(false)) << "Error processing png file";
|
||||
ASSERT_EQ(out_data.GetDataSize(), 38'625);
|
||||
//ADD COMPARSION WITH REFERENCE OUTPUT
|
||||
}
|
||||
|
||||
// This test can take up to few minutes depending on your hardware
|
||||
TEST_F(GuetzliSapiTest, ProcessJpeg) {
|
||||
std::string data = ReadFromFile(GetPathToInputFile(IN_JPG_FILENAME));
|
||||
ASSERT_EQ(data.size(), IN_JPG_FILE_SIZE) << "Error reading input file";
|
||||
sapi::v::LenVal in_data(data.data(), data.size());
|
||||
sapi::v::Int xsize, ysize;
|
||||
|
||||
auto status = api_->ReadJpegData(in_data.PtrBefore(), 0,
|
||||
xsize.PtrBoth(), ysize.PtrBoth());
|
||||
ASSERT_TRUE(status.value_or(false)) << "Error processing jpeg data";
|
||||
ASSERT_EQ(xsize.GetValue(), 180) << "Error parsing width";
|
||||
ASSERT_EQ(ysize.GetValue(), 180) << "Error parsing height";
|
||||
|
||||
auto quality =
|
||||
api_->ButteraugliScoreQuality(static_cast<double>(DEFAULT_QUALITY_TARGET));
|
||||
ASSERT_TRUE(quality.ok()) << "Error calculating butteraugli quality";
|
||||
sapi::v::Struct<Params> params;
|
||||
params.mutable_data()->butteraugli_target = quality.value();
|
||||
sapi::v::LenVal out_data(0);
|
||||
|
||||
status = api_->ProcessJPEGString(params.PtrBefore(), 0, in_data.PtrBefore(),
|
||||
out_data.PtrBoth());
|
||||
ASSERT_TRUE(status.value_or(false)) << "Error processing jpeg file";
|
||||
ASSERT_EQ(out_data.GetDataSize(), 10'816);
|
||||
//ADD COMPARSION WITH REFERENCE OUTPUT
|
||||
}
|
||||
|
||||
} // namespace tests
|
||||
} // namespace sandbox
|
||||
} // namespace guetzli
|
|
@ -0,0 +1,2 @@
|
|||
#include "gtest/gtest.h"
|
||||
#include "guetzli_transaction.h"
|
BIN
oss-internship-2020/guetzli/tests/testdata/bees.png
vendored
Normal file
BIN
oss-internship-2020/guetzli/tests/testdata/bees.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 173 KiB |
BIN
oss-internship-2020/guetzli/tests/testdata/landscape.jpg
vendored
Normal file
BIN
oss-internship-2020/guetzli/tests/testdata/landscape.jpg
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
Loading…
Reference in New Issue
Block a user