From 842ffde4794ee81d468eef1f0bcb342b20b63c3f Mon Sep 17 00:00:00 2001 From: Sandeep Davu Date: Mon, 21 Dec 2015 17:04:16 -0800 Subject: [PATCH 01/19] [TS-4095] adding a new example plugin for converting jpeg/png to webp format --- configure.ac | 16 + lib/atscppapi/examples/Makefile.am | 8 + .../examples/webp_transform/Common.h | 14 + .../examples/webp_transform/ImageTransform.cc | 111 +++++++ .../examples/webp_transform/ImageTransform.h | 52 +++ .../examples/webp_transform/Makefile.am | 29 ++ lib/atscppapi/examples/webp_transform/README | 6 + .../examples/webp_transform/compress.cc | 180 +++++++++++ .../examples/webp_transform/compress.h | 65 ++++ .../examples/webp_transform/jpegdec.cc | 265 ++++++++++++++++ .../examples/webp_transform/jpegdec.h | 58 ++++ .../examples/webp_transform/metadata.cc | 35 ++ .../examples/webp_transform/metadata.h | 35 ++ .../examples/webp_transform/pngdec.cc | 298 ++++++++++++++++++ .../examples/webp_transform/pngdec.h | 51 +++ 15 files changed, 1223 insertions(+) create mode 100644 lib/atscppapi/examples/webp_transform/Common.h create mode 100644 lib/atscppapi/examples/webp_transform/ImageTransform.cc create mode 100644 lib/atscppapi/examples/webp_transform/ImageTransform.h create mode 100644 lib/atscppapi/examples/webp_transform/Makefile.am create mode 100644 lib/atscppapi/examples/webp_transform/README create mode 100644 lib/atscppapi/examples/webp_transform/compress.cc create mode 100644 lib/atscppapi/examples/webp_transform/compress.h create mode 100644 lib/atscppapi/examples/webp_transform/jpegdec.cc create mode 100644 lib/atscppapi/examples/webp_transform/jpegdec.h create mode 100644 lib/atscppapi/examples/webp_transform/metadata.cc create mode 100644 lib/atscppapi/examples/webp_transform/metadata.h create mode 100644 lib/atscppapi/examples/webp_transform/pngdec.cc create mode 100644 lib/atscppapi/examples/webp_transform/pngdec.h diff --git a/configure.ac b/configure.ac index 58b3e772b87..c6e7d6313ee 100644 --- a/configure.ac +++ b/configure.ac @@ -1937,6 +1937,21 @@ AS_IF([test "x$enable_experimental_plugins" = "xyes"], [ plugins/experimental/stream_editor/Makefile ])]) +AC_CHECK_HEADERS([webp/encode.h], [has_webp=1],[has_webp=0]) +AC_CHECK_LIB([webp],[WebPEncode],[AC_SUBST([LIB_WEBP],["-lwebp"])],[has_webp=0]) +AC_SUBST(has_webp) +AM_CONDITIONAL([HAS_WEBP], [ test "x${has_webp}" = "x1" ]) + +AC_CHECK_HEADERS([jpeglib.h], [has_jpeg=1],[has_jpeg=0]) +AC_CHECK_LIB([jpeg],[jpeg_mem_src],[AC_SUBST([LIB_JPEG],["-ljpeg"])],[has_jpeg=0]) +AC_SUBST(has_jpeg) +AM_CONDITIONAL([HAS_JPEG], [ test "x${has_jpeg}" = "x1" ]) + +AC_CHECK_HEADERS([png.h], [has_png=1],[has_png=0]) +AC_CHECK_LIB([png],[png_set_read_fn],[AC_SUBST([LIB_PNG],["-lpng"])],[has_png=0]) +AC_SUBST(has_png) +AM_CONDITIONAL([HAS_PNG], [ test "x${has_png}" = "x1" ]) + AS_IF([test "x$enable_cppapi" = "xyes"], [ AC_CONFIG_FILES([ lib/atscppapi/Makefile @@ -1962,6 +1977,7 @@ AS_IF([test "x$enable_cppapi" = "xyes"], [ lib/atscppapi/examples/timeout_example/Makefile lib/atscppapi/examples/transactionhook/Makefile lib/atscppapi/examples/async_http_fetch_streaming/Makefile + lib/atscppapi/examples/webp_transform/Makefile lib/atscppapi/src/Makefile ])]) diff --git a/lib/atscppapi/examples/Makefile.am b/lib/atscppapi/examples/Makefile.am index 9f56838cf5d..f30a0ae1650 100644 --- a/lib/atscppapi/examples/Makefile.am +++ b/lib/atscppapi/examples/Makefile.am @@ -37,3 +37,11 @@ SUBDIRS = \ async_timer \ intercept \ async_http_fetch_streaming + +if HAS_WEBP +if HAS_JPEG +if HAS_PNG + SUBDIRS += webp_transform +endif +endif +endif diff --git a/lib/atscppapi/examples/webp_transform/Common.h b/lib/atscppapi/examples/webp_transform/Common.h new file mode 100644 index 00000000000..7794631b775 --- /dev/null +++ b/lib/atscppapi/examples/webp_transform/Common.h @@ -0,0 +1,14 @@ +/* + * Common.h + * + * Created on: Jul 30, 2015 + * Author: sdavu + */ + +#ifndef COMMON_H_ +#define COMMON_H_ + +#define TAG "img_transform" + + +#endif /* COMMON_H_ */ diff --git a/lib/atscppapi/examples/webp_transform/ImageTransform.cc b/lib/atscppapi/examples/webp_transform/ImageTransform.cc new file mode 100644 index 00000000000..209fb50b29c --- /dev/null +++ b/lib/atscppapi/examples/webp_transform/ImageTransform.cc @@ -0,0 +1,111 @@ +/** + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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. + */ + +#include +#include +#include +#include + +#include "compress.h" +#include "Common.h" +#include "ImageTransform.h" + +using namespace atscppapi; +using std::string; + + +std::string ImageTransform::FIELD_USER_AGENT("User-Agent"); +std::string ImageTransform::FIELD_CONTENT_TYPE("Content-Type"); +std::string ImageTransform::FIELD_TRANSFORM_IMAGE("@X-Transform-Image"); +std::string ImageTransform::CONTEXT_IMG_TRANSFORM("Transform-Image"); +std::string ImageTransform::USER_AGENT_CROME("Chrome"); + + +ImageTransform::ImageTransform(Transaction &transaction, TransformationPlugin::Type xformType) +: TransformationPlugin(transaction, xformType), + webp_transform_(){ + TransactionPlugin::registerHook(HOOK_SEND_REQUEST_HEADERS); + TransformationPlugin::registerHook((xformType == TransformationPlugin::REQUEST_TRANSFORMATION) ? + HOOK_SEND_REQUEST_HEADERS : HOOK_READ_RESPONSE_HEADERS); +} + +ImageTransform::~ImageTransform() { + webp_transform_.Finalize(); +} + +void +ImageTransform::handleReadResponseHeaders(Transaction &transaction) +{ + Headers& headers = transaction.getServerResponse().getHeaders(); + headers.set("Vary", ImageTransform::FIELD_TRANSFORM_IMAGE); + headers.set(ImageTransform::FIELD_CONTENT_TYPE, "image/webp"); + + TS_DEBUG(TAG, "Image Transformation Plugin for url %s", transaction.getServerRequest().getUrl().getUrlString().c_str() ); + transaction.resume(); +} + +void +ImageTransform::consume(const string &data) { + img_.write(data.data(), data.size()); +} + +void +ImageTransform::handleInputComplete() { + webp_transform_.Init(); + webp_transform_.Transform(img_); + produce(webp_transform_.getTransformedImage().str()); + + setOutputComplete(); +} + + +GlobalHookPlugin::GlobalHookPlugin() { + registerHook(HOOK_READ_REQUEST_HEADERS); + registerHook(HOOK_READ_RESPONSE_HEADERS); +} + +void +GlobalHookPlugin::handleReadRequestHeaders(Transaction &transaction) { + //add transformation only for jpeg files + Headers& hdrs = transaction.getClientRequest().getHeaders(); + string uagent = hdrs.values(ImageTransform::FIELD_USER_AGENT); + if(uagent.find(ImageTransform::USER_AGENT_CROME) != string::npos) { + TS_DEBUG(TAG, "Setting Context for useragent chrome."); + transaction.setContextValue(ImageTransform::CONTEXT_IMG_TRANSFORM, shared_ptr(new ImageValue(true))); + transaction.getClientRequest().getHeaders().set(ImageTransform::FIELD_TRANSFORM_IMAGE, "1"); + } + transaction.resume(); +} + +void +GlobalHookPlugin::handleReadResponseHeaders(Transaction &transaction) { + //add transformation only for jpeg files + Headers& hdrs = transaction.getServerResponse().getHeaders(); + string ctype = hdrs.values(ImageTransform::FIELD_CONTENT_TYPE); + ImageValue* img_context = dynamic_cast(transaction.getContextValue(ImageTransform::CONTEXT_IMG_TRANSFORM).get()); + if(img_context && (ctype.find("jpeg") != string::npos || ctype.find("png") != string::npos)) { + //modify clientrequest at this point. Lets see if this will effect the caching. + transaction.addPlugin(new ImageTransform(transaction, TransformationPlugin::RESPONSE_TRANSFORMATION)); + } + transaction.resume(); +} + +void TSPluginInit(int argc ATSCPPAPI_UNUSED, const char *argv[] ATSCPPAPI_UNUSED) { + TS_DEBUG(TAG, "TSPluginInit"); + new GlobalHookPlugin(); +} diff --git a/lib/atscppapi/examples/webp_transform/ImageTransform.h b/lib/atscppapi/examples/webp_transform/ImageTransform.h new file mode 100644 index 00000000000..eaf6784e9b3 --- /dev/null +++ b/lib/atscppapi/examples/webp_transform/ImageTransform.h @@ -0,0 +1,52 @@ +/* + * ImageTransfrom.h + * + * Created on: Aug 6, 2015 + * Author: sdavu + */ + +#ifndef IMAGETRANSFROM_H_ +#define IMAGETRANSFROM_H_ + +#include +#include +#include +#include +#include + +struct ImageValue: public atscppapi::Transaction::ContextValue{ + bool do_transform_; + ImageValue(bool transform) : do_transform_(transform) { } +}; + + +class ImageTransform : public atscppapi::TransformationPlugin { +public: + ImageTransform(atscppapi::Transaction &transaction, atscppapi::TransformationPlugin::Type xformType); + + void handleReadResponseHeaders(atscppapi::Transaction &transaction); + void consume(const std::string &data); + void handleInputComplete(); + virtual ~ImageTransform(); + + static std::string FIELD_USER_AGENT; + static std::string FIELD_TRANSFORM_IMAGE; + static std::string CONTEXT_IMG_TRANSFORM; + static std::string USER_AGENT_CROME; + static std::string FIELD_CONTENT_TYPE; + +private: + std::stringstream img_; + WebpTransform webp_transform_; +}; + +class GlobalHookPlugin : public atscppapi::GlobalPlugin { +public: + GlobalHookPlugin(); + virtual void handleReadRequestHeaders(atscppapi::Transaction &transaction); + virtual void handleReadResponseHeaders(atscppapi::Transaction &transaction); +}; + + + +#endif /* IMAGETRANSFROM_H_ */ diff --git a/lib/atscppapi/examples/webp_transform/Makefile.am b/lib/atscppapi/examples/webp_transform/Makefile.am new file mode 100644 index 00000000000..f9007cc1f9d --- /dev/null +++ b/lib/atscppapi/examples/webp_transform/Makefile.am @@ -0,0 +1,29 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +AM_CPPFLAGS = -I$(top_srcdir)/lib/atscppapi/src/include -Wno-unused-variable + +target=WebpTransform.so +pkglibdir = ${pkglibexecdir} +pkglib_LTLIBRARIES = WebpTransform.la +WebpTransform_la_SOURCES = ImageTransform.cc jpegdec.cc pngdec.cc metadata.cc compress.cc +WebpTransform_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir)/lib/atscppapi/src/ -latscppapi -lwebp -ljpeg -lpng + +all: + ln -sf .libs/$(target) + +clean-local: + rm -f $(target) diff --git a/lib/atscppapi/examples/webp_transform/README b/lib/atscppapi/examples/webp_transform/README new file mode 100644 index 00000000000..476fc93c531 --- /dev/null +++ b/lib/atscppapi/examples/webp_transform/README @@ -0,0 +1,6 @@ +onverting jpeg and png to webp +Pre-requisites + +1. webp +2. jpeg version 9 and above -- http://ijg.org/files/jpegsrc.v9.tar.gz +3. png version 1.6.19 and above -- http://sourceforge.net/projects/libpng/files/libpng19/1.6.19/libpng-1.6.19.tar.xz/download diff --git a/lib/atscppapi/examples/webp_transform/compress.cc b/lib/atscppapi/examples/webp_transform/compress.cc new file mode 100644 index 00000000000..8d59fedea2f --- /dev/null +++ b/lib/atscppapi/examples/webp_transform/compress.cc @@ -0,0 +1,180 @@ +#include +#include +#include + + +#include +#include +#include "compress.h" +#include "Common.h" + +#define MAGIC_SIZE 12; +using std::string; +using std::vector; + + +static int +StreamWriter(const uint8_t* data, size_t data_size, + const WebPPicture* const pic) { + WebpTransform* webp_transform = static_cast(pic->custom_ptr); + webp_transform->WriteImage(reinterpret_cast(data), data_size); + return data_size ? data_size : 1; +} + +const string WebpTransform::errors_[] = { + "OK", + "OUT_OF_MEMORY: Out of memory allocating objects", + "BITSTREAM_OUT_OF_MEMORY: Out of memory re-allocating byte buffer", + "NULL_PARAMETER: NULL parameter passed to function", + "INVALID_CONFIGURATION: configuration is invalid", + "BAD_DIMENSION: Bad picture dimension. Maximum width and height " + "allowed is 16383 pixels.", + "PARTITION0_OVERFLOW: Partition #0 is too big to fit 512k.\n" + "To reduce the size of this partition, try using less segments " + "with the -segments option, and eventually reduce the number of " + "header bits using -partition_limit. More details are available " + "in the manual (`man cwebp`)", + "PARTITION_OVERFLOW: Partition is too big to fit 16M", + "BAD_WRITE: Picture writer returned an I/O error", + "FILE_TOO_BIG: File would be too big to fit in 4G", + "USER_ABORT: encoding abort requested by user" +}; + +void +WebpTransform::WebPMemoryWriterClear() { + if(writer_.mem != NULL) { + free(writer_.mem); + writer_.mem = NULL; + writer_.size = 0; + writer_.max_size = 0; + } +} + + +WebpTransform::InputFileFormat +WebpTransform::GetImageType(std::stringstream& input_img) { + InputFileFormat format = UNSUPPORTED; + uint32_t magic1, magic2; + uint8_t buf[12]; + input_img.read((char *)buf, 12); + input_img.seekg(0, input_img.beg); + + magic1 = ((uint32_t)buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; + magic2 = ((uint32_t)buf[8] << 24) | (buf[9] << 16) | (buf[10] << 8) | buf[11]; + if (magic1 == 0x89504E47U) { + format = PNG_; + } else if (magic1 >= 0xFFD8FF00U && magic1 <= 0xFFD8FFFFU) { + format = JPEG_; + } else if (magic1 == 0x49492A00 || magic1 == 0x4D4D002A) { + format = TIFF_; + } else if (magic1 == 0x52494646 && magic2 == 0x57454250) { + format = WEBP_; + } + return format; +} + +int +WebpTransform::ReadImage(std::stringstream& input_img) { + int ok = 0; + + if (picture_.width == 0 || picture_.height == 0) { + // If no size specified, try to decode it as PNG/JPEG (as appropriate). + const InputFileFormat format = GetImageType(input_img); + if (format == PNG_) { + if(!png_dec_.Init(&input_img)) { + png_dec_.Finalize(); + return 0; + } + ok = png_dec_.ReadImage(&picture_, &metadata_); + } else if (format == JPEG_) { + if(!jpeg_dec_.Init(&input_img)) { + jpeg_dec_.Finalize(); + return 0; + } + ok = jpeg_dec_.ReadImage(&picture_, &metadata_); + } else if (format == TIFF_) { + TS_DEBUG(TAG, "Cannot read tiff files."); + } else if (format == WEBP_) { + TS_DEBUG(TAG, "Already webp file. Nothing to be done."); + } + } + if (!ok) + TS_DEBUG(TAG, "failed to read image."); + + return ok; +} + + +void +WebpTransform::AllocExtraInfo() { + const int mb_w = (picture_.width + 15) / 16; + const int mb_h = (picture_.height + 15) / 16; + picture_.extra_info = (uint8_t*)malloc(mb_w * mb_h * sizeof(picture_.extra_info)); +} + +bool +WebpTransform::Init() { + MetadataInit(&metadata_); + WebPMemoryWriterInit(&writer_); + if (!WebPPictureInit(&picture_) || !WebPConfigInit(&config_)) { + TS_DEBUG(TAG, "DEBUG! Version mismatch"); + return false; + } + WebPPreset preset = WEBP_PRESET_PICTURE; + if (!WebPConfigPreset(&config_, preset, config_.quality)) { + TS_DEBUG(TAG, "DEBUG! Could initialize configuration with preset."); + return false; + } + + if (!WebPValidateConfig(&config_)) { + TS_DEBUG(TAG, "DEBUG! Invalid configuration."); + return false; + } + init_ =true; + return true; +} + + +bool +WebpTransform::Transform(std::stringstream& input_img) { + + + if (!ReadImage(input_img) ) { + TS_DEBUG(TAG, "Cannot read input picture file ."); + return false; + } + picture_.progress_hook = NULL; + + picture_.writer = StreamWriter; + picture_.custom_ptr = (void*)this; + + if (picture_.extra_info_type > 0) { + AllocExtraInfo(); + } + + if (!WebPEncode(&config_, &picture_)) { + + TS_DEBUG(TAG, "DEBUG! Cannot encode picture as WebP. Error code: %d (%s)", + picture_.error_code, WebpTransform::errors_[picture_.error_code].c_str()); + return false; + } + return true; +} + +void +WebpTransform::Finalize() { + if(init_) { + WebPMemoryWriterClear(); + free(picture_.extra_info); + MetadataFree(&metadata_); + WebPPictureFree(&picture_); + + png_dec_.Finalize(); + jpeg_dec_.Finalize(); + } +} + +void +WebpTransform::WriteImage(const char* data, size_t data_size) { + stream_.write(data, data_size); +} diff --git a/lib/atscppapi/examples/webp_transform/compress.h b/lib/atscppapi/examples/webp_transform/compress.h new file mode 100644 index 00000000000..921b47e9d88 --- /dev/null +++ b/lib/atscppapi/examples/webp_transform/compress.h @@ -0,0 +1,65 @@ + +#ifndef WEBPCOMPRESS_H_ +#define WEBPTRANSFORM_H_ + +#include +#include +#include +#include + +#include +#include "jpegdec.h" +#include "pngdec.h" +#include "metadata.h" + + +class WebpTransform { +public: + WebpTransform() :init_(false), png_dec_(), jpeg_dec_() + { } + + ~WebpTransform() { } + + bool Init(); + bool Transform(std::stringstream& stream); + void Finalize(); + std::stringstream& getTransformedImage() { return stream_; } + void WriteImage(const char* data, size_t data_size); + +#ifndef UNIT_TESTING +private: +#endif + typedef enum { + PNG_ = 0, + JPEG_, + TIFF_, // 'TIFF' clashes with libtiff + WEBP_, + UNSUPPORTED + } InputFileFormat; + + enum { + METADATA_EXIF = (1 << 0), + METADATA_ICC = (1 << 1), + METADATA_XMP = (1 << 2), + METADATA_ALL = METADATA_EXIF | METADATA_ICC | METADATA_XMP + }; + + InputFileFormat GetImageType(std::stringstream& input_msg); + int ReadImage(std::stringstream& input_img); + void AllocExtraInfo(); + + void WebPMemoryWriterClear(); + + static const std::string errors_[]; + bool init_; + WebPMemoryWriter writer_; + std::stringstream stream_; + WebPPicture picture_; + WebPConfig config_; + Metadata metadata_; + std::string debug_tag_; + PngDec png_dec_; + JpegDec jpeg_dec_; +}; + +#endif // COMPRESS_H_ diff --git a/lib/atscppapi/examples/webp_transform/jpegdec.cc b/lib/atscppapi/examples/webp_transform/jpegdec.cc new file mode 100644 index 00000000000..a11cf71fad8 --- /dev/null +++ b/lib/atscppapi/examples/webp_transform/jpegdec.cc @@ -0,0 +1,265 @@ + +#include + +#include +#include +#include +#include +#include +#include "webp/encode.h" +#include "metadata.h" +#include "jpegdec.h" +#include "Common.h" + +#define JPEG_APP1 (JPEG_APP0 + 1) +#define JPEG_APP2 (JPEG_APP0 + 2) + + +JpegDec::JpegMetadataMap JpegDec::jpeg_metadata_map_[] = { + // Exif 2.2 Section 4.7.2 Interoperability Structure of APP1 ... + { JPEG_APP1, "Exif\0", 6, METADATA_OFFSET(exif) }, + // XMP Specification Part 3 Section 3 Embedding XMP Metadata ... #JPEG + // TODO(jzern) Add support for 'ExtendedXMP' + { JPEG_APP1, "http://ns.adobe.com/xap/1.0/", 29, METADATA_OFFSET(xmp) }, + { 0, NULL, 0, 0 }, + }; + +void JpegDec::SaveMetadataMarkers() { + const unsigned int max_marker_length = 0xffff; + jpeg_save_markers((j_decompress_ptr)&dinfo_, JPEG_APP1, max_marker_length); // Exif/XMP + jpeg_save_markers((j_decompress_ptr)&dinfo_, JPEG_APP2, max_marker_length); // ICC profile +} + +int JpegDec::CompareICCPSegments(const void* a, const void* b) { + const ICCPSegment* s1 = (const ICCPSegment*)a; + const ICCPSegment* s2 = (const ICCPSegment*)b; + return s1->seq - s2->seq; +} + + +int +JpegDec::StoreICCP(MetadataPayload* const iccp) { + // ICC.1:2010-12 (4.3.0.0) Annex B.4 Embedding ICC Profiles in JPEG files + static const char kICCPSignature[] = "ICC_PROFILE"; + static const size_t kICCPSignatureLength = 12; // signature includes '\0' + static const size_t kICCPSkipLength = 14; // signature + seq & count + int expected_count = 0; + int actual_count = 0; + int seq_max = 0; + size_t total_size = 0; + ICCPSegment iccp_segments[255]; + jpeg_saved_marker_ptr marker; + + memset(iccp_segments, 0, sizeof(iccp_segments)); + for (marker = dinfo_.marker_list; marker != NULL; marker = marker->next) { + if (marker->marker == JPEG_APP2 && + marker->data_length > kICCPSkipLength && + !memcmp(marker->data, kICCPSignature, kICCPSignatureLength)) { + // ICC_PROFILE\0; 'seq' starts at 1. + const int seq = marker->data[kICCPSignatureLength]; + const int count = marker->data[kICCPSignatureLength + 1]; + const size_t segment_size = marker->data_length - kICCPSkipLength; + ICCPSegment* segment; + if (segment_size == 0 || count == 0 || seq == 0) { + TS_DEBUG(TAG, "[ICCP] size (%d) / count (%d) / sequence number (%d) cannot be 0!", + (int)segment_size, seq, count); + return 0; + } + + if (expected_count == 0) { + expected_count = count; + } else if (expected_count != count) { + TS_DEBUG(TAG, "[ICCP] Inconsistent segment count (%d / %d)!\n", + expected_count, count); + return 0; + } + + segment = iccp_segments + seq - 1; + if (segment->data_length != 0) { + TS_DEBUG(TAG, "[ICCP] Duplicate segment number (%d)!\n" , seq); + return 0; + } + + segment->data = marker->data + kICCPSkipLength; + segment->data_length = segment_size; + segment->seq = seq; + total_size += segment_size; + if (seq > seq_max) seq_max = seq; + ++actual_count; + } + } + + if (actual_count == 0) return 1; + if (seq_max != actual_count) { + TS_DEBUG(TAG, "[ICCP] Discontinuous segments, expected: %d actual: %d!\n", + actual_count, seq_max); + return 0; + } + if (expected_count != actual_count) { + TS_DEBUG(TAG, "[ICCP] Segment count: %d does not match expected: %d!\n", + actual_count, expected_count); + return 0; + } + + // The segments may appear out of order in the file, sort them based on + // sequence number before assembling the payload. + qsort(iccp_segments, actual_count, sizeof(*iccp_segments), + JpegDec::CompareICCPSegments); + + iccp->bytes = (uint8_t*)malloc(total_size); + if (iccp->bytes == NULL) return 0; + iccp->size = total_size; + + { + int i; + size_t offset = 0; + for (i = 0; i < seq_max; ++i) { + memcpy(iccp->bytes + offset, + iccp_segments[i].data, iccp_segments[i].data_length); + offset += iccp_segments[i].data_length; + } + } + return 1; +} + +// Returns true on success and false for memory errors and corrupt profiles. +// The caller must use MetadataFree() on 'metadata' in all cases. +int +JpegDec::ExtractMetadataFromJPEG(Metadata* const metadata) { + jpeg_saved_marker_ptr marker; + // Treat ICC profiles separately as they may be segmented and out of order. + if (!StoreICCP(&metadata->iccp)) return 0; + + for (marker = dinfo_.marker_list; marker != NULL; marker = marker->next) { + int i; + for (i = 0; jpeg_metadata_map_[i].marker != 0; ++i) { + if (marker->marker == jpeg_metadata_map_[i].marker && + marker->data_length > jpeg_metadata_map_[i].signature_length && + !memcmp(marker->data, jpeg_metadata_map_[i].signature, + jpeg_metadata_map_[i].signature_length)) { + MetadataPayload* const payload = + (MetadataPayload*)((uint8_t*)metadata + + jpeg_metadata_map_[i].storage_offset); + + if (payload->bytes == NULL) { + const char* marker_data = (const char*)marker->data + + jpeg_metadata_map_[i].signature_length; + const size_t marker_data_length = + marker->data_length - jpeg_metadata_map_[i].signature_length; + if (!MetadataCopy(marker_data, marker_data_length, payload)) return 0; + } else { + TS_DEBUG(TAG, "Ignoring additional '%s' marker\n", + jpeg_metadata_map_[i].signature); + } + } + } + } + return 1; +} + +#undef JPEG_APP1 +#undef JPEG_APP2 + +// ----------------------------------------------------------------------------- +// JPEG decoding + + +void +JpegDec::Error(j_common_ptr dinfo) { + struct JpegDec::ErrorMgr* err = (struct JpegDec::ErrorMgr*)dinfo->err; + dinfo->err->output_message(dinfo); + longjmp(err->setjmp_buffer, 1); +} + +bool +JpegDec::Init(std::stringstream* img) { + input_img_ = img; + + memset((j_decompress_ptr)&dinfo_, 0, sizeof(dinfo_)); // for setjmp sanity + dinfo_.err = jpeg_std_error(&jerr_.pub); + jerr_.pub.error_exit = JpegDec::Error; + + if (setjmp(jerr_.setjmp_buffer)) { + TS_DEBUG(TAG, " setjmp failed"); + jpeg_destroy_decompress((j_decompress_ptr)&dinfo_); + return false; + } + + jpeg_create_decompress((j_decompress_ptr)&dinfo_); + init_ = true; + return true; +} + +int +JpegDec::ReadImage(WebPPicture* const pic, Metadata* const metadata) { + int ok = 0; + int stride, width, height; + uint8_t* volatile rgb = NULL; + JSAMPROW buffer[1]; + + std::string img_str = input_img_->str(); + //TODO: Can this copy be avoided. + jpeg_mem_src((j_decompress_ptr)&dinfo_, (unsigned char*)img_str.data(), img_str.size()); + + if (metadata != NULL) SaveMetadataMarkers(); + jpeg_read_header((j_decompress_ptr)&dinfo_, TRUE); + + dinfo_.out_color_space = JCS_RGB; + dinfo_.do_fancy_upsampling = TRUE; + + jpeg_start_decompress((j_decompress_ptr)&dinfo_); + + if (dinfo_.output_components != 3) { + TS_DEBUG(TAG,"not enought output componenets available."); + return 0; + } + + width = dinfo_.output_width; + height = dinfo_.output_height; + stride = dinfo_.output_width * dinfo_.output_components * sizeof(*rgb); + + rgb = (uint8_t*)malloc(stride * height); + if (rgb == NULL) { + TS_DEBUG(TAG,"unable to alloc memory for rgb."); + return 0; + } + buffer[0] = (JSAMPLE*)rgb; + + while (dinfo_.output_scanline < dinfo_.output_height) { + if (jpeg_read_scanlines((j_decompress_ptr)&dinfo_, buffer, 1) != 1) { + free(rgb); + return 0; + } + buffer[0] += stride; + } + + if (metadata != NULL) { + ok = ExtractMetadataFromJPEG(metadata); + if (!ok) { + TS_DEBUG(TAG, "Error extracting JPEG metadata!"); + free(rgb); + return 0; + } + } + + jpeg_finish_decompress((j_decompress_ptr)&dinfo_); + jpeg_destroy_decompress((j_decompress_ptr)&dinfo_); + + // WebP conversion. + pic->width = width; + pic->height = height; + pic->use_argb = 1; // store raw RGB samples + ok = WebPPictureImportRGB(pic, rgb, stride); + if (!ok) { + TS_DEBUG(TAG, "Unable to import inot webp"); + } + + free(rgb); + return ok; +} + +void +JpegDec::Finalize() { + if(init_) + jpeg_destroy_decompress((j_decompress_ptr)&dinfo_); +} diff --git a/lib/atscppapi/examples/webp_transform/jpegdec.h b/lib/atscppapi/examples/webp_transform/jpegdec.h new file mode 100644 index 00000000000..59133af6cb7 --- /dev/null +++ b/lib/atscppapi/examples/webp_transform/jpegdec.h @@ -0,0 +1,58 @@ +#ifndef JPEGDEC_H_ +#define JPEGDEC_H_ + +#include +#include +#include +#include +#include +#include +#include "jpegdec.h" +#include "metadata.h" + +struct WebPPicture; + +typedef struct { + const uint8_t* data; + size_t data_length; + int seq; // this segment's sequence number [1, 255] for use in reassembly. +} ICCPSegment; + +class JpegDec { + +public: + JpegDec() : init_(false) { } + ~JpegDec() { } + bool Init(std::stringstream* img); + int ReadImage(struct WebPPicture* const pic, struct Metadata* const metadata); + void Finalize(); + +private: + struct ErrorMgr { + struct jpeg_error_mgr pub; + jmp_buf setjmp_buffer; + }; + + struct JpegMetadataMap { + int marker; + const char* signature; + size_t signature_length; + size_t storage_offset; + }; + + static int CompareICCPSegments(const void* a, const void* b); + int StoreICCP(MetadataPayload* const iccp); + int ExtractMetadataFromJPEG(Metadata* const metadata); + void SaveMetadataMarkers(); + + static void Error(j_common_ptr dinfo); + + bool init_; + std::stringstream* input_img_; + volatile struct jpeg_decompress_struct dinfo_; + struct ErrorMgr jerr_; + static JpegMetadataMap jpeg_metadata_map_[]; + +}; + +#endif // JPEGDEC_H_ diff --git a/lib/atscppapi/examples/webp_transform/metadata.cc b/lib/atscppapi/examples/webp_transform/metadata.cc new file mode 100644 index 00000000000..5a5f2f50876 --- /dev/null +++ b/lib/atscppapi/examples/webp_transform/metadata.cc @@ -0,0 +1,35 @@ +#include +#include + +#include "webp/types.h" +#include "metadata.h" + +void MetadataInit(Metadata* const metadata) { + if (metadata == NULL) return; + memset(metadata, 0, sizeof(*metadata)); +} + +void MetadataPayloadDelete(MetadataPayload* const payload) { + if (payload == NULL) return; + free(payload->bytes); + payload->bytes = NULL; + payload->size = 0; +} + +void MetadataFree(Metadata* const metadata) { + if (metadata == NULL) return; + MetadataPayloadDelete(&metadata->exif); + MetadataPayloadDelete(&metadata->iccp); + MetadataPayloadDelete(&metadata->xmp); +} + +int MetadataCopy(const char* metadata, size_t metadata_len, + MetadataPayload* const payload) { + if (metadata == NULL || metadata_len == 0 || payload == NULL) return 0; + payload->bytes = (uint8_t*)malloc(metadata_len); + if (payload->bytes == NULL) return 0; + payload->size = metadata_len; + memcpy(payload->bytes, metadata, metadata_len); + return 1; +} + diff --git a/lib/atscppapi/examples/webp_transform/metadata.h b/lib/atscppapi/examples/webp_transform/metadata.h new file mode 100644 index 00000000000..4d8c9492fba --- /dev/null +++ b/lib/atscppapi/examples/webp_transform/metadata.h @@ -0,0 +1,35 @@ +#ifndef METADATA_H_ +#define METADATA_H_ + +#include "webp/types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct MetadataPayload { + uint8_t* bytes; + size_t size; +} MetadataPayload; + +typedef struct Metadata { + MetadataPayload exif; + MetadataPayload iccp; + MetadataPayload xmp; +} Metadata; + +#define METADATA_OFFSET(x) offsetof(Metadata, x) + +void MetadataInit(Metadata* const metadata); +void MetadataPayloadDelete(MetadataPayload* const payload); +void MetadataFree(Metadata* const metadata); + +// Stores 'metadata' to 'payload->bytes', returns false on allocation error. +int MetadataCopy(const char* metadata, size_t metadata_len, + MetadataPayload* const payload); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // METADATA_H_ diff --git a/lib/atscppapi/examples/webp_transform/pngdec.cc b/lib/atscppapi/examples/webp_transform/pngdec.cc new file mode 100644 index 00000000000..713c621bf89 --- /dev/null +++ b/lib/atscppapi/examples/webp_transform/pngdec.cc @@ -0,0 +1,298 @@ +#include +#include +#include +#include +#include // note: this must be included *after* png.h +#include +#include +#include + +#include "webp/encode.h" +#include "metadata.h" +#include "pngdec.h" +#include "Common.h" + +void +PngDec::ErrorFunction(png_structp png, png_const_charp error) { + if (error != NULL) TS_DEBUG("img_transform_png", "libpng error: %s\n", error); + longjmp(png_jmpbuf(png), 1); +} + +void +PngDec::ReadFunction(png_structp pngPtr, png_bytep data, png_size_t length) { + PngDec* png_dec = reinterpret_cast(png_get_io_ptr(pngPtr)); + png_dec->ReadData(data, length); +} + +PngDec::PNGMetadataMap PngDec::png_metadata_map_[] = { + // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PNG.html#TextualData + // See also: ExifTool on CPAN. + { "Raw profile type exif", PngDec::ProcessRawProfile, METADATA_OFFSET(exif) }, + { "Raw profile type xmp", PngDec::ProcessRawProfile, METADATA_OFFSET(xmp) }, + // Exiftool puts exif data in APP1 chunk, too. + { "Raw profile type APP1", PngDec::ProcessRawProfile, METADATA_OFFSET(exif) }, + // XMP Specification Part 3, Section 3 #PNG + { "XML:com.adobe.xmp", MetadataCopy, METADATA_OFFSET(xmp) }, + { NULL, NULL, 0 }, + }; + +int +PngDec::ProcessRawProfile(const char* profile, size_t profile_len, + MetadataPayload* const payload) { + const char* src = profile; + char* end; + int expected_length; + + if (profile == NULL || profile_len == 0) return 0; + + // ImageMagick formats 'raw profiles' as + // '\n\n(%8lu)\n\n'. + if (*src != '\n') { + TS_DEBUG(TAG, "Malformed raw profile, expected '\\n' got '\\x%.2X'\n", *src); + return 0; + } + ++src; + // skip the profile name and extract the length. + while (*src != '\0' && *src++ != '\n') {} + expected_length = (int)strtol(src, &end, 10); + if (*end != '\n') { + TS_DEBUG(TAG, "Malformed raw profile, expected '\\n' got '\\x%.2X'\n", *end); + return 0; + } + ++end; + + // 'end' now points to the profile payload. + payload->bytes = HexStringToBytes(end, expected_length); + if (payload->bytes == NULL) { + TS_DEBUG(TAG, "HexStringToBytes failed"); + return 0; + } + payload->size = expected_length; + return 1; +} + +// Converts the NULL terminated 'hexstring' which contains 2-byte character +// representations of hex values to raw data. +// 'hexstring' may contain values consisting of [A-F][a-f][0-9] in pairs, +// e.g., 7af2..., separated by any number of newlines. +// 'expected_length' is the anticipated processed size. +// On success the raw buffer is returned with its length equivalent to +// 'expected_length'. NULL is returned if the processed length is less than +// 'expected_length' or any character aside from those above is encountered. +// The returned buffer must be freed by the caller. +uint8_t* +PngDec::HexStringToBytes(const char* hexstring, + size_t expected_length) { + const char* src = hexstring; + size_t actual_length = 0; + uint8_t* const raw_data = (uint8_t*)malloc(expected_length); + uint8_t* dst; + + if (raw_data == NULL) return NULL; + + for (dst = raw_data; actual_length < expected_length && *src != '\0'; ++src) { + char* end; + char val[3]; + if (*src == '\n') continue; + val[0] = *src++; + val[1] = *src; + val[2] = '\0'; + *dst++ = (uint8_t)strtol(val, &end, 16); + if (end != val + 2) break; + ++actual_length; + } + if (actual_length != expected_length) { + free(raw_data); + return NULL; + } + return raw_data; +} + + + + +// Looks for metadata at both the beginning and end of the PNG file, giving +// preference to the head. +// Returns true on success. The caller must use MetadataFree() on 'metadata' in +// all cases. +int +PngDec::ExtractMetadataFromPNG(Metadata* const metadata) { + int p; + for (p = 0; p < 2; ++p) { + png_infop const info = (p == 0) ? info_ : end_info_; + png_textp text = NULL; + const int num = png_get_text(png_, info, &text, NULL); + int i; + // Look for EXIF / XMP metadata. + for (i = 0; i < num; ++i, ++text) { + int j; + for (j = 0; png_metadata_map_[j].name != NULL; ++j) { + if (!strcmp(text->key, png_metadata_map_[j].name)) { + MetadataPayload* const payload = + (MetadataPayload*)((uint8_t*)metadata + + png_metadata_map_[j].storage_offset); + png_size_t text_length; + switch (text->compression) { +#ifdef PNG_iTXt_SUPPORTED + case PNG_ITXT_COMPRESSION_NONE: + case PNG_ITXT_COMPRESSION_zTXt: + text_length = text->itxt_length; + break; +#endif + case PNG_TEXT_COMPRESSION_NONE: + case PNG_TEXT_COMPRESSION_zTXt: + default: + text_length = text->text_length; + break; + } + if (payload->bytes != NULL) { + TS_DEBUG(TAG, "Ignoring additional '%s'\n", text->key); + } else if (!png_metadata_map_[j].process(text->text, text_length, + payload)) { + TS_DEBUG(TAG, "Failed to process: '%s'\n", text->key); + return 0; + } + break; + } + } + } + // Look for an ICC profile. + { + png_charp name; + int comp_type; +#if ((PNG_LIBPNG_VER_MAJOR << 8) | PNG_LIBPNG_VER_MINOR << 0) < \ + ((1 << 8) | (5 << 0)) + png_charp profile; +#else // >= libpng 1.5.0 + png_bytep profile; +#endif + png_uint_32 len; + + if (png_get_iCCP(png_, info, + &name, &comp_type, &profile, &len) == PNG_INFO_iCCP) { + if (!MetadataCopy((const char*)profile, len, &metadata->iccp)) return 0; + } + } + } + + return 1; +} + +bool +PngDec::Init(std::stringstream* img) { + input_img_ = img; + png_ = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); + if (png_ == NULL) { + TS_DEBUG(TAG, "Error! Unable to create read structure"); + return false; + } + + png_set_error_fn(png_, 0, PngDec::ErrorFunction, NULL); + if (setjmp(png_jmpbuf(png_))) { + TS_DEBUG(TAG, "Error! setjmp failed"); + return false; + } + + info_ = png_create_info_struct(png_); + if (info_ == NULL) { + TS_DEBUG(TAG, "Error! could not create info struct for info_"); + return false; + } + end_info_ = png_create_info_struct(png_); + if (end_info_ == NULL) { + TS_DEBUG(TAG, "Error! could not create info struct for info_"); + return false; + } + + //png_init_io(png, in_file); + png_set_read_fn(png_, (void *)this, PngDec::ReadFunction); + png_read_info(png_, info_); + init_= true; + return true; +} + +void +PngDec::Finalize() { + + if (init_ && png_ != NULL) { + png_destroy_read_struct((png_structpp)&png_,(png_infopp)&info_, (png_infopp)&end_info_); + png_ = NULL; + info_ = end_info_ = NULL; + } +} + +int +PngDec::ReadImage(WebPPicture* const pic, Metadata* const metadata) { + + int color_type, bit_depth, interlaced; + int has_alpha; + int num_passes; + int p; + int ok = 0; + png_uint_32 width, height, y; + int stride; + uint8_t* volatile rgb = NULL; + + + if (!png_get_IHDR(png_, info_, + &width, &height, &bit_depth, &color_type, &interlaced, + NULL, NULL)) { + TS_DEBUG(TAG, "failed to get IHDR"); + return false; + } + + png_set_strip_16(png_); + png_set_packing(png_); + if (color_type == PNG_COLOR_TYPE_PALETTE) { + png_set_palette_to_rgb(png_); + } + if (color_type == PNG_COLOR_TYPE_GRAY || + color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { + if (bit_depth < 8) { + png_set_expand_gray_1_2_4_to_8(png_); + } + png_set_gray_to_rgb(png_); + } + if (png_get_valid(png_, info_, PNG_INFO_tRNS)) { + png_set_tRNS_to_alpha(png_); + has_alpha = 1; + } else { + has_alpha = !!(color_type & PNG_COLOR_MASK_ALPHA); + } + + num_passes = png_set_interlace_handling(png_); + png_read_update_info(png_, info_); + stride = (has_alpha ? 4 : 3) * width * sizeof(*rgb); + rgb = (uint8_t*)malloc(stride * height); + if (rgb == NULL) return false; + for (p = 0; p < num_passes; ++p) { + for (y = 0; y < height; ++y) { + png_bytep row = (png_bytep)(rgb + y * stride); + png_read_rows(png_, &row, NULL, 1); + } + } + png_read_end(png_, end_info_); + + if (metadata != NULL && + !ExtractMetadataFromPNG(metadata)) { + TS_DEBUG(TAG, "Error!! extracting PNG metadata!"); + free(rgb); + return false; + } + + pic->width = width; + pic->height = height; + pic->use_argb = 1; + ok = has_alpha ? WebPPictureImportRGBA(pic, rgb, stride) + : WebPPictureImportRGB(pic, rgb, stride); + + free(rgb); + return ok; +} + + +bool +PngDec::ReadData(png_bytep data, png_size_t length) { + input_img_->read((char *)data, length); + return true; +} diff --git a/lib/atscppapi/examples/webp_transform/pngdec.h b/lib/atscppapi/examples/webp_transform/pngdec.h new file mode 100644 index 00000000000..a7918d0743b --- /dev/null +++ b/lib/atscppapi/examples/webp_transform/pngdec.h @@ -0,0 +1,51 @@ +#ifndef PNGDEC_H_ +#define PNGDEC_H_ + +#include +#include +#include +#include +#include +#include "pngdec.h" +#include "metadata.h" + +struct WebPPicture; + +class PngDec { +public: + PngDec() : init_(false), input_img_(NULL), info_(NULL), end_info_(NULL) + {} + ~PngDec() { } + bool Init(std::stringstream* img); + int ReadImage(struct WebPPicture* const pic, struct Metadata* const metadata); + void Finalize(); + +#ifndef UNIT_TESTING +private: +#endif + + struct PNGMetadataMap { + const char* name; + int (*process)(const char* profile, size_t profile_len, + MetadataPayload* const payload); + size_t storage_offset; + }; + + void Read(png_structp pngPtr, png_bytep data, png_size_t length); + int ExtractMetadataFromPNG(Metadata* const metadata); + + static uint8_t* HexStringToBytes(const char* hexstring, size_t expected_length); + static int ProcessRawProfile(const char* profile, size_t profile_len, MetadataPayload* const payload); + static void ReadFunction(png_structp pngPtr, png_bytep data, png_size_t length); + static void ErrorFunction(png_structp png, png_const_charp error); + bool ReadData(png_bytep data, png_size_t len); + + + bool init_; + std::stringstream* input_img_; + volatile png_structp png_; + volatile png_infop info_; + volatile png_infop end_info_; + static PNGMetadataMap png_metadata_map_[]; +}; +#endif // PNGDEC_H_ From 7f2c2b66037588902434512cc63626d567ed9ab9 Mon Sep 17 00:00:00 2001 From: Sandeep Davu Date: Tue, 22 Dec 2015 15:48:22 -0800 Subject: [PATCH 02/19] [TS-4095] remove context value. Add license agreement. --- .../examples/webp_transform/Common.h | 28 +++++++++--- .../examples/webp_transform/ImageTransform.cc | 43 ++++++------------- .../examples/webp_transform/ImageTransform.h | 40 +++++++++++------ .../examples/webp_transform/compress.cc | 29 ++++++++++--- .../examples/webp_transform/compress.h | 25 ++++++++++- .../examples/webp_transform/jpegdec.cc | 17 ++++++++ .../examples/webp_transform/jpegdec.h | 18 ++++++++ .../examples/webp_transform/metadata.cc | 18 ++++++++ .../examples/webp_transform/metadata.h | 18 ++++++++ .../examples/webp_transform/pngdec.cc | 18 ++++++++ .../examples/webp_transform/pngdec.h | 18 ++++++++ 11 files changed, 215 insertions(+), 57 deletions(-) diff --git a/lib/atscppapi/examples/webp_transform/Common.h b/lib/atscppapi/examples/webp_transform/Common.h index 7794631b775..3f1f2f78818 100644 --- a/lib/atscppapi/examples/webp_transform/Common.h +++ b/lib/atscppapi/examples/webp_transform/Common.h @@ -1,9 +1,25 @@ -/* - * Common.h - * - * Created on: Jul 30, 2015 - * Author: sdavu - */ +/** @file + + ATSCPPAPI plugin to do webp transform. + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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. +*/ #ifndef COMMON_H_ #define COMMON_H_ diff --git a/lib/atscppapi/examples/webp_transform/ImageTransform.cc b/lib/atscppapi/examples/webp_transform/ImageTransform.cc index 209fb50b29c..b56e0667078 100644 --- a/lib/atscppapi/examples/webp_transform/ImageTransform.cc +++ b/lib/atscppapi/examples/webp_transform/ImageTransform.cc @@ -33,15 +33,15 @@ std::string ImageTransform::FIELD_USER_AGENT("User-Agent"); std::string ImageTransform::FIELD_CONTENT_TYPE("Content-Type"); std::string ImageTransform::FIELD_TRANSFORM_IMAGE("@X-Transform-Image"); std::string ImageTransform::CONTEXT_IMG_TRANSFORM("Transform-Image"); -std::string ImageTransform::USER_AGENT_CROME("Chrome"); +std::string ImageTransform::USER_AGENT_CHROME("Chrome"); +std::string ImageTransform::FIELD_VARY("Vary"); +std::string ImageTransform::IMAGE_TYPE("image/webp"); -ImageTransform::ImageTransform(Transaction &transaction, TransformationPlugin::Type xformType) -: TransformationPlugin(transaction, xformType), +ImageTransform::ImageTransform(Transaction &transaction) +: TransformationPlugin(transaction, TransformationPlugin::RESPONSE_TRANSFORMATION), webp_transform_(){ - TransactionPlugin::registerHook(HOOK_SEND_REQUEST_HEADERS); - TransformationPlugin::registerHook((xformType == TransformationPlugin::REQUEST_TRANSFORMATION) ? - HOOK_SEND_REQUEST_HEADERS : HOOK_READ_RESPONSE_HEADERS); + TransformationPlugin::registerHook(HOOK_READ_RESPONSE_HEADERS); } ImageTransform::~ImageTransform() { @@ -51,9 +51,8 @@ ImageTransform::~ImageTransform() { void ImageTransform::handleReadResponseHeaders(Transaction &transaction) { - Headers& headers = transaction.getServerResponse().getHeaders(); - headers.set("Vary", ImageTransform::FIELD_TRANSFORM_IMAGE); - headers.set(ImageTransform::FIELD_CONTENT_TYPE, "image/webp"); + transaction.getClientResponse().getHeaders()[ImageTransform::FIELD_CONTENT_TYPE] = ImageTransform::IMAGE_TYPE; + transaction.getClientResponse().getHeaders()[ImageTransform::FIELD_VARY] = ImageTransform::ImageTransform::FIELD_CONTENT_TYPE; TS_DEBUG(TAG, "Image Transformation Plugin for url %s", transaction.getServerRequest().getUrl().getUrlString().c_str() ); transaction.resume(); @@ -73,34 +72,18 @@ ImageTransform::handleInputComplete() { setOutputComplete(); } - GlobalHookPlugin::GlobalHookPlugin() { - registerHook(HOOK_READ_REQUEST_HEADERS); registerHook(HOOK_READ_RESPONSE_HEADERS); } -void -GlobalHookPlugin::handleReadRequestHeaders(Transaction &transaction) { - //add transformation only for jpeg files - Headers& hdrs = transaction.getClientRequest().getHeaders(); - string uagent = hdrs.values(ImageTransform::FIELD_USER_AGENT); - if(uagent.find(ImageTransform::USER_AGENT_CROME) != string::npos) { - TS_DEBUG(TAG, "Setting Context for useragent chrome."); - transaction.setContextValue(ImageTransform::CONTEXT_IMG_TRANSFORM, shared_ptr(new ImageValue(true))); - transaction.getClientRequest().getHeaders().set(ImageTransform::FIELD_TRANSFORM_IMAGE, "1"); - } - transaction.resume(); -} - void GlobalHookPlugin::handleReadResponseHeaders(Transaction &transaction) { //add transformation only for jpeg files - Headers& hdrs = transaction.getServerResponse().getHeaders(); - string ctype = hdrs.values(ImageTransform::FIELD_CONTENT_TYPE); - ImageValue* img_context = dynamic_cast(transaction.getContextValue(ImageTransform::CONTEXT_IMG_TRANSFORM).get()); - if(img_context && (ctype.find("jpeg") != string::npos || ctype.find("png") != string::npos)) { - //modify clientrequest at this point. Lets see if this will effect the caching. - transaction.addPlugin(new ImageTransform(transaction, TransformationPlugin::RESPONSE_TRANSFORMATION)); + string ctype = transaction.getServerResponse().getHeaders().values(ImageTransform::FIELD_CONTENT_TYPE); + string user_agent = transaction.getServerRequest().getHeaders().values(ImageTransform::FIELD_USER_AGENT) ; + if(user_agent.find(ImageTransform::USER_AGENT_CHROME) != string::npos && + (ctype.find("jpeg") != string::npos || ctype.find("png") != string::npos)) { + transaction.addPlugin(new ImageTransform(transaction)); } transaction.resume(); } diff --git a/lib/atscppapi/examples/webp_transform/ImageTransform.h b/lib/atscppapi/examples/webp_transform/ImageTransform.h index eaf6784e9b3..8c08fe2ba63 100644 --- a/lib/atscppapi/examples/webp_transform/ImageTransform.h +++ b/lib/atscppapi/examples/webp_transform/ImageTransform.h @@ -1,9 +1,25 @@ -/* - * ImageTransfrom.h - * - * Created on: Aug 6, 2015 - * Author: sdavu - */ +/** @file + + ATSCPPAPI plugin to do webp transform. + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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. +*/ #ifndef IMAGETRANSFROM_H_ #define IMAGETRANSFROM_H_ @@ -14,15 +30,10 @@ #include #include -struct ImageValue: public atscppapi::Transaction::ContextValue{ - bool do_transform_; - ImageValue(bool transform) : do_transform_(transform) { } -}; - class ImageTransform : public atscppapi::TransformationPlugin { public: - ImageTransform(atscppapi::Transaction &transaction, atscppapi::TransformationPlugin::Type xformType); + ImageTransform(atscppapi::Transaction &transaction); void handleReadResponseHeaders(atscppapi::Transaction &transaction); void consume(const std::string &data); @@ -32,8 +43,10 @@ class ImageTransform : public atscppapi::TransformationPlugin { static std::string FIELD_USER_AGENT; static std::string FIELD_TRANSFORM_IMAGE; static std::string CONTEXT_IMG_TRANSFORM; - static std::string USER_AGENT_CROME; + static std::string USER_AGENT_CHROME; static std::string FIELD_CONTENT_TYPE; + static std::string FIELD_VARY; + static std::string IMAGE_TYPE; private: std::stringstream img_; @@ -43,7 +56,6 @@ class ImageTransform : public atscppapi::TransformationPlugin { class GlobalHookPlugin : public atscppapi::GlobalPlugin { public: GlobalHookPlugin(); - virtual void handleReadRequestHeaders(atscppapi::Transaction &transaction); virtual void handleReadResponseHeaders(atscppapi::Transaction &transaction); }; diff --git a/lib/atscppapi/examples/webp_transform/compress.cc b/lib/atscppapi/examples/webp_transform/compress.cc index 8d59fedea2f..ac73fc93740 100644 --- a/lib/atscppapi/examples/webp_transform/compress.cc +++ b/lib/atscppapi/examples/webp_transform/compress.cc @@ -1,3 +1,26 @@ +/** @file + + ATSCPPAPI plugin to do webp transform. + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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. +*/ + #include #include #include @@ -65,8 +88,6 @@ WebpTransform::GetImageType(std::stringstream& input_img) { format = PNG_; } else if (magic1 >= 0xFFD8FF00U && magic1 <= 0xFFD8FFFFU) { format = JPEG_; - } else if (magic1 == 0x49492A00 || magic1 == 0x4D4D002A) { - format = TIFF_; } else if (magic1 == 0x52494646 && magic2 == 0x57454250) { format = WEBP_; } @@ -92,14 +113,12 @@ WebpTransform::ReadImage(std::stringstream& input_img) { return 0; } ok = jpeg_dec_.ReadImage(&picture_, &metadata_); - } else if (format == TIFF_) { - TS_DEBUG(TAG, "Cannot read tiff files."); } else if (format == WEBP_) { TS_DEBUG(TAG, "Already webp file. Nothing to be done."); } } if (!ok) - TS_DEBUG(TAG, "failed to read image."); + TS_DEBUG(TAG, "Unsupported image format. Failed to read image."); return ok; } diff --git a/lib/atscppapi/examples/webp_transform/compress.h b/lib/atscppapi/examples/webp_transform/compress.h index 921b47e9d88..9133b664534 100644 --- a/lib/atscppapi/examples/webp_transform/compress.h +++ b/lib/atscppapi/examples/webp_transform/compress.h @@ -1,5 +1,27 @@ +/** @file -#ifndef WEBPCOMPRESS_H_ + ATSCPPAPI plugin to do webp transform. + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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. +*/ + +#ifndef WEBPTRANSFORM_H_ #define WEBPTRANSFORM_H_ #include @@ -32,7 +54,6 @@ class WebpTransform { typedef enum { PNG_ = 0, JPEG_, - TIFF_, // 'TIFF' clashes with libtiff WEBP_, UNSUPPORTED } InputFileFormat; diff --git a/lib/atscppapi/examples/webp_transform/jpegdec.cc b/lib/atscppapi/examples/webp_transform/jpegdec.cc index a11cf71fad8..9c54de58afc 100644 --- a/lib/atscppapi/examples/webp_transform/jpegdec.cc +++ b/lib/atscppapi/examples/webp_transform/jpegdec.cc @@ -1,3 +1,20 @@ +/** + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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. + */ #include diff --git a/lib/atscppapi/examples/webp_transform/jpegdec.h b/lib/atscppapi/examples/webp_transform/jpegdec.h index 59133af6cb7..8e4280edfce 100644 --- a/lib/atscppapi/examples/webp_transform/jpegdec.h +++ b/lib/atscppapi/examples/webp_transform/jpegdec.h @@ -1,3 +1,21 @@ +/** + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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. + */ + #ifndef JPEGDEC_H_ #define JPEGDEC_H_ diff --git a/lib/atscppapi/examples/webp_transform/metadata.cc b/lib/atscppapi/examples/webp_transform/metadata.cc index 5a5f2f50876..3f46fb8af97 100644 --- a/lib/atscppapi/examples/webp_transform/metadata.cc +++ b/lib/atscppapi/examples/webp_transform/metadata.cc @@ -1,3 +1,21 @@ +/** + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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. + */ + #include #include diff --git a/lib/atscppapi/examples/webp_transform/metadata.h b/lib/atscppapi/examples/webp_transform/metadata.h index 4d8c9492fba..dc8a550bf03 100644 --- a/lib/atscppapi/examples/webp_transform/metadata.h +++ b/lib/atscppapi/examples/webp_transform/metadata.h @@ -1,3 +1,21 @@ +/** + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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. + */ + #ifndef METADATA_H_ #define METADATA_H_ diff --git a/lib/atscppapi/examples/webp_transform/pngdec.cc b/lib/atscppapi/examples/webp_transform/pngdec.cc index 713c621bf89..50391b71229 100644 --- a/lib/atscppapi/examples/webp_transform/pngdec.cc +++ b/lib/atscppapi/examples/webp_transform/pngdec.cc @@ -1,3 +1,21 @@ +/** + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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. + */ + #include #include #include diff --git a/lib/atscppapi/examples/webp_transform/pngdec.h b/lib/atscppapi/examples/webp_transform/pngdec.h index a7918d0743b..58058a966a9 100644 --- a/lib/atscppapi/examples/webp_transform/pngdec.h +++ b/lib/atscppapi/examples/webp_transform/pngdec.h @@ -1,3 +1,21 @@ +/** + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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. + */ + #ifndef PNGDEC_H_ #define PNGDEC_H_ From da5007fb4fe19acf426a9beffca17b89030a7934 Mon Sep 17 00:00:00 2001 From: Sandeep Davu Date: Tue, 22 Dec 2015 16:11:28 -0800 Subject: [PATCH 03/19] [TS-4095] remove ifdef UNIT_TESTING] --- lib/atscppapi/examples/webp_transform/compress.h | 2 -- lib/atscppapi/examples/webp_transform/pngdec.h | 2 -- 2 files changed, 4 deletions(-) diff --git a/lib/atscppapi/examples/webp_transform/compress.h b/lib/atscppapi/examples/webp_transform/compress.h index 9133b664534..b23c9cb09f1 100644 --- a/lib/atscppapi/examples/webp_transform/compress.h +++ b/lib/atscppapi/examples/webp_transform/compress.h @@ -48,9 +48,7 @@ class WebpTransform { std::stringstream& getTransformedImage() { return stream_; } void WriteImage(const char* data, size_t data_size); -#ifndef UNIT_TESTING private: -#endif typedef enum { PNG_ = 0, JPEG_, diff --git a/lib/atscppapi/examples/webp_transform/pngdec.h b/lib/atscppapi/examples/webp_transform/pngdec.h index 58058a966a9..25f061a7754 100644 --- a/lib/atscppapi/examples/webp_transform/pngdec.h +++ b/lib/atscppapi/examples/webp_transform/pngdec.h @@ -38,9 +38,7 @@ class PngDec { int ReadImage(struct WebPPicture* const pic, struct Metadata* const metadata); void Finalize(); -#ifndef UNIT_TESTING private: -#endif struct PNGMetadataMap { const char* name; From 18e2c635ce49d00fca1af515fe0007d165a57c80 Mon Sep 17 00:00:00 2001 From: Sandeep Davu Date: Tue, 22 Dec 2015 16:20:53 -0800 Subject: [PATCH 04/19] [TS-4095] clang-formatting --- .../examples/webp_transform/ImageTransform.cc | 61 +++--- .../examples/webp_transform/ImageTransform.h | 9 +- .../examples/webp_transform/compress.cc | 115 ++++++----- .../examples/webp_transform/compress.h | 79 ++++---- .../examples/webp_transform/jpegdec.cc | 152 ++++++++------- .../examples/webp_transform/jpegdec.h | 47 +++-- .../examples/webp_transform/metadata.cc | 35 ++-- .../examples/webp_transform/metadata.h | 15 +- .../examples/webp_transform/pngdec.cc | 183 +++++++++--------- .../examples/webp_transform/pngdec.h | 52 +++-- 10 files changed, 382 insertions(+), 366 deletions(-) diff --git a/lib/atscppapi/examples/webp_transform/ImageTransform.cc b/lib/atscppapi/examples/webp_transform/ImageTransform.cc index b56e0667078..6ec5e4ffbf2 100644 --- a/lib/atscppapi/examples/webp_transform/ImageTransform.cc +++ b/lib/atscppapi/examples/webp_transform/ImageTransform.cc @@ -39,13 +39,14 @@ std::string ImageTransform::IMAGE_TYPE("image/webp"); ImageTransform::ImageTransform(Transaction &transaction) -: TransformationPlugin(transaction, TransformationPlugin::RESPONSE_TRANSFORMATION), - webp_transform_(){ - TransformationPlugin::registerHook(HOOK_READ_RESPONSE_HEADERS); + : TransformationPlugin(transaction, TransformationPlugin::RESPONSE_TRANSFORMATION), webp_transform_() +{ + TransformationPlugin::registerHook(HOOK_READ_RESPONSE_HEADERS); } -ImageTransform::~ImageTransform() { - webp_transform_.Finalize(); +ImageTransform::~ImageTransform() +{ + webp_transform_.Finalize(); } void @@ -54,41 +55,47 @@ ImageTransform::handleReadResponseHeaders(Transaction &transaction) transaction.getClientResponse().getHeaders()[ImageTransform::FIELD_CONTENT_TYPE] = ImageTransform::IMAGE_TYPE; transaction.getClientResponse().getHeaders()[ImageTransform::FIELD_VARY] = ImageTransform::ImageTransform::FIELD_CONTENT_TYPE; - TS_DEBUG(TAG, "Image Transformation Plugin for url %s", transaction.getServerRequest().getUrl().getUrlString().c_str() ); - transaction.resume(); + TS_DEBUG(TAG, "Image Transformation Plugin for url %s", transaction.getServerRequest().getUrl().getUrlString().c_str()); + transaction.resume(); } void -ImageTransform::consume(const string &data) { - img_.write(data.data(), data.size()); +ImageTransform::consume(const string &data) +{ + img_.write(data.data(), data.size()); } void -ImageTransform::handleInputComplete() { - webp_transform_.Init(); - webp_transform_.Transform(img_); - produce(webp_transform_.getTransformedImage().str()); +ImageTransform::handleInputComplete() +{ + webp_transform_.Init(); + webp_transform_.Transform(img_); + produce(webp_transform_.getTransformedImage().str()); - setOutputComplete(); + setOutputComplete(); } -GlobalHookPlugin::GlobalHookPlugin() { - registerHook(HOOK_READ_RESPONSE_HEADERS); +GlobalHookPlugin::GlobalHookPlugin() +{ + registerHook(HOOK_READ_RESPONSE_HEADERS); } void -GlobalHookPlugin::handleReadResponseHeaders(Transaction &transaction) { - //add transformation only for jpeg files - string ctype = transaction.getServerResponse().getHeaders().values(ImageTransform::FIELD_CONTENT_TYPE); - string user_agent = transaction.getServerRequest().getHeaders().values(ImageTransform::FIELD_USER_AGENT) ; - if(user_agent.find(ImageTransform::USER_AGENT_CHROME) != string::npos && - (ctype.find("jpeg") != string::npos || ctype.find("png") != string::npos)) { +GlobalHookPlugin::handleReadResponseHeaders(Transaction &transaction) +{ + // add transformation only for jpeg files + string ctype = transaction.getServerResponse().getHeaders().values(ImageTransform::FIELD_CONTENT_TYPE); + string user_agent = transaction.getServerRequest().getHeaders().values(ImageTransform::FIELD_USER_AGENT); + if (user_agent.find(ImageTransform::USER_AGENT_CHROME) != string::npos && + (ctype.find("jpeg") != string::npos || ctype.find("png") != string::npos)) { transaction.addPlugin(new ImageTransform(transaction)); - } - transaction.resume(); + } + transaction.resume(); } -void TSPluginInit(int argc ATSCPPAPI_UNUSED, const char *argv[] ATSCPPAPI_UNUSED) { - TS_DEBUG(TAG, "TSPluginInit"); - new GlobalHookPlugin(); +void +TSPluginInit(int argc ATSCPPAPI_UNUSED, const char *argv[] ATSCPPAPI_UNUSED) +{ + TS_DEBUG(TAG, "TSPluginInit"); + new GlobalHookPlugin(); } diff --git a/lib/atscppapi/examples/webp_transform/ImageTransform.h b/lib/atscppapi/examples/webp_transform/ImageTransform.h index 8c08fe2ba63..79c8d436f90 100644 --- a/lib/atscppapi/examples/webp_transform/ImageTransform.h +++ b/lib/atscppapi/examples/webp_transform/ImageTransform.h @@ -31,9 +31,10 @@ #include -class ImageTransform : public atscppapi::TransformationPlugin { +class ImageTransform : public atscppapi::TransformationPlugin +{ public: - ImageTransform(atscppapi::Transaction &transaction); + ImageTransform(atscppapi::Transaction &transaction); void handleReadResponseHeaders(atscppapi::Transaction &transaction); void consume(const std::string &data); @@ -53,12 +54,12 @@ class ImageTransform : public atscppapi::TransformationPlugin { WebpTransform webp_transform_; }; -class GlobalHookPlugin : public atscppapi::GlobalPlugin { +class GlobalHookPlugin : public atscppapi::GlobalPlugin +{ public: GlobalHookPlugin(); virtual void handleReadResponseHeaders(atscppapi::Transaction &transaction); }; - #endif /* IMAGETRANSFROM_H_ */ diff --git a/lib/atscppapi/examples/webp_transform/compress.cc b/lib/atscppapi/examples/webp_transform/compress.cc index ac73fc93740..26dee8e1427 100644 --- a/lib/atscppapi/examples/webp_transform/compress.cc +++ b/lib/atscppapi/examples/webp_transform/compress.cc @@ -32,24 +32,21 @@ #include "Common.h" #define MAGIC_SIZE 12; -using std::string; -using std::vector; +using std::string; +using std::vector; static int -StreamWriter(const uint8_t* data, size_t data_size, - const WebPPicture* const pic) { - WebpTransform* webp_transform = static_cast(pic->custom_ptr); - webp_transform->WriteImage(reinterpret_cast(data), data_size); +StreamWriter(const uint8_t *data, size_t data_size, const WebPPicture *const pic) +{ + WebpTransform *webp_transform = static_cast(pic->custom_ptr); + webp_transform->WriteImage(reinterpret_cast(data), data_size); return data_size ? data_size : 1; } const string WebpTransform::errors_[] = { - "OK", - "OUT_OF_MEMORY: Out of memory allocating objects", - "BITSTREAM_OUT_OF_MEMORY: Out of memory re-allocating byte buffer", - "NULL_PARAMETER: NULL parameter passed to function", - "INVALID_CONFIGURATION: configuration is invalid", + "OK", "OUT_OF_MEMORY: Out of memory allocating objects", "BITSTREAM_OUT_OF_MEMORY: Out of memory re-allocating byte buffer", + "NULL_PARAMETER: NULL parameter passed to function", "INVALID_CONFIGURATION: configuration is invalid", "BAD_DIMENSION: Bad picture dimension. Maximum width and height " "allowed is 16383 pixels.", "PARTITION0_OVERFLOW: Partition #0 is too big to fit 512k.\n" @@ -57,25 +54,24 @@ const string WebpTransform::errors_[] = { "with the -segments option, and eventually reduce the number of " "header bits using -partition_limit. More details are available " "in the manual (`man cwebp`)", - "PARTITION_OVERFLOW: Partition is too big to fit 16M", - "BAD_WRITE: Picture writer returned an I/O error", - "FILE_TOO_BIG: File would be too big to fit in 4G", - "USER_ABORT: encoding abort requested by user" -}; + "PARTITION_OVERFLOW: Partition is too big to fit 16M", "BAD_WRITE: Picture writer returned an I/O error", + "FILE_TOO_BIG: File would be too big to fit in 4G", "USER_ABORT: encoding abort requested by user"}; void -WebpTransform::WebPMemoryWriterClear() { - if(writer_.mem != NULL) { +WebpTransform::WebPMemoryWriterClear() +{ + if (writer_.mem != NULL) { free(writer_.mem); writer_.mem = NULL; writer_.size = 0; writer_.max_size = 0; - } + } } WebpTransform::InputFileFormat -WebpTransform::GetImageType(std::stringstream& input_img) { +WebpTransform::GetImageType(std::stringstream &input_img) +{ InputFileFormat format = UNSUPPORTED; uint32_t magic1, magic2; uint8_t buf[12]; @@ -95,105 +91,108 @@ WebpTransform::GetImageType(std::stringstream& input_img) { } int -WebpTransform::ReadImage(std::stringstream& input_img) { +WebpTransform::ReadImage(std::stringstream &input_img) +{ int ok = 0; if (picture_.width == 0 || picture_.height == 0) { // If no size specified, try to decode it as PNG/JPEG (as appropriate). const InputFileFormat format = GetImageType(input_img); if (format == PNG_) { - if(!png_dec_.Init(&input_img)) { - png_dec_.Finalize(); - return 0; + if (!png_dec_.Init(&input_img)) { + png_dec_.Finalize(); + return 0; } ok = png_dec_.ReadImage(&picture_, &metadata_); } else if (format == JPEG_) { - if(!jpeg_dec_.Init(&input_img)) { - jpeg_dec_.Finalize(); - return 0; + if (!jpeg_dec_.Init(&input_img)) { + jpeg_dec_.Finalize(); + return 0; } ok = jpeg_dec_.ReadImage(&picture_, &metadata_); } else if (format == WEBP_) { - TS_DEBUG(TAG, "Already webp file. Nothing to be done."); + TS_DEBUG(TAG, "Already webp file. Nothing to be done."); } } if (!ok) - TS_DEBUG(TAG, "Unsupported image format. Failed to read image."); + TS_DEBUG(TAG, "Unsupported image format. Failed to read image."); return ok; } void -WebpTransform::AllocExtraInfo() { +WebpTransform::AllocExtraInfo() +{ const int mb_w = (picture_.width + 15) / 16; const int mb_h = (picture_.height + 15) / 16; - picture_.extra_info = (uint8_t*)malloc(mb_w * mb_h * sizeof(picture_.extra_info)); + picture_.extra_info = (uint8_t *)malloc(mb_w * mb_h * sizeof(picture_.extra_info)); } bool -WebpTransform::Init() { +WebpTransform::Init() +{ MetadataInit(&metadata_); WebPMemoryWriterInit(&writer_); if (!WebPPictureInit(&picture_) || !WebPConfigInit(&config_)) { - TS_DEBUG(TAG, "DEBUG! Version mismatch"); + TS_DEBUG(TAG, "DEBUG! Version mismatch"); return false; } WebPPreset preset = WEBP_PRESET_PICTURE; if (!WebPConfigPreset(&config_, preset, config_.quality)) { - TS_DEBUG(TAG, "DEBUG! Could initialize configuration with preset."); + TS_DEBUG(TAG, "DEBUG! Could initialize configuration with preset."); return false; } if (!WebPValidateConfig(&config_)) { - TS_DEBUG(TAG, "DEBUG! Invalid configuration."); + TS_DEBUG(TAG, "DEBUG! Invalid configuration."); return false; } - init_ =true; + init_ = true; return true; } bool -WebpTransform::Transform(std::stringstream& input_img) { - - - if (!ReadImage(input_img) ) { - TS_DEBUG(TAG, "Cannot read input picture file ."); +WebpTransform::Transform(std::stringstream &input_img) +{ + if (!ReadImage(input_img)) { + TS_DEBUG(TAG, "Cannot read input picture file ."); return false; } - picture_.progress_hook = NULL; + picture_.progress_hook = NULL; picture_.writer = StreamWriter; - picture_.custom_ptr = (void*)this; + picture_.custom_ptr = (void *)this; if (picture_.extra_info_type > 0) { AllocExtraInfo(); } if (!WebPEncode(&config_, &picture_)) { - - TS_DEBUG(TAG, "DEBUG! Cannot encode picture as WebP. Error code: %d (%s)", - picture_.error_code, WebpTransform::errors_[picture_.error_code].c_str()); + TS_DEBUG(TAG, "DEBUG! Cannot encode picture as WebP. Error code: %d (%s)", picture_.error_code, + WebpTransform::errors_[picture_.error_code].c_str()); return false; } return true; } void -WebpTransform::Finalize() { - if(init_) { - WebPMemoryWriterClear(); - free(picture_.extra_info); - MetadataFree(&metadata_); - WebPPictureFree(&picture_); - - png_dec_.Finalize(); - jpeg_dec_.Finalize(); - } +WebpTransform::Finalize() +{ + if (init_) { + WebPMemoryWriterClear(); + free(picture_.extra_info); + MetadataFree(&metadata_); + WebPPictureFree(&picture_); + + png_dec_.Finalize(); + jpeg_dec_.Finalize(); + } } void -WebpTransform::WriteImage(const char* data, size_t data_size) { - stream_.write(data, data_size); +WebpTransform::WriteImage(const char *data, size_t data_size) +{ + stream_.write(data, data_size); } diff --git a/lib/atscppapi/examples/webp_transform/compress.h b/lib/atscppapi/examples/webp_transform/compress.h index b23c9cb09f1..8b6b4afd608 100644 --- a/lib/atscppapi/examples/webp_transform/compress.h +++ b/lib/atscppapi/examples/webp_transform/compress.h @@ -35,50 +35,49 @@ #include "metadata.h" -class WebpTransform { +class WebpTransform +{ public: - WebpTransform() :init_(false), png_dec_(), jpeg_dec_() - { } + WebpTransform() : init_(false), png_dec_(), jpeg_dec_() {} - ~WebpTransform() { } + ~WebpTransform() {} - bool Init(); - bool Transform(std::stringstream& stream); - void Finalize(); - std::stringstream& getTransformedImage() { return stream_; } - void WriteImage(const char* data, size_t data_size); + bool Init(); + bool Transform(std::stringstream &stream); + void Finalize(); + std::stringstream & + getTransformedImage() + { + return stream_; + } + void WriteImage(const char *data, size_t data_size); private: - typedef enum { - PNG_ = 0, - JPEG_, - WEBP_, - UNSUPPORTED - } InputFileFormat; - - enum { - METADATA_EXIF = (1 << 0), - METADATA_ICC = (1 << 1), - METADATA_XMP = (1 << 2), - METADATA_ALL = METADATA_EXIF | METADATA_ICC | METADATA_XMP - }; - - InputFileFormat GetImageType(std::stringstream& input_msg); - int ReadImage(std::stringstream& input_img); - void AllocExtraInfo(); - - void WebPMemoryWriterClear(); - - static const std::string errors_[]; - bool init_; - WebPMemoryWriter writer_; - std::stringstream stream_; - WebPPicture picture_; - WebPConfig config_; - Metadata metadata_; - std::string debug_tag_; - PngDec png_dec_; - JpegDec jpeg_dec_; + typedef enum { PNG_ = 0, JPEG_, WEBP_, UNSUPPORTED } InputFileFormat; + + enum { + METADATA_EXIF = (1 << 0), + METADATA_ICC = (1 << 1), + METADATA_XMP = (1 << 2), + METADATA_ALL = METADATA_EXIF | METADATA_ICC | METADATA_XMP + }; + + InputFileFormat GetImageType(std::stringstream &input_msg); + int ReadImage(std::stringstream &input_img); + void AllocExtraInfo(); + + void WebPMemoryWriterClear(); + + static const std::string errors_[]; + bool init_; + WebPMemoryWriter writer_; + std::stringstream stream_; + WebPPicture picture_; + WebPConfig config_; + Metadata metadata_; + std::string debug_tag_; + PngDec png_dec_; + JpegDec jpeg_dec_; }; -#endif // COMPRESS_H_ +#endif //WEBPTRANSFORM_H_ diff --git a/lib/atscppapi/examples/webp_transform/jpegdec.cc b/lib/atscppapi/examples/webp_transform/jpegdec.cc index 9c54de58afc..c0f90538083 100644 --- a/lib/atscppapi/examples/webp_transform/jpegdec.cc +++ b/lib/atscppapi/examples/webp_transform/jpegdec.cc @@ -33,33 +33,38 @@ JpegDec::JpegMetadataMap JpegDec::jpeg_metadata_map_[] = { - // Exif 2.2 Section 4.7.2 Interoperability Structure of APP1 ... - { JPEG_APP1, "Exif\0", 6, METADATA_OFFSET(exif) }, - // XMP Specification Part 3 Section 3 Embedding XMP Metadata ... #JPEG - // TODO(jzern) Add support for 'ExtendedXMP' - { JPEG_APP1, "http://ns.adobe.com/xap/1.0/", 29, METADATA_OFFSET(xmp) }, - { 0, NULL, 0, 0 }, - }; - -void JpegDec::SaveMetadataMarkers() { + // Exif 2.2 Section 4.7.2 Interoperability Structure of APP1 ... + {JPEG_APP1, "Exif\0", 6, METADATA_OFFSET(exif)}, + // XMP Specification Part 3 Section 3 Embedding XMP Metadata ... #JPEG + // TODO(jzern) Add support for 'ExtendedXMP' + {JPEG_APP1, "http://ns.adobe.com/xap/1.0/", 29, METADATA_OFFSET(xmp)}, + {0, NULL, 0, 0}, +}; + +void +JpegDec::SaveMetadataMarkers() +{ const unsigned int max_marker_length = 0xffff; - jpeg_save_markers((j_decompress_ptr)&dinfo_, JPEG_APP1, max_marker_length); // Exif/XMP - jpeg_save_markers((j_decompress_ptr)&dinfo_, JPEG_APP2, max_marker_length); // ICC profile + jpeg_save_markers((j_decompress_ptr)&dinfo_, JPEG_APP1, max_marker_length); // Exif/XMP + jpeg_save_markers((j_decompress_ptr)&dinfo_, JPEG_APP2, max_marker_length); // ICC profile } -int JpegDec::CompareICCPSegments(const void* a, const void* b) { - const ICCPSegment* s1 = (const ICCPSegment*)a; - const ICCPSegment* s2 = (const ICCPSegment*)b; +int +JpegDec::CompareICCPSegments(const void *a, const void *b) +{ + const ICCPSegment *s1 = (const ICCPSegment *)a; + const ICCPSegment *s2 = (const ICCPSegment *)b; return s1->seq - s2->seq; } int -JpegDec::StoreICCP(MetadataPayload* const iccp) { +JpegDec::StoreICCP(MetadataPayload *const iccp) +{ // ICC.1:2010-12 (4.3.0.0) Annex B.4 Embedding ICC Profiles in JPEG files static const char kICCPSignature[] = "ICC_PROFILE"; - static const size_t kICCPSignatureLength = 12; // signature includes '\0' - static const size_t kICCPSkipLength = 14; // signature + seq & count + static const size_t kICCPSignatureLength = 12; // signature includes '\0' + static const size_t kICCPSkipLength = 14; // signature + seq & count int expected_count = 0; int actual_count = 0; int seq_max = 0; @@ -69,31 +74,28 @@ JpegDec::StoreICCP(MetadataPayload* const iccp) { memset(iccp_segments, 0, sizeof(iccp_segments)); for (marker = dinfo_.marker_list; marker != NULL; marker = marker->next) { - if (marker->marker == JPEG_APP2 && - marker->data_length > kICCPSkipLength && + if (marker->marker == JPEG_APP2 && marker->data_length > kICCPSkipLength && !memcmp(marker->data, kICCPSignature, kICCPSignatureLength)) { // ICC_PROFILE\0; 'seq' starts at 1. const int seq = marker->data[kICCPSignatureLength]; const int count = marker->data[kICCPSignatureLength + 1]; const size_t segment_size = marker->data_length - kICCPSkipLength; - ICCPSegment* segment; + ICCPSegment *segment; if (segment_size == 0 || count == 0 || seq == 0) { - TS_DEBUG(TAG, "[ICCP] size (%d) / count (%d) / sequence number (%d) cannot be 0!", - (int)segment_size, seq, count); + TS_DEBUG(TAG, "[ICCP] size (%d) / count (%d) / sequence number (%d) cannot be 0!", (int)segment_size, seq, count); return 0; } if (expected_count == 0) { expected_count = count; } else if (expected_count != count) { - TS_DEBUG(TAG, "[ICCP] Inconsistent segment count (%d / %d)!\n", - expected_count, count); + TS_DEBUG(TAG, "[ICCP] Inconsistent segment count (%d / %d)!\n", expected_count, count); return 0; } segment = iccp_segments + seq - 1; if (segment->data_length != 0) { - TS_DEBUG(TAG, "[ICCP] Duplicate segment number (%d)!\n" , seq); + TS_DEBUG(TAG, "[ICCP] Duplicate segment number (%d)!\n", seq); return 0; } @@ -101,38 +103,37 @@ JpegDec::StoreICCP(MetadataPayload* const iccp) { segment->data_length = segment_size; segment->seq = seq; total_size += segment_size; - if (seq > seq_max) seq_max = seq; + if (seq > seq_max) + seq_max = seq; ++actual_count; } } - if (actual_count == 0) return 1; + if (actual_count == 0) + return 1; if (seq_max != actual_count) { - TS_DEBUG(TAG, "[ICCP] Discontinuous segments, expected: %d actual: %d!\n", - actual_count, seq_max); + TS_DEBUG(TAG, "[ICCP] Discontinuous segments, expected: %d actual: %d!\n", actual_count, seq_max); return 0; } if (expected_count != actual_count) { - TS_DEBUG(TAG, "[ICCP] Segment count: %d does not match expected: %d!\n", - actual_count, expected_count); + TS_DEBUG(TAG, "[ICCP] Segment count: %d does not match expected: %d!\n", actual_count, expected_count); return 0; } // The segments may appear out of order in the file, sort them based on // sequence number before assembling the payload. - qsort(iccp_segments, actual_count, sizeof(*iccp_segments), - JpegDec::CompareICCPSegments); + qsort(iccp_segments, actual_count, sizeof(*iccp_segments), JpegDec::CompareICCPSegments); - iccp->bytes = (uint8_t*)malloc(total_size); - if (iccp->bytes == NULL) return 0; + iccp->bytes = (uint8_t *)malloc(total_size); + if (iccp->bytes == NULL) + return 0; iccp->size = total_size; { int i; size_t offset = 0; for (i = 0; i < seq_max; ++i) { - memcpy(iccp->bytes + offset, - iccp_segments[i].data, iccp_segments[i].data_length); + memcpy(iccp->bytes + offset, iccp_segments[i].data, iccp_segments[i].data_length); offset += iccp_segments[i].data_length; } } @@ -142,31 +143,27 @@ JpegDec::StoreICCP(MetadataPayload* const iccp) { // Returns true on success and false for memory errors and corrupt profiles. // The caller must use MetadataFree() on 'metadata' in all cases. int -JpegDec::ExtractMetadataFromJPEG(Metadata* const metadata) { +JpegDec::ExtractMetadataFromJPEG(Metadata *const metadata) +{ jpeg_saved_marker_ptr marker; // Treat ICC profiles separately as they may be segmented and out of order. - if (!StoreICCP(&metadata->iccp)) return 0; + if (!StoreICCP(&metadata->iccp)) + return 0; for (marker = dinfo_.marker_list; marker != NULL; marker = marker->next) { int i; for (i = 0; jpeg_metadata_map_[i].marker != 0; ++i) { - if (marker->marker == jpeg_metadata_map_[i].marker && - marker->data_length > jpeg_metadata_map_[i].signature_length && - !memcmp(marker->data, jpeg_metadata_map_[i].signature, - jpeg_metadata_map_[i].signature_length)) { - MetadataPayload* const payload = - (MetadataPayload*)((uint8_t*)metadata + - jpeg_metadata_map_[i].storage_offset); + if (marker->marker == jpeg_metadata_map_[i].marker && marker->data_length > jpeg_metadata_map_[i].signature_length && + !memcmp(marker->data, jpeg_metadata_map_[i].signature, jpeg_metadata_map_[i].signature_length)) { + MetadataPayload *const payload = (MetadataPayload *)((uint8_t *)metadata + jpeg_metadata_map_[i].storage_offset); if (payload->bytes == NULL) { - const char* marker_data = (const char*)marker->data + - jpeg_metadata_map_[i].signature_length; - const size_t marker_data_length = - marker->data_length - jpeg_metadata_map_[i].signature_length; - if (!MetadataCopy(marker_data, marker_data_length, payload)) return 0; + const char *marker_data = (const char *)marker->data + jpeg_metadata_map_[i].signature_length; + const size_t marker_data_length = marker->data_length - jpeg_metadata_map_[i].signature_length; + if (!MetadataCopy(marker_data, marker_data_length, payload)) + return 0; } else { - TS_DEBUG(TAG, "Ignoring additional '%s' marker\n", - jpeg_metadata_map_[i].signature); + TS_DEBUG(TAG, "Ignoring additional '%s' marker\n", jpeg_metadata_map_[i].signature); } } } @@ -182,22 +179,24 @@ JpegDec::ExtractMetadataFromJPEG(Metadata* const metadata) { void -JpegDec::Error(j_common_ptr dinfo) { - struct JpegDec::ErrorMgr* err = (struct JpegDec::ErrorMgr*)dinfo->err; +JpegDec::Error(j_common_ptr dinfo) +{ + struct JpegDec::ErrorMgr *err = (struct JpegDec::ErrorMgr *)dinfo->err; dinfo->err->output_message(dinfo); longjmp(err->setjmp_buffer, 1); } bool -JpegDec::Init(std::stringstream* img) { - input_img_ = img; +JpegDec::Init(std::stringstream *img) +{ + input_img_ = img; - memset((j_decompress_ptr)&dinfo_, 0, sizeof(dinfo_)); // for setjmp sanity + memset((j_decompress_ptr)&dinfo_, 0, sizeof(dinfo_)); // for setjmp sanity dinfo_.err = jpeg_std_error(&jerr_.pub); jerr_.pub.error_exit = JpegDec::Error; if (setjmp(jerr_.setjmp_buffer)) { - TS_DEBUG(TAG, " setjmp failed"); + TS_DEBUG(TAG, " setjmp failed"); jpeg_destroy_decompress((j_decompress_ptr)&dinfo_); return false; } @@ -208,17 +207,19 @@ JpegDec::Init(std::stringstream* img) { } int -JpegDec::ReadImage(WebPPicture* const pic, Metadata* const metadata) { +JpegDec::ReadImage(WebPPicture *const pic, Metadata *const metadata) +{ int ok = 0; int stride, width, height; - uint8_t* volatile rgb = NULL; + uint8_t *volatile rgb = NULL; JSAMPROW buffer[1]; std::string img_str = input_img_->str(); - //TODO: Can this copy be avoided. - jpeg_mem_src((j_decompress_ptr)&dinfo_, (unsigned char*)img_str.data(), img_str.size()); + // TODO: Can this copy be avoided. + jpeg_mem_src((j_decompress_ptr)&dinfo_, (unsigned char *)img_str.data(), img_str.size()); - if (metadata != NULL) SaveMetadataMarkers(); + if (metadata != NULL) + SaveMetadataMarkers(); jpeg_read_header((j_decompress_ptr)&dinfo_, TRUE); dinfo_.out_color_space = JCS_RGB; @@ -227,7 +228,7 @@ JpegDec::ReadImage(WebPPicture* const pic, Metadata* const metadata) { jpeg_start_decompress((j_decompress_ptr)&dinfo_); if (dinfo_.output_components != 3) { - TS_DEBUG(TAG,"not enought output componenets available."); + TS_DEBUG(TAG, "not enought output componenets available."); return 0; } @@ -235,16 +236,16 @@ JpegDec::ReadImage(WebPPicture* const pic, Metadata* const metadata) { height = dinfo_.output_height; stride = dinfo_.output_width * dinfo_.output_components * sizeof(*rgb); - rgb = (uint8_t*)malloc(stride * height); + rgb = (uint8_t *)malloc(stride * height); if (rgb == NULL) { - TS_DEBUG(TAG,"unable to alloc memory for rgb."); + TS_DEBUG(TAG, "unable to alloc memory for rgb."); return 0; } - buffer[0] = (JSAMPLE*)rgb; + buffer[0] = (JSAMPLE *)rgb; while (dinfo_.output_scanline < dinfo_.output_height) { if (jpeg_read_scanlines((j_decompress_ptr)&dinfo_, buffer, 1) != 1) { - free(rgb); + free(rgb); return 0; } buffer[0] += stride; @@ -265,10 +266,10 @@ JpegDec::ReadImage(WebPPicture* const pic, Metadata* const metadata) { // WebP conversion. pic->width = width; pic->height = height; - pic->use_argb = 1; // store raw RGB samples + pic->use_argb = 1; // store raw RGB samples ok = WebPPictureImportRGB(pic, rgb, stride); - if (!ok) { - TS_DEBUG(TAG, "Unable to import inot webp"); + if (!ok) { + TS_DEBUG(TAG, "Unable to import inot webp"); } free(rgb); @@ -276,7 +277,8 @@ JpegDec::ReadImage(WebPPicture* const pic, Metadata* const metadata) { } void -JpegDec::Finalize() { - if(init_) - jpeg_destroy_decompress((j_decompress_ptr)&dinfo_); +JpegDec::Finalize() +{ + if (init_) + jpeg_destroy_decompress((j_decompress_ptr)&dinfo_); } diff --git a/lib/atscppapi/examples/webp_transform/jpegdec.h b/lib/atscppapi/examples/webp_transform/jpegdec.h index 8e4280edfce..3b816f0cab7 100644 --- a/lib/atscppapi/examples/webp_transform/jpegdec.h +++ b/lib/atscppapi/examples/webp_transform/jpegdec.h @@ -31,46 +31,45 @@ struct WebPPicture; typedef struct { - const uint8_t* data; + const uint8_t *data; size_t data_length; - int seq; // this segment's sequence number [1, 255] for use in reassembly. + int seq; // this segment's sequence number [1, 255] for use in reassembly. } ICCPSegment; -class JpegDec { - +class JpegDec +{ public: - JpegDec() : init_(false) { } - ~JpegDec() { } - bool Init(std::stringstream* img); - int ReadImage(struct WebPPicture* const pic, struct Metadata* const metadata); - void Finalize(); + JpegDec() : init_(false) {} + ~JpegDec() {} + bool Init(std::stringstream *img); + int ReadImage(struct WebPPicture *const pic, struct Metadata *const metadata); + void Finalize(); private: - struct ErrorMgr { - struct jpeg_error_mgr pub; - jmp_buf setjmp_buffer; - }; + struct ErrorMgr { + struct jpeg_error_mgr pub; + jmp_buf setjmp_buffer; + }; struct JpegMetadataMap { int marker; - const char* signature; + const char *signature; size_t signature_length; size_t storage_offset; }; - static int CompareICCPSegments(const void* a, const void* b); - int StoreICCP(MetadataPayload* const iccp); - int ExtractMetadataFromJPEG(Metadata* const metadata); - void SaveMetadataMarkers(); + static int CompareICCPSegments(const void *a, const void *b); + int StoreICCP(MetadataPayload *const iccp); + int ExtractMetadataFromJPEG(Metadata *const metadata); + void SaveMetadataMarkers(); - static void Error(j_common_ptr dinfo); + static void Error(j_common_ptr dinfo); - bool init_; - std::stringstream* input_img_; + bool init_; + std::stringstream *input_img_; volatile struct jpeg_decompress_struct dinfo_; - struct ErrorMgr jerr_; + struct ErrorMgr jerr_; static JpegMetadataMap jpeg_metadata_map_[]; - }; -#endif // JPEGDEC_H_ +#endif // JPEGDEC_H_ diff --git a/lib/atscppapi/examples/webp_transform/metadata.cc b/lib/atscppapi/examples/webp_transform/metadata.cc index 3f46fb8af97..8bcd7bc86a8 100644 --- a/lib/atscppapi/examples/webp_transform/metadata.cc +++ b/lib/atscppapi/examples/webp_transform/metadata.cc @@ -22,32 +22,43 @@ #include "webp/types.h" #include "metadata.h" -void MetadataInit(Metadata* const metadata) { - if (metadata == NULL) return; +void +MetadataInit(Metadata *const metadata) +{ + if (metadata == NULL) + return; memset(metadata, 0, sizeof(*metadata)); } -void MetadataPayloadDelete(MetadataPayload* const payload) { - if (payload == NULL) return; +void +MetadataPayloadDelete(MetadataPayload *const payload) +{ + if (payload == NULL) + return; free(payload->bytes); payload->bytes = NULL; payload->size = 0; } -void MetadataFree(Metadata* const metadata) { - if (metadata == NULL) return; +void +MetadataFree(Metadata *const metadata) +{ + if (metadata == NULL) + return; MetadataPayloadDelete(&metadata->exif); MetadataPayloadDelete(&metadata->iccp); MetadataPayloadDelete(&metadata->xmp); } -int MetadataCopy(const char* metadata, size_t metadata_len, - MetadataPayload* const payload) { - if (metadata == NULL || metadata_len == 0 || payload == NULL) return 0; - payload->bytes = (uint8_t*)malloc(metadata_len); - if (payload->bytes == NULL) return 0; +int +MetadataCopy(const char *metadata, size_t metadata_len, MetadataPayload *const payload) +{ + if (metadata == NULL || metadata_len == 0 || payload == NULL) + return 0; + payload->bytes = (uint8_t *)malloc(metadata_len); + if (payload->bytes == NULL) + return 0; payload->size = metadata_len; memcpy(payload->bytes, metadata, metadata_len); return 1; } - diff --git a/lib/atscppapi/examples/webp_transform/metadata.h b/lib/atscppapi/examples/webp_transform/metadata.h index dc8a550bf03..104760cb1ae 100644 --- a/lib/atscppapi/examples/webp_transform/metadata.h +++ b/lib/atscppapi/examples/webp_transform/metadata.h @@ -26,7 +26,7 @@ extern "C" { #endif typedef struct MetadataPayload { - uint8_t* bytes; + uint8_t *bytes; size_t size; } MetadataPayload; @@ -38,16 +38,15 @@ typedef struct Metadata { #define METADATA_OFFSET(x) offsetof(Metadata, x) -void MetadataInit(Metadata* const metadata); -void MetadataPayloadDelete(MetadataPayload* const payload); -void MetadataFree(Metadata* const metadata); +void MetadataInit(Metadata *const metadata); +void MetadataPayloadDelete(MetadataPayload *const payload); +void MetadataFree(Metadata *const metadata); // Stores 'metadata' to 'payload->bytes', returns false on allocation error. -int MetadataCopy(const char* metadata, size_t metadata_len, - MetadataPayload* const payload); +int MetadataCopy(const char *metadata, size_t metadata_len, MetadataPayload *const payload); #ifdef __cplusplus -} // extern "C" +} // extern "C" #endif -#endif // METADATA_H_ +#endif // METADATA_H_ diff --git a/lib/atscppapi/examples/webp_transform/pngdec.cc b/lib/atscppapi/examples/webp_transform/pngdec.cc index 50391b71229..95c59698542 100644 --- a/lib/atscppapi/examples/webp_transform/pngdec.cc +++ b/lib/atscppapi/examples/webp_transform/pngdec.cc @@ -20,7 +20,7 @@ #include #include #include -#include // note: this must be included *after* png.h +#include // note: this must be included *after* png.h #include #include #include @@ -31,50 +31,55 @@ #include "Common.h" void -PngDec::ErrorFunction(png_structp png, png_const_charp error) { - if (error != NULL) TS_DEBUG("img_transform_png", "libpng error: %s\n", error); +PngDec::ErrorFunction(png_structp png, png_const_charp error) +{ + if (error != NULL) + TS_DEBUG("img_transform_png", "libpng error: %s\n", error); longjmp(png_jmpbuf(png), 1); } void -PngDec::ReadFunction(png_structp pngPtr, png_bytep data, png_size_t length) { - PngDec* png_dec = reinterpret_cast(png_get_io_ptr(pngPtr)); +PngDec::ReadFunction(png_structp pngPtr, png_bytep data, png_size_t length) +{ + PngDec *png_dec = reinterpret_cast(png_get_io_ptr(pngPtr)); png_dec->ReadData(data, length); } PngDec::PNGMetadataMap PngDec::png_metadata_map_[] = { - // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PNG.html#TextualData - // See also: ExifTool on CPAN. - { "Raw profile type exif", PngDec::ProcessRawProfile, METADATA_OFFSET(exif) }, - { "Raw profile type xmp", PngDec::ProcessRawProfile, METADATA_OFFSET(xmp) }, - // Exiftool puts exif data in APP1 chunk, too. - { "Raw profile type APP1", PngDec::ProcessRawProfile, METADATA_OFFSET(exif) }, - // XMP Specification Part 3, Section 3 #PNG - { "XML:com.adobe.xmp", MetadataCopy, METADATA_OFFSET(xmp) }, - { NULL, NULL, 0 }, - }; + // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PNG.html#TextualData + // See also: ExifTool on CPAN. + {"Raw profile type exif", PngDec::ProcessRawProfile, METADATA_OFFSET(exif)}, + {"Raw profile type xmp", PngDec::ProcessRawProfile, METADATA_OFFSET(xmp)}, + // Exiftool puts exif data in APP1 chunk, too. + {"Raw profile type APP1", PngDec::ProcessRawProfile, METADATA_OFFSET(exif)}, + // XMP Specification Part 3, Section 3 #PNG + {"XML:com.adobe.xmp", MetadataCopy, METADATA_OFFSET(xmp)}, + {NULL, NULL, 0}, +}; int -PngDec::ProcessRawProfile(const char* profile, size_t profile_len, - MetadataPayload* const payload) { - const char* src = profile; - char* end; +PngDec::ProcessRawProfile(const char *profile, size_t profile_len, MetadataPayload *const payload) +{ + const char *src = profile; + char *end; int expected_length; - if (profile == NULL || profile_len == 0) return 0; + if (profile == NULL || profile_len == 0) + return 0; // ImageMagick formats 'raw profiles' as // '\n\n(%8lu)\n\n'. if (*src != '\n') { - TS_DEBUG(TAG, "Malformed raw profile, expected '\\n' got '\\x%.2X'\n", *src); + TS_DEBUG(TAG, "Malformed raw profile, expected '\\n' got '\\x%.2X'\n", *src); return 0; } ++src; // skip the profile name and extract the length. - while (*src != '\0' && *src++ != '\n') {} + while (*src != '\0' && *src++ != '\n') { + } expected_length = (int)strtol(src, &end, 10); if (*end != '\n') { - TS_DEBUG(TAG, "Malformed raw profile, expected '\\n' got '\\x%.2X'\n", *end); + TS_DEBUG(TAG, "Malformed raw profile, expected '\\n' got '\\x%.2X'\n", *end); return 0; } ++end; @@ -82,8 +87,8 @@ PngDec::ProcessRawProfile(const char* profile, size_t profile_len, // 'end' now points to the profile payload. payload->bytes = HexStringToBytes(end, expected_length); if (payload->bytes == NULL) { - TS_DEBUG(TAG, "HexStringToBytes failed"); - return 0; + TS_DEBUG(TAG, "HexStringToBytes failed"); + return 0; } payload->size = expected_length; return 1; @@ -98,25 +103,28 @@ PngDec::ProcessRawProfile(const char* profile, size_t profile_len, // 'expected_length'. NULL is returned if the processed length is less than // 'expected_length' or any character aside from those above is encountered. // The returned buffer must be freed by the caller. -uint8_t* -PngDec::HexStringToBytes(const char* hexstring, - size_t expected_length) { - const char* src = hexstring; +uint8_t * +PngDec::HexStringToBytes(const char *hexstring, size_t expected_length) +{ + const char *src = hexstring; size_t actual_length = 0; - uint8_t* const raw_data = (uint8_t*)malloc(expected_length); - uint8_t* dst; + uint8_t *const raw_data = (uint8_t *)malloc(expected_length); + uint8_t *dst; - if (raw_data == NULL) return NULL; + if (raw_data == NULL) + return NULL; for (dst = raw_data; actual_length < expected_length && *src != '\0'; ++src) { - char* end; + char *end; char val[3]; - if (*src == '\n') continue; + if (*src == '\n') + continue; val[0] = *src++; val[1] = *src; val[2] = '\0'; *dst++ = (uint8_t)strtol(val, &end, 16); - if (end != val + 2) break; + if (end != val + 2) + break; ++actual_length; } if (actual_length != expected_length) { @@ -127,16 +135,15 @@ PngDec::HexStringToBytes(const char* hexstring, } - - // Looks for metadata at both the beginning and end of the PNG file, giving // preference to the head. // Returns true on success. The caller must use MetadataFree() on 'metadata' in // all cases. int -PngDec::ExtractMetadataFromPNG(Metadata* const metadata) { +PngDec::ExtractMetadataFromPNG(Metadata *const metadata) +{ int p; - for (p = 0; p < 2; ++p) { + for (p = 0; p < 2; ++p) { png_infop const info = (p == 0) ? info_ : end_info_; png_textp text = NULL; const int num = png_get_text(png_, info, &text, NULL); @@ -146,28 +153,25 @@ PngDec::ExtractMetadataFromPNG(Metadata* const metadata) { int j; for (j = 0; png_metadata_map_[j].name != NULL; ++j) { if (!strcmp(text->key, png_metadata_map_[j].name)) { - MetadataPayload* const payload = - (MetadataPayload*)((uint8_t*)metadata + - png_metadata_map_[j].storage_offset); + MetadataPayload *const payload = (MetadataPayload *)((uint8_t *)metadata + png_metadata_map_[j].storage_offset); png_size_t text_length; switch (text->compression) { #ifdef PNG_iTXt_SUPPORTED - case PNG_ITXT_COMPRESSION_NONE: - case PNG_ITXT_COMPRESSION_zTXt: - text_length = text->itxt_length; - break; + case PNG_ITXT_COMPRESSION_NONE: + case PNG_ITXT_COMPRESSION_zTXt: + text_length = text->itxt_length; + break; #endif - case PNG_TEXT_COMPRESSION_NONE: - case PNG_TEXT_COMPRESSION_zTXt: - default: - text_length = text->text_length; - break; + case PNG_TEXT_COMPRESSION_NONE: + case PNG_TEXT_COMPRESSION_zTXt: + default: + text_length = text->text_length; + break; } if (payload->bytes != NULL) { TS_DEBUG(TAG, "Ignoring additional '%s'\n", text->key); - } else if (!png_metadata_map_[j].process(text->text, text_length, - payload)) { - TS_DEBUG(TAG, "Failed to process: '%s'\n", text->key); + } else if (!png_metadata_map_[j].process(text->text, text_length, payload)) { + TS_DEBUG(TAG, "Failed to process: '%s'\n", text->key); return 0; } break; @@ -178,17 +182,16 @@ PngDec::ExtractMetadataFromPNG(Metadata* const metadata) { { png_charp name; int comp_type; -#if ((PNG_LIBPNG_VER_MAJOR << 8) | PNG_LIBPNG_VER_MINOR << 0) < \ - ((1 << 8) | (5 << 0)) +#if ((PNG_LIBPNG_VER_MAJOR << 8) | PNG_LIBPNG_VER_MINOR << 0) < ((1 << 8) | (5 << 0)) png_charp profile; -#else // >= libpng 1.5.0 +#else // >= libpng 1.5.0 png_bytep profile; #endif png_uint_32 len; - if (png_get_iCCP(png_, info, - &name, &comp_type, &profile, &len) == PNG_INFO_iCCP) { - if (!MetadataCopy((const char*)profile, len, &metadata->iccp)) return 0; + if (png_get_iCCP(png_, info, &name, &comp_type, &profile, &len) == PNG_INFO_iCCP) { + if (!MetadataCopy((const char *)profile, len, &metadata->iccp)) + return 0; } } } @@ -197,11 +200,12 @@ PngDec::ExtractMetadataFromPNG(Metadata* const metadata) { } bool -PngDec::Init(std::stringstream* img) { - input_img_ = img; +PngDec::Init(std::stringstream *img) +{ + input_img_ = img; png_ = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); if (png_ == NULL) { - TS_DEBUG(TAG, "Error! Unable to create read structure"); + TS_DEBUG(TAG, "Error! Unable to create read structure"); return false; } @@ -222,26 +226,26 @@ PngDec::Init(std::stringstream* img) { return false; } - //png_init_io(png, in_file); + // png_init_io(png, in_file); png_set_read_fn(png_, (void *)this, PngDec::ReadFunction); png_read_info(png_, info_); - init_= true; + init_ = true; return true; } void -PngDec::Finalize() { - - if (init_ && png_ != NULL) { - png_destroy_read_struct((png_structpp)&png_,(png_infopp)&info_, (png_infopp)&end_info_); - png_ = NULL; - info_ = end_info_ = NULL; - } +PngDec::Finalize() +{ + if (init_ && png_ != NULL) { + png_destroy_read_struct((png_structpp)&png_, (png_infopp)&info_, (png_infopp)&end_info_); + png_ = NULL; + info_ = end_info_ = NULL; + } } int -PngDec::ReadImage(WebPPicture* const pic, Metadata* const metadata) { - +PngDec::ReadImage(WebPPicture *const pic, Metadata *const metadata) +{ int color_type, bit_depth, interlaced; int has_alpha; int num_passes; @@ -249,14 +253,12 @@ PngDec::ReadImage(WebPPicture* const pic, Metadata* const metadata) { int ok = 0; png_uint_32 width, height, y; int stride; - uint8_t* volatile rgb = NULL; + uint8_t *volatile rgb = NULL; - if (!png_get_IHDR(png_, info_, - &width, &height, &bit_depth, &color_type, &interlaced, - NULL, NULL)) { - TS_DEBUG(TAG, "failed to get IHDR"); - return false; + if (!png_get_IHDR(png_, info_, &width, &height, &bit_depth, &color_type, &interlaced, NULL, NULL)) { + TS_DEBUG(TAG, "failed to get IHDR"); + return false; } png_set_strip_16(png_); @@ -264,8 +266,7 @@ PngDec::ReadImage(WebPPicture* const pic, Metadata* const metadata) { if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_); } - if (color_type == PNG_COLOR_TYPE_GRAY || - color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { + if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { if (bit_depth < 8) { png_set_expand_gray_1_2_4_to_8(png_); } @@ -281,8 +282,9 @@ PngDec::ReadImage(WebPPicture* const pic, Metadata* const metadata) { num_passes = png_set_interlace_handling(png_); png_read_update_info(png_, info_); stride = (has_alpha ? 4 : 3) * width * sizeof(*rgb); - rgb = (uint8_t*)malloc(stride * height); - if (rgb == NULL) return false; + rgb = (uint8_t *)malloc(stride * height); + if (rgb == NULL) + return false; for (p = 0; p < num_passes; ++p) { for (y = 0; y < height; ++y) { png_bytep row = (png_bytep)(rgb + y * stride); @@ -291,8 +293,7 @@ PngDec::ReadImage(WebPPicture* const pic, Metadata* const metadata) { } png_read_end(png_, end_info_); - if (metadata != NULL && - !ExtractMetadataFromPNG(metadata)) { + if (metadata != NULL && !ExtractMetadataFromPNG(metadata)) { TS_DEBUG(TAG, "Error!! extracting PNG metadata!"); free(rgb); return false; @@ -301,8 +302,7 @@ PngDec::ReadImage(WebPPicture* const pic, Metadata* const metadata) { pic->width = width; pic->height = height; pic->use_argb = 1; - ok = has_alpha ? WebPPictureImportRGBA(pic, rgb, stride) - : WebPPictureImportRGB(pic, rgb, stride); + ok = has_alpha ? WebPPictureImportRGBA(pic, rgb, stride) : WebPPictureImportRGB(pic, rgb, stride); free(rgb); return ok; @@ -310,7 +310,8 @@ PngDec::ReadImage(WebPPicture* const pic, Metadata* const metadata) { bool -PngDec::ReadData(png_bytep data, png_size_t length) { - input_img_->read((char *)data, length); - return true; +PngDec::ReadData(png_bytep data, png_size_t length) +{ + input_img_->read((char *)data, length); + return true; } diff --git a/lib/atscppapi/examples/webp_transform/pngdec.h b/lib/atscppapi/examples/webp_transform/pngdec.h index 25f061a7754..f9f79a73ecd 100644 --- a/lib/atscppapi/examples/webp_transform/pngdec.h +++ b/lib/atscppapi/examples/webp_transform/pngdec.h @@ -29,39 +29,37 @@ struct WebPPicture; -class PngDec { +class PngDec +{ public: - PngDec() : init_(false), input_img_(NULL), info_(NULL), end_info_(NULL) - {} - ~PngDec() { } - bool Init(std::stringstream* img); - int ReadImage(struct WebPPicture* const pic, struct Metadata* const metadata); - void Finalize(); + PngDec() : init_(false), input_img_(NULL), info_(NULL), end_info_(NULL) {} + ~PngDec() {} + bool Init(std::stringstream *img); + int ReadImage(struct WebPPicture *const pic, struct Metadata *const metadata); + void Finalize(); private: + struct PNGMetadataMap { + const char *name; + int (*process)(const char *profile, size_t profile_len, MetadataPayload *const payload); + size_t storage_offset; + }; - struct PNGMetadataMap { - const char* name; - int (*process)(const char* profile, size_t profile_len, - MetadataPayload* const payload); - size_t storage_offset; - }; + void Read(png_structp pngPtr, png_bytep data, png_size_t length); + int ExtractMetadataFromPNG(Metadata *const metadata); - void Read(png_structp pngPtr, png_bytep data, png_size_t length); - int ExtractMetadataFromPNG(Metadata* const metadata); + static uint8_t *HexStringToBytes(const char *hexstring, size_t expected_length); + static int ProcessRawProfile(const char *profile, size_t profile_len, MetadataPayload *const payload); + static void ReadFunction(png_structp pngPtr, png_bytep data, png_size_t length); + static void ErrorFunction(png_structp png, png_const_charp error); + bool ReadData(png_bytep data, png_size_t len); - static uint8_t* HexStringToBytes(const char* hexstring, size_t expected_length); - static int ProcessRawProfile(const char* profile, size_t profile_len, MetadataPayload* const payload); - static void ReadFunction(png_structp pngPtr, png_bytep data, png_size_t length); - static void ErrorFunction(png_structp png, png_const_charp error); - bool ReadData(png_bytep data, png_size_t len); - - bool init_; - std::stringstream* input_img_; + bool init_; + std::stringstream *input_img_; volatile png_structp png_; - volatile png_infop info_; - volatile png_infop end_info_; - static PNGMetadataMap png_metadata_map_[]; + volatile png_infop info_; + volatile png_infop end_info_; + static PNGMetadataMap png_metadata_map_[]; }; -#endif // PNGDEC_H_ +#endif // PNGDEC_H_ From 5d61b692755fed58214d5046297f4e2ba58ca15d Mon Sep 17 00:00:00 2001 From: myraid Date: Wed, 23 Dec 2015 10:51:15 -0800 Subject: [PATCH 05/19] [TS-4095] Register the plugin --- lib/atscppapi/examples/webp_transform/ImageTransform.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/atscppapi/examples/webp_transform/ImageTransform.cc b/lib/atscppapi/examples/webp_transform/ImageTransform.cc index 6ec5e4ffbf2..c705216b3c3 100644 --- a/lib/atscppapi/examples/webp_transform/ImageTransform.cc +++ b/lib/atscppapi/examples/webp_transform/ImageTransform.cc @@ -96,6 +96,6 @@ GlobalHookPlugin::handleReadResponseHeaders(Transaction &transaction) void TSPluginInit(int argc ATSCPPAPI_UNUSED, const char *argv[] ATSCPPAPI_UNUSED) { - TS_DEBUG(TAG, "TSPluginInit"); + RegisterGlobalPlugin("CPP_Webp_Transform", "apache", "dev@trafficserver.apache.org"); new GlobalHookPlugin(); } From 1b4041774dd91f7785346e3e1c50268d0e4e0cc6 Mon Sep 17 00:00:00 2001 From: myraid Date: Wed, 23 Dec 2015 15:58:26 -0800 Subject: [PATCH 06/19] [TS-4095] naming convention changes --- .../examples/webp_transform/ImageTransform.cc | 12 +- .../examples/webp_transform/ImageTransform.h | 4 +- .../examples/webp_transform/compress.cc | 100 ++++++++--------- .../examples/webp_transform/compress.h | 48 ++++---- .../examples/webp_transform/jpegdec.cc | 96 ++++++++-------- .../examples/webp_transform/jpegdec.h | 40 +++---- .../examples/webp_transform/metadata.h | 2 +- .../examples/webp_transform/pngdec.cc | 106 +++++++++--------- .../examples/webp_transform/pngdec.h | 34 +++--- 9 files changed, 220 insertions(+), 222 deletions(-) diff --git a/lib/atscppapi/examples/webp_transform/ImageTransform.cc b/lib/atscppapi/examples/webp_transform/ImageTransform.cc index c705216b3c3..208b5cca0ac 100644 --- a/lib/atscppapi/examples/webp_transform/ImageTransform.cc +++ b/lib/atscppapi/examples/webp_transform/ImageTransform.cc @@ -39,14 +39,14 @@ std::string ImageTransform::IMAGE_TYPE("image/webp"); ImageTransform::ImageTransform(Transaction &transaction) - : TransformationPlugin(transaction, TransformationPlugin::RESPONSE_TRANSFORMATION), webp_transform_() + : TransformationPlugin(transaction, TransformationPlugin::RESPONSE_TRANSFORMATION), _webp_transform() { TransformationPlugin::registerHook(HOOK_READ_RESPONSE_HEADERS); } ImageTransform::~ImageTransform() { - webp_transform_.Finalize(); + _webp_transform.finalize(); } void @@ -62,15 +62,15 @@ ImageTransform::handleReadResponseHeaders(Transaction &transaction) void ImageTransform::consume(const string &data) { - img_.write(data.data(), data.size()); + _img.write(data.data(), data.size()); } void ImageTransform::handleInputComplete() { - webp_transform_.Init(); - webp_transform_.Transform(img_); - produce(webp_transform_.getTransformedImage().str()); + _webp_transform.init(); + _webp_transform.transform(_img); + produce(_webp_transform.getTransformedImage().str()); setOutputComplete(); } diff --git a/lib/atscppapi/examples/webp_transform/ImageTransform.h b/lib/atscppapi/examples/webp_transform/ImageTransform.h index 79c8d436f90..a3e69ca40de 100644 --- a/lib/atscppapi/examples/webp_transform/ImageTransform.h +++ b/lib/atscppapi/examples/webp_transform/ImageTransform.h @@ -50,8 +50,8 @@ class ImageTransform : public atscppapi::TransformationPlugin static std::string IMAGE_TYPE; private: - std::stringstream img_; - WebpTransform webp_transform_; + std::stringstream _img; + WebpTransform _webp_transform; }; class GlobalHookPlugin : public atscppapi::GlobalPlugin diff --git a/lib/atscppapi/examples/webp_transform/compress.cc b/lib/atscppapi/examples/webp_transform/compress.cc index 26dee8e1427..848fbdc338e 100644 --- a/lib/atscppapi/examples/webp_transform/compress.cc +++ b/lib/atscppapi/examples/webp_transform/compress.cc @@ -40,11 +40,11 @@ static int StreamWriter(const uint8_t *data, size_t data_size, const WebPPicture *const pic) { WebpTransform *webp_transform = static_cast(pic->custom_ptr); - webp_transform->WriteImage(reinterpret_cast(data), data_size); + webp_transform->writeImage(reinterpret_cast(data), data_size); return data_size ? data_size : 1; } -const string WebpTransform::errors_[] = { +const string WebpTransform::_errors[] = { "OK", "OUT_OF_MEMORY: Out of memory allocating objects", "BITSTREAM_OUT_OF_MEMORY: Out of memory re-allocating byte buffer", "NULL_PARAMETER: NULL parameter passed to function", "INVALID_CONFIGURATION: configuration is invalid", "BAD_DIMENSION: Bad picture dimension. Maximum width and height " @@ -58,19 +58,19 @@ const string WebpTransform::errors_[] = { "FILE_TOO_BIG: File would be too big to fit in 4G", "USER_ABORT: encoding abort requested by user"}; void -WebpTransform::WebPMemoryWriterClear() +WebpTransform::_webpMemoryWriterClear() { - if (writer_.mem != NULL) { - free(writer_.mem); - writer_.mem = NULL; - writer_.size = 0; - writer_.max_size = 0; + if (_writer.mem != NULL) { + free(_writer.mem); + _writer.mem = NULL; + _writer.size = 0; + _writer.max_size = 0; } } WebpTransform::InputFileFormat -WebpTransform::GetImageType(std::stringstream &input_img) +WebpTransform::_getImageType(std::stringstream &input_img) { InputFileFormat format = UNSUPPORTED; uint32_t magic1, magic2; @@ -91,25 +91,25 @@ WebpTransform::GetImageType(std::stringstream &input_img) } int -WebpTransform::ReadImage(std::stringstream &input_img) +WebpTransform::_readImage(std::stringstream &input_img) { int ok = 0; - if (picture_.width == 0 || picture_.height == 0) { + if (_picture.width == 0 || _picture.height == 0) { // If no size specified, try to decode it as PNG/JPEG (as appropriate). - const InputFileFormat format = GetImageType(input_img); + const InputFileFormat format = _getImageType(input_img); if (format == PNG_) { - if (!png_dec_.Init(&input_img)) { - png_dec_.Finalize(); + if (!_png_dec.init(&input_img)) { + _png_dec.finalize(); return 0; } - ok = png_dec_.ReadImage(&picture_, &metadata_); + ok = _png_dec.readImage(&_picture, &_metadata); } else if (format == JPEG_) { - if (!jpeg_dec_.Init(&input_img)) { - jpeg_dec_.Finalize(); + if (!_jpeg_dec.init(&input_img)) { + _jpeg_dec.finalize(); return 0; } - ok = jpeg_dec_.ReadImage(&picture_, &metadata_); + ok = _jpeg_dec.readImage(&_picture, &_metadata); } else if (format == WEBP_) { TS_DEBUG(TAG, "Already webp file. Nothing to be done."); } @@ -122,77 +122,77 @@ WebpTransform::ReadImage(std::stringstream &input_img) void -WebpTransform::AllocExtraInfo() +WebpTransform::_allocExtraInfo() { - const int mb_w = (picture_.width + 15) / 16; - const int mb_h = (picture_.height + 15) / 16; - picture_.extra_info = (uint8_t *)malloc(mb_w * mb_h * sizeof(picture_.extra_info)); + const int mb_w = (_picture.width + 15) / 16; + const int mb_h = (_picture.height + 15) / 16; + _picture.extra_info = (uint8_t *)malloc(mb_w * mb_h * sizeof(_picture.extra_info)); } bool -WebpTransform::Init() +WebpTransform::init() { - MetadataInit(&metadata_); - WebPMemoryWriterInit(&writer_); - if (!WebPPictureInit(&picture_) || !WebPConfigInit(&config_)) { + MetadataInit(&_metadata); + WebPMemoryWriterInit(&_writer); + if (!WebPPictureInit(&_picture) || !WebPConfigInit(&_config)) { TS_DEBUG(TAG, "DEBUG! Version mismatch"); return false; } WebPPreset preset = WEBP_PRESET_PICTURE; - if (!WebPConfigPreset(&config_, preset, config_.quality)) { + if (!WebPConfigPreset(&_config, preset, _config.quality)) { TS_DEBUG(TAG, "DEBUG! Could initialize configuration with preset."); return false; } - if (!WebPValidateConfig(&config_)) { + if (!WebPValidateConfig(&_config)) { TS_DEBUG(TAG, "DEBUG! Invalid configuration."); return false; } - init_ = true; + _init = true; return true; } bool -WebpTransform::Transform(std::stringstream &input_img) +WebpTransform::transform(std::stringstream &input_img) { - if (!ReadImage(input_img)) { + if (!_readImage(input_img)) { TS_DEBUG(TAG, "Cannot read input picture file ."); return false; } - picture_.progress_hook = NULL; + _picture.progress_hook = NULL; - picture_.writer = StreamWriter; - picture_.custom_ptr = (void *)this; + _picture.writer = StreamWriter; + _picture.custom_ptr = (void *)this; - if (picture_.extra_info_type > 0) { - AllocExtraInfo(); + if (_picture.extra_info_type > 0) { + _allocExtraInfo(); } - if (!WebPEncode(&config_, &picture_)) { - TS_DEBUG(TAG, "DEBUG! Cannot encode picture as WebP. Error code: %d (%s)", picture_.error_code, - WebpTransform::errors_[picture_.error_code].c_str()); + if (!WebPEncode(&_config, &_picture)) { + TS_DEBUG(TAG, "DEBUG! Cannot encode picture as WebP. Error code: %d (%s)", _picture.error_code, + WebpTransform::_errors[_picture.error_code].c_str()); return false; } return true; } void -WebpTransform::Finalize() +WebpTransform::finalize() { - if (init_) { - WebPMemoryWriterClear(); - free(picture_.extra_info); - MetadataFree(&metadata_); - WebPPictureFree(&picture_); - - png_dec_.Finalize(); - jpeg_dec_.Finalize(); + if (_init) { + _webpMemoryWriterClear(); + free(_picture.extra_info); + MetadataFree(&_metadata); + WebPPictureFree(&_picture); + + _png_dec.finalize(); + _jpeg_dec.finalize(); } } void -WebpTransform::WriteImage(const char *data, size_t data_size) +WebpTransform::writeImage(const char *data, size_t data_size) { - stream_.write(data, data_size); + _stream.write(data, data_size); } diff --git a/lib/atscppapi/examples/webp_transform/compress.h b/lib/atscppapi/examples/webp_transform/compress.h index 8b6b4afd608..3029c70c051 100644 --- a/lib/atscppapi/examples/webp_transform/compress.h +++ b/lib/atscppapi/examples/webp_transform/compress.h @@ -38,19 +38,18 @@ class WebpTransform { public: - WebpTransform() : init_(false), png_dec_(), jpeg_dec_() {} + WebpTransform() : _init(false), _png_dec(), _jpeg_dec() {} ~WebpTransform() {} - bool Init(); - bool Transform(std::stringstream &stream); - void Finalize(); - std::stringstream & - getTransformedImage() - { - return stream_; + bool init(); + bool transform(std::stringstream &stream); + void finalize(); + std::stringstream &getTransformedImage() { + return _stream; } - void WriteImage(const char *data, size_t data_size); + + void writeImage(const char *data, size_t data_size); private: typedef enum { PNG_ = 0, JPEG_, WEBP_, UNSUPPORTED } InputFileFormat; @@ -62,22 +61,21 @@ class WebpTransform METADATA_ALL = METADATA_EXIF | METADATA_ICC | METADATA_XMP }; - InputFileFormat GetImageType(std::stringstream &input_msg); - int ReadImage(std::stringstream &input_img); - void AllocExtraInfo(); - - void WebPMemoryWriterClear(); - - static const std::string errors_[]; - bool init_; - WebPMemoryWriter writer_; - std::stringstream stream_; - WebPPicture picture_; - WebPConfig config_; - Metadata metadata_; - std::string debug_tag_; - PngDec png_dec_; - JpegDec jpeg_dec_; + InputFileFormat _getImageType(std::stringstream &input_msg); + int _readImage(std::stringstream &input_img); + void _allocExtraInfo(); + void _webpMemoryWriterClear(); + + static const std::string _errors[]; + bool _init; + WebPMemoryWriter _writer; + std::stringstream _stream; + WebPPicture _picture; + WebPConfig _config; + Metadata _metadata; + std::string _debug_tag; + PngDec _png_dec; + JpegDec _jpeg_dec; }; #endif //WEBPTRANSFORM_H_ diff --git a/lib/atscppapi/examples/webp_transform/jpegdec.cc b/lib/atscppapi/examples/webp_transform/jpegdec.cc index c0f90538083..bf6206ac567 100644 --- a/lib/atscppapi/examples/webp_transform/jpegdec.cc +++ b/lib/atscppapi/examples/webp_transform/jpegdec.cc @@ -32,7 +32,7 @@ #define JPEG_APP2 (JPEG_APP0 + 2) -JpegDec::JpegMetadataMap JpegDec::jpeg_metadata_map_[] = { +JpegDec::JpegMetadataMap JpegDec::_jpeg_metadata_map[] = { // Exif 2.2 Section 4.7.2 Interoperability Structure of APP1 ... {JPEG_APP1, "Exif\0", 6, METADATA_OFFSET(exif)}, // XMP Specification Part 3 Section 3 Embedding XMP Metadata ... #JPEG @@ -42,15 +42,15 @@ JpegDec::JpegMetadataMap JpegDec::jpeg_metadata_map_[] = { }; void -JpegDec::SaveMetadataMarkers() +JpegDec::_saveMetadataMarkers() { const unsigned int max_marker_length = 0xffff; - jpeg_save_markers((j_decompress_ptr)&dinfo_, JPEG_APP1, max_marker_length); // Exif/XMP - jpeg_save_markers((j_decompress_ptr)&dinfo_, JPEG_APP2, max_marker_length); // ICC profile + jpeg_save_markers((j_decompress_ptr)&_dinfo, JPEG_APP1, max_marker_length); // Exif/XMP + jpeg_save_markers((j_decompress_ptr)&_dinfo, JPEG_APP2, max_marker_length); // ICC profile } int -JpegDec::CompareICCPSegments(const void *a, const void *b) +JpegDec::_compareICCPSegments(const void *a, const void *b) { const ICCPSegment *s1 = (const ICCPSegment *)a; const ICCPSegment *s2 = (const ICCPSegment *)b; @@ -59,7 +59,7 @@ JpegDec::CompareICCPSegments(const void *a, const void *b) int -JpegDec::StoreICCP(MetadataPayload *const iccp) +JpegDec::_storeICCP(MetadataPayload *const iccp) { // ICC.1:2010-12 (4.3.0.0) Annex B.4 Embedding ICC Profiles in JPEG files static const char kICCPSignature[] = "ICC_PROFILE"; @@ -73,7 +73,7 @@ JpegDec::StoreICCP(MetadataPayload *const iccp) jpeg_saved_marker_ptr marker; memset(iccp_segments, 0, sizeof(iccp_segments)); - for (marker = dinfo_.marker_list; marker != NULL; marker = marker->next) { + for (marker = _dinfo.marker_list; marker != NULL; marker = marker->next) { if (marker->marker == JPEG_APP2 && marker->data_length > kICCPSkipLength && !memcmp(marker->data, kICCPSignature, kICCPSignatureLength)) { // ICC_PROFILE\0; 'seq' starts at 1. @@ -122,7 +122,7 @@ JpegDec::StoreICCP(MetadataPayload *const iccp) // The segments may appear out of order in the file, sort them based on // sequence number before assembling the payload. - qsort(iccp_segments, actual_count, sizeof(*iccp_segments), JpegDec::CompareICCPSegments); + qsort(iccp_segments, actual_count, sizeof(*iccp_segments), JpegDec::_compareICCPSegments); iccp->bytes = (uint8_t *)malloc(total_size); if (iccp->bytes == NULL) @@ -143,27 +143,27 @@ JpegDec::StoreICCP(MetadataPayload *const iccp) // Returns true on success and false for memory errors and corrupt profiles. // The caller must use MetadataFree() on 'metadata' in all cases. int -JpegDec::ExtractMetadataFromJPEG(Metadata *const metadata) +JpegDec::_extractMetadataFromJPEG(Metadata *const metadata) { jpeg_saved_marker_ptr marker; // Treat ICC profiles separately as they may be segmented and out of order. - if (!StoreICCP(&metadata->iccp)) + if (!_storeICCP(&metadata->iccp)) return 0; - for (marker = dinfo_.marker_list; marker != NULL; marker = marker->next) { + for (marker = _dinfo.marker_list; marker != NULL; marker = marker->next) { int i; - for (i = 0; jpeg_metadata_map_[i].marker != 0; ++i) { - if (marker->marker == jpeg_metadata_map_[i].marker && marker->data_length > jpeg_metadata_map_[i].signature_length && - !memcmp(marker->data, jpeg_metadata_map_[i].signature, jpeg_metadata_map_[i].signature_length)) { - MetadataPayload *const payload = (MetadataPayload *)((uint8_t *)metadata + jpeg_metadata_map_[i].storage_offset); + for (i = 0; _jpeg_metadata_map[i].marker != 0; ++i) { + if (marker->marker == _jpeg_metadata_map[i].marker && marker->data_length > _jpeg_metadata_map[i].signature_length && + !memcmp(marker->data, _jpeg_metadata_map[i].signature, _jpeg_metadata_map[i].signature_length)) { + MetadataPayload *const payload = (MetadataPayload *)((uint8_t *)metadata + _jpeg_metadata_map[i].storage_offset); if (payload->bytes == NULL) { - const char *marker_data = (const char *)marker->data + jpeg_metadata_map_[i].signature_length; - const size_t marker_data_length = marker->data_length - jpeg_metadata_map_[i].signature_length; + const char *marker_data = (const char *)marker->data + _jpeg_metadata_map[i].signature_length; + const size_t marker_data_length = marker->data_length - _jpeg_metadata_map[i].signature_length; if (!MetadataCopy(marker_data, marker_data_length, payload)) return 0; } else { - TS_DEBUG(TAG, "Ignoring additional '%s' marker\n", jpeg_metadata_map_[i].signature); + TS_DEBUG(TAG, "Ignoring additional '%s' marker\n", _jpeg_metadata_map[i].signature); } } } @@ -179,7 +179,7 @@ JpegDec::ExtractMetadataFromJPEG(Metadata *const metadata) void -JpegDec::Error(j_common_ptr dinfo) +JpegDec::_error(j_common_ptr dinfo) { struct JpegDec::ErrorMgr *err = (struct JpegDec::ErrorMgr *)dinfo->err; dinfo->err->output_message(dinfo); @@ -187,54 +187,54 @@ JpegDec::Error(j_common_ptr dinfo) } bool -JpegDec::Init(std::stringstream *img) +JpegDec::init(std::stringstream *img) { - input_img_ = img; + _input_img = img; - memset((j_decompress_ptr)&dinfo_, 0, sizeof(dinfo_)); // for setjmp sanity - dinfo_.err = jpeg_std_error(&jerr_.pub); - jerr_.pub.error_exit = JpegDec::Error; + memset((j_decompress_ptr)&_dinfo, 0, sizeof(_dinfo)); // for setjmp sanity + _dinfo.err = jpeg_std_error(&_jerr.pub); + _jerr.pub.error_exit = JpegDec::_error; - if (setjmp(jerr_.setjmp_buffer)) { + if (setjmp(_jerr.setjmp_buffer)) { TS_DEBUG(TAG, " setjmp failed"); - jpeg_destroy_decompress((j_decompress_ptr)&dinfo_); + jpeg_destroy_decompress((j_decompress_ptr)&_dinfo); return false; } - jpeg_create_decompress((j_decompress_ptr)&dinfo_); - init_ = true; + jpeg_create_decompress((j_decompress_ptr)&_dinfo); + _init = true; return true; } int -JpegDec::ReadImage(WebPPicture *const pic, Metadata *const metadata) +JpegDec::readImage(WebPPicture *const pic, Metadata *const metadata) { int ok = 0; int stride, width, height; uint8_t *volatile rgb = NULL; JSAMPROW buffer[1]; - std::string img_str = input_img_->str(); + std::string img_str = _input_img->str(); // TODO: Can this copy be avoided. - jpeg_mem_src((j_decompress_ptr)&dinfo_, (unsigned char *)img_str.data(), img_str.size()); + jpeg_mem_src((j_decompress_ptr)&_dinfo, (unsigned char *)img_str.data(), img_str.size()); if (metadata != NULL) - SaveMetadataMarkers(); - jpeg_read_header((j_decompress_ptr)&dinfo_, TRUE); + _saveMetadataMarkers(); + jpeg_read_header((j_decompress_ptr)&_dinfo, TRUE); - dinfo_.out_color_space = JCS_RGB; - dinfo_.do_fancy_upsampling = TRUE; + _dinfo.out_color_space = JCS_RGB; + _dinfo.do_fancy_upsampling = TRUE; - jpeg_start_decompress((j_decompress_ptr)&dinfo_); + jpeg_start_decompress((j_decompress_ptr)&_dinfo); - if (dinfo_.output_components != 3) { + if (_dinfo.output_components != 3) { TS_DEBUG(TAG, "not enought output componenets available."); return 0; } - width = dinfo_.output_width; - height = dinfo_.output_height; - stride = dinfo_.output_width * dinfo_.output_components * sizeof(*rgb); + width = _dinfo.output_width; + height = _dinfo.output_height; + stride = _dinfo.output_width * _dinfo.output_components * sizeof(*rgb); rgb = (uint8_t *)malloc(stride * height); if (rgb == NULL) { @@ -243,8 +243,8 @@ JpegDec::ReadImage(WebPPicture *const pic, Metadata *const metadata) } buffer[0] = (JSAMPLE *)rgb; - while (dinfo_.output_scanline < dinfo_.output_height) { - if (jpeg_read_scanlines((j_decompress_ptr)&dinfo_, buffer, 1) != 1) { + while (_dinfo.output_scanline < _dinfo.output_height) { + if (jpeg_read_scanlines((j_decompress_ptr)&_dinfo, buffer, 1) != 1) { free(rgb); return 0; } @@ -252,7 +252,7 @@ JpegDec::ReadImage(WebPPicture *const pic, Metadata *const metadata) } if (metadata != NULL) { - ok = ExtractMetadataFromJPEG(metadata); + ok = _extractMetadataFromJPEG(metadata); if (!ok) { TS_DEBUG(TAG, "Error extracting JPEG metadata!"); free(rgb); @@ -260,8 +260,8 @@ JpegDec::ReadImage(WebPPicture *const pic, Metadata *const metadata) } } - jpeg_finish_decompress((j_decompress_ptr)&dinfo_); - jpeg_destroy_decompress((j_decompress_ptr)&dinfo_); + jpeg_finish_decompress((j_decompress_ptr)&_dinfo); + jpeg_destroy_decompress((j_decompress_ptr)&_dinfo); // WebP conversion. pic->width = width; @@ -277,8 +277,8 @@ JpegDec::ReadImage(WebPPicture *const pic, Metadata *const metadata) } void -JpegDec::Finalize() +JpegDec::finalize() { - if (init_) - jpeg_destroy_decompress((j_decompress_ptr)&dinfo_); + if (_init) + jpeg_destroy_decompress((j_decompress_ptr)&_dinfo); } diff --git a/lib/atscppapi/examples/webp_transform/jpegdec.h b/lib/atscppapi/examples/webp_transform/jpegdec.h index 3b816f0cab7..ee9cef72be8 100644 --- a/lib/atscppapi/examples/webp_transform/jpegdec.h +++ b/lib/atscppapi/examples/webp_transform/jpegdec.h @@ -32,44 +32,44 @@ struct WebPPicture; typedef struct { const uint8_t *data; - size_t data_length; - int seq; // this segment's sequence number [1, 255] for use in reassembly. + size_t data_length; + int seq; // this segment's sequence number [1, 255] for use in reassembly. } ICCPSegment; class JpegDec { public: - JpegDec() : init_(false) {} + JpegDec() : _init(false) {} ~JpegDec() {} - bool Init(std::stringstream *img); - int ReadImage(struct WebPPicture *const pic, struct Metadata *const metadata); - void Finalize(); + bool init(std::stringstream *img); + int readImage(struct WebPPicture *const pic, struct Metadata *const metadata); + void finalize(); private: struct ErrorMgr { struct jpeg_error_mgr pub; - jmp_buf setjmp_buffer; + jmp_buf setjmp_buffer; }; struct JpegMetadataMap { - int marker; + int marker; const char *signature; - size_t signature_length; - size_t storage_offset; + size_t signature_length; + size_t storage_offset; }; - static int CompareICCPSegments(const void *a, const void *b); - int StoreICCP(MetadataPayload *const iccp); - int ExtractMetadataFromJPEG(Metadata *const metadata); - void SaveMetadataMarkers(); + static int _compareICCPSegments(const void *a, const void *b); + int _storeICCP(MetadataPayload *const iccp); + int _extractMetadataFromJPEG(Metadata *const metadata); + void _saveMetadataMarkers(); - static void Error(j_common_ptr dinfo); + static void _error(j_common_ptr dinfo); - bool init_; - std::stringstream *input_img_; - volatile struct jpeg_decompress_struct dinfo_; - struct ErrorMgr jerr_; - static JpegMetadataMap jpeg_metadata_map_[]; + bool _init; + std::stringstream * _input_img; + volatile struct jpeg_decompress_struct _dinfo; + struct ErrorMgr _jerr; + static JpegMetadataMap _jpeg_metadata_map[]; }; #endif // JPEGDEC_H_ diff --git a/lib/atscppapi/examples/webp_transform/metadata.h b/lib/atscppapi/examples/webp_transform/metadata.h index 104760cb1ae..fd0a1311b98 100644 --- a/lib/atscppapi/examples/webp_transform/metadata.h +++ b/lib/atscppapi/examples/webp_transform/metadata.h @@ -27,7 +27,7 @@ extern "C" { typedef struct MetadataPayload { uint8_t *bytes; - size_t size; + size_t size; } MetadataPayload; typedef struct Metadata { diff --git a/lib/atscppapi/examples/webp_transform/pngdec.cc b/lib/atscppapi/examples/webp_transform/pngdec.cc index 95c59698542..beb508715e3 100644 --- a/lib/atscppapi/examples/webp_transform/pngdec.cc +++ b/lib/atscppapi/examples/webp_transform/pngdec.cc @@ -31,7 +31,7 @@ #include "Common.h" void -PngDec::ErrorFunction(png_structp png, png_const_charp error) +PngDec::_errorFunction(png_structp png, png_const_charp error) { if (error != NULL) TS_DEBUG("img_transform_png", "libpng error: %s\n", error); @@ -39,26 +39,26 @@ PngDec::ErrorFunction(png_structp png, png_const_charp error) } void -PngDec::ReadFunction(png_structp pngPtr, png_bytep data, png_size_t length) +PngDec::_readFunction(png_structp pngPtr, png_bytep data, png_size_t length) { PngDec *png_dec = reinterpret_cast(png_get_io_ptr(pngPtr)); - png_dec->ReadData(data, length); + png_dec->_readData(data, length); } -PngDec::PNGMetadataMap PngDec::png_metadata_map_[] = { +PngDec::PNGMetadataMap PngDec::_png_metadata_map[] = { // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PNG.html#TextualData // See also: ExifTool on CPAN. - {"Raw profile type exif", PngDec::ProcessRawProfile, METADATA_OFFSET(exif)}, - {"Raw profile type xmp", PngDec::ProcessRawProfile, METADATA_OFFSET(xmp)}, + {"Raw profile type exif", PngDec::_processRawProfile, METADATA_OFFSET(exif)}, + {"Raw profile type xmp", PngDec::_processRawProfile, METADATA_OFFSET(xmp)}, // Exiftool puts exif data in APP1 chunk, too. - {"Raw profile type APP1", PngDec::ProcessRawProfile, METADATA_OFFSET(exif)}, + {"Raw profile type APP1", PngDec::_processRawProfile, METADATA_OFFSET(exif)}, // XMP Specification Part 3, Section 3 #PNG {"XML:com.adobe.xmp", MetadataCopy, METADATA_OFFSET(xmp)}, {NULL, NULL, 0}, }; int -PngDec::ProcessRawProfile(const char *profile, size_t profile_len, MetadataPayload *const payload) +PngDec::_processRawProfile(const char *profile, size_t profile_len, MetadataPayload *const payload) { const char *src = profile; char *end; @@ -85,9 +85,9 @@ PngDec::ProcessRawProfile(const char *profile, size_t profile_len, MetadataPaylo ++end; // 'end' now points to the profile payload. - payload->bytes = HexStringToBytes(end, expected_length); + payload->bytes = _hexStringToBytes(end, expected_length); if (payload->bytes == NULL) { - TS_DEBUG(TAG, "HexStringToBytes failed"); + TS_DEBUG(TAG, " failed"); return 0; } payload->size = expected_length; @@ -104,7 +104,7 @@ PngDec::ProcessRawProfile(const char *profile, size_t profile_len, MetadataPaylo // 'expected_length' or any character aside from those above is encountered. // The returned buffer must be freed by the caller. uint8_t * -PngDec::HexStringToBytes(const char *hexstring, size_t expected_length) +PngDec::_hexStringToBytes(const char *hexstring, size_t expected_length) { const char *src = hexstring; size_t actual_length = 0; @@ -140,20 +140,20 @@ PngDec::HexStringToBytes(const char *hexstring, size_t expected_length) // Returns true on success. The caller must use MetadataFree() on 'metadata' in // all cases. int -PngDec::ExtractMetadataFromPNG(Metadata *const metadata) +PngDec::_extractMetadataFromPNG(Metadata *const metadata) { int p; for (p = 0; p < 2; ++p) { - png_infop const info = (p == 0) ? info_ : end_info_; + png_infop const info = (p == 0) ? _info : _end_info; png_textp text = NULL; - const int num = png_get_text(png_, info, &text, NULL); + const int num = png_get_text(_png, info, &text, NULL); int i; // Look for EXIF / XMP metadata. for (i = 0; i < num; ++i, ++text) { int j; - for (j = 0; png_metadata_map_[j].name != NULL; ++j) { - if (!strcmp(text->key, png_metadata_map_[j].name)) { - MetadataPayload *const payload = (MetadataPayload *)((uint8_t *)metadata + png_metadata_map_[j].storage_offset); + for (j = 0; _png_metadata_map[j].name != NULL; ++j) { + if (!strcmp(text->key, _png_metadata_map[j].name)) { + MetadataPayload *const payload = (MetadataPayload *)((uint8_t *)metadata + _png_metadata_map[j].storage_offset); png_size_t text_length; switch (text->compression) { #ifdef PNG_iTXt_SUPPORTED @@ -170,7 +170,7 @@ PngDec::ExtractMetadataFromPNG(Metadata *const metadata) } if (payload->bytes != NULL) { TS_DEBUG(TAG, "Ignoring additional '%s'\n", text->key); - } else if (!png_metadata_map_[j].process(text->text, text_length, payload)) { + } else if (!_png_metadata_map[j].process(text->text, text_length, payload)) { TS_DEBUG(TAG, "Failed to process: '%s'\n", text->key); return 0; } @@ -189,7 +189,7 @@ PngDec::ExtractMetadataFromPNG(Metadata *const metadata) #endif png_uint_32 len; - if (png_get_iCCP(png_, info, &name, &comp_type, &profile, &len) == PNG_INFO_iCCP) { + if (png_get_iCCP(_png, info, &name, &comp_type, &profile, &len) == PNG_INFO_iCCP) { if (!MetadataCopy((const char *)profile, len, &metadata->iccp)) return 0; } @@ -200,51 +200,51 @@ PngDec::ExtractMetadataFromPNG(Metadata *const metadata) } bool -PngDec::Init(std::stringstream *img) +PngDec::init(std::stringstream *img) { - input_img_ = img; - png_ = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); - if (png_ == NULL) { + _input_img = img; + _png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); + if (_png == NULL) { TS_DEBUG(TAG, "Error! Unable to create read structure"); return false; } - png_set_error_fn(png_, 0, PngDec::ErrorFunction, NULL); - if (setjmp(png_jmpbuf(png_))) { + png_set_error_fn(_png, 0, PngDec::_errorFunction, NULL); + if (setjmp(png_jmpbuf(_png))) { TS_DEBUG(TAG, "Error! setjmp failed"); return false; } - info_ = png_create_info_struct(png_); - if (info_ == NULL) { + _info = png_create_info_struct(_png); + if (_info == NULL) { TS_DEBUG(TAG, "Error! could not create info struct for info_"); return false; } - end_info_ = png_create_info_struct(png_); - if (end_info_ == NULL) { + _end_info = png_create_info_struct(_png); + if (_end_info == NULL) { TS_DEBUG(TAG, "Error! could not create info struct for info_"); return false; } // png_init_io(png, in_file); - png_set_read_fn(png_, (void *)this, PngDec::ReadFunction); - png_read_info(png_, info_); - init_ = true; + png_set_read_fn(_png, (void *)this, PngDec::_readFunction); + png_read_info(_png, _info); + _init = true; return true; } void -PngDec::Finalize() +PngDec::finalize() { - if (init_ && png_ != NULL) { - png_destroy_read_struct((png_structpp)&png_, (png_infopp)&info_, (png_infopp)&end_info_); - png_ = NULL; - info_ = end_info_ = NULL; + if (_init && _png != NULL) { + png_destroy_read_struct((png_structpp)&_png, (png_infopp)&_info, (png_infopp)&_end_info); + _png = NULL; + _info = _end_info = NULL; } } int -PngDec::ReadImage(WebPPicture *const pic, Metadata *const metadata) +PngDec::readImage(WebPPicture *const pic, Metadata *const metadata) { int color_type, bit_depth, interlaced; int has_alpha; @@ -256,31 +256,31 @@ PngDec::ReadImage(WebPPicture *const pic, Metadata *const metadata) uint8_t *volatile rgb = NULL; - if (!png_get_IHDR(png_, info_, &width, &height, &bit_depth, &color_type, &interlaced, NULL, NULL)) { + if (!png_get_IHDR(_png, _info, &width, &height, &bit_depth, &color_type, &interlaced, NULL, NULL)) { TS_DEBUG(TAG, "failed to get IHDR"); return false; } - png_set_strip_16(png_); - png_set_packing(png_); + png_set_strip_16(_png); + png_set_packing(_png); if (color_type == PNG_COLOR_TYPE_PALETTE) { - png_set_palette_to_rgb(png_); + png_set_palette_to_rgb(_png); } if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { if (bit_depth < 8) { - png_set_expand_gray_1_2_4_to_8(png_); + png_set_expand_gray_1_2_4_to_8(_png); } - png_set_gray_to_rgb(png_); + png_set_gray_to_rgb(_png); } - if (png_get_valid(png_, info_, PNG_INFO_tRNS)) { - png_set_tRNS_to_alpha(png_); + if (png_get_valid(_png, _info, PNG_INFO_tRNS)) { + png_set_tRNS_to_alpha(_png); has_alpha = 1; } else { has_alpha = !!(color_type & PNG_COLOR_MASK_ALPHA); } - num_passes = png_set_interlace_handling(png_); - png_read_update_info(png_, info_); + num_passes = png_set_interlace_handling(_png); + png_read_update_info(_png, _info); stride = (has_alpha ? 4 : 3) * width * sizeof(*rgb); rgb = (uint8_t *)malloc(stride * height); if (rgb == NULL) @@ -288,12 +288,12 @@ PngDec::ReadImage(WebPPicture *const pic, Metadata *const metadata) for (p = 0; p < num_passes; ++p) { for (y = 0; y < height; ++y) { png_bytep row = (png_bytep)(rgb + y * stride); - png_read_rows(png_, &row, NULL, 1); + png_read_rows(_png, &row, NULL, 1); } } - png_read_end(png_, end_info_); + png_read_end(_png, _end_info); - if (metadata != NULL && !ExtractMetadataFromPNG(metadata)) { + if (metadata != NULL && !_extractMetadataFromPNG(metadata)) { TS_DEBUG(TAG, "Error!! extracting PNG metadata!"); free(rgb); return false; @@ -310,8 +310,8 @@ PngDec::ReadImage(WebPPicture *const pic, Metadata *const metadata) bool -PngDec::ReadData(png_bytep data, png_size_t length) +PngDec::_readData(png_bytep data, png_size_t length) { - input_img_->read((char *)data, length); + _input_img->read((char *)data, length); return true; } diff --git a/lib/atscppapi/examples/webp_transform/pngdec.h b/lib/atscppapi/examples/webp_transform/pngdec.h index f9f79a73ecd..4c9d13506c5 100644 --- a/lib/atscppapi/examples/webp_transform/pngdec.h +++ b/lib/atscppapi/examples/webp_transform/pngdec.h @@ -32,11 +32,11 @@ struct WebPPicture; class PngDec { public: - PngDec() : init_(false), input_img_(NULL), info_(NULL), end_info_(NULL) {} + PngDec() : _init(false), _input_img(NULL), _info(NULL), _end_info(NULL) {} ~PngDec() {} - bool Init(std::stringstream *img); - int ReadImage(struct WebPPicture *const pic, struct Metadata *const metadata); - void Finalize(); + bool init(std::stringstream *img); + int readImage(struct WebPPicture *const pic, struct Metadata *const metadata); + void finalize(); private: struct PNGMetadataMap { @@ -45,21 +45,21 @@ class PngDec size_t storage_offset; }; - void Read(png_structp pngPtr, png_bytep data, png_size_t length); - int ExtractMetadataFromPNG(Metadata *const metadata); + void _read(png_structp pngPtr, png_bytep data, png_size_t length); + int _extractMetadataFromPNG(Metadata *const metadata); - static uint8_t *HexStringToBytes(const char *hexstring, size_t expected_length); - static int ProcessRawProfile(const char *profile, size_t profile_len, MetadataPayload *const payload); - static void ReadFunction(png_structp pngPtr, png_bytep data, png_size_t length); - static void ErrorFunction(png_structp png, png_const_charp error); - bool ReadData(png_bytep data, png_size_t len); + static uint8_t *_hexStringToBytes(const char *hexstring, size_t expected_length); + static int _processRawProfile(const char *profile, size_t profile_len, MetadataPayload *const payload); + static void _readFunction(png_structp pngPtr, png_bytep data, png_size_t length); + static void _errorFunction(png_structp png, png_const_charp error); + bool _readData(png_bytep data, png_size_t len); - bool init_; - std::stringstream *input_img_; - volatile png_structp png_; - volatile png_infop info_; - volatile png_infop end_info_; - static PNGMetadataMap png_metadata_map_[]; + bool _init; + std::stringstream * _input_img; + volatile png_structp _png; + volatile png_infop _info; + volatile png_infop _end_info; + static PNGMetadataMap _png_metadata_map[]; }; #endif // PNGDEC_H_ From 4866cdf09e62ed97e6211324db305255eb4cf80c Mon Sep 17 00:00:00 2001 From: myraid Date: Wed, 23 Dec 2015 17:21:58 -0800 Subject: [PATCH 07/19] [TS-4095] correct readme --- lib/atscppapi/examples/webp_transform/README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/atscppapi/examples/webp_transform/README b/lib/atscppapi/examples/webp_transform/README index 476fc93c531..f088ae9d773 100644 --- a/lib/atscppapi/examples/webp_transform/README +++ b/lib/atscppapi/examples/webp_transform/README @@ -1,4 +1,4 @@ -onverting jpeg and png to webp +Converting jpeg and png to webp Pre-requisites 1. webp From a5109adc31993c36ebe592578f5d41dd5fccba32 Mon Sep 17 00:00:00 2001 From: myraid Date: Mon, 28 Dec 2015 12:44:46 -0800 Subject: [PATCH 08/19] [TS-4095] moving webp_transform to experimental --- configure.ac | 6 +++++- lib/atscppapi/examples/Makefile.am | 8 -------- plugins/experimental/Makefile.am | 9 +++++++++ .../experimental}/webp_transform/Common.h | 0 .../experimental}/webp_transform/ImageTransform.cc | 0 .../experimental}/webp_transform/ImageTransform.h | 0 .../experimental}/webp_transform/Makefile.am | 0 .../experimental}/webp_transform/README | 0 .../experimental}/webp_transform/compress.cc | 0 .../experimental}/webp_transform/compress.h | 0 .../experimental}/webp_transform/jpegdec.cc | 0 .../experimental}/webp_transform/jpegdec.h | 0 .../experimental}/webp_transform/metadata.cc | 0 .../experimental}/webp_transform/metadata.h | 0 .../experimental}/webp_transform/pngdec.cc | 0 .../experimental}/webp_transform/pngdec.h | 0 16 files changed, 14 insertions(+), 9 deletions(-) rename {lib/atscppapi/examples => plugins/experimental}/webp_transform/Common.h (100%) rename {lib/atscppapi/examples => plugins/experimental}/webp_transform/ImageTransform.cc (100%) rename {lib/atscppapi/examples => plugins/experimental}/webp_transform/ImageTransform.h (100%) rename {lib/atscppapi/examples => plugins/experimental}/webp_transform/Makefile.am (100%) rename {lib/atscppapi/examples => plugins/experimental}/webp_transform/README (100%) rename {lib/atscppapi/examples => plugins/experimental}/webp_transform/compress.cc (100%) rename {lib/atscppapi/examples => plugins/experimental}/webp_transform/compress.h (100%) rename {lib/atscppapi/examples => plugins/experimental}/webp_transform/jpegdec.cc (100%) rename {lib/atscppapi/examples => plugins/experimental}/webp_transform/jpegdec.h (100%) rename {lib/atscppapi/examples => plugins/experimental}/webp_transform/metadata.cc (100%) rename {lib/atscppapi/examples => plugins/experimental}/webp_transform/metadata.h (100%) rename {lib/atscppapi/examples => plugins/experimental}/webp_transform/pngdec.cc (100%) rename {lib/atscppapi/examples => plugins/experimental}/webp_transform/pngdec.h (100%) diff --git a/configure.ac b/configure.ac index c6e7d6313ee..26a7ab6175f 100644 --- a/configure.ac +++ b/configure.ac @@ -1952,6 +1952,11 @@ AC_CHECK_LIB([png],[png_set_read_fn],[AC_SUBST([LIB_PNG],["-lpng"])],[has_png=0] AC_SUBST(has_png) AM_CONDITIONAL([HAS_PNG], [ test "x${has_png}" = "x1" ]) +AS_IF([test "x$enable_experimental_plugins" = "xyes"], [ + AS_IF([test "x$enable_cppapi" = "xyes"], [ + AC_CONFIG_FILES([plugins/experimental/webp_transform/Makefile]) + ])]) + AS_IF([test "x$enable_cppapi" = "xyes"], [ AC_CONFIG_FILES([ lib/atscppapi/Makefile @@ -1977,7 +1982,6 @@ AS_IF([test "x$enable_cppapi" = "xyes"], [ lib/atscppapi/examples/timeout_example/Makefile lib/atscppapi/examples/transactionhook/Makefile lib/atscppapi/examples/async_http_fetch_streaming/Makefile - lib/atscppapi/examples/webp_transform/Makefile lib/atscppapi/src/Makefile ])]) diff --git a/lib/atscppapi/examples/Makefile.am b/lib/atscppapi/examples/Makefile.am index f30a0ae1650..9f56838cf5d 100644 --- a/lib/atscppapi/examples/Makefile.am +++ b/lib/atscppapi/examples/Makefile.am @@ -37,11 +37,3 @@ SUBDIRS = \ async_timer \ intercept \ async_http_fetch_streaming - -if HAS_WEBP -if HAS_JPEG -if HAS_PNG - SUBDIRS += webp_transform -endif -endif -endif diff --git a/plugins/experimental/Makefile.am b/plugins/experimental/Makefile.am index a3252a48ae4..484cc537126 100644 --- a/plugins/experimental/Makefile.am +++ b/plugins/experimental/Makefile.am @@ -53,3 +53,12 @@ endif if BUILD_LUAJIT SUBDIRS += ts_lua endif + +if HAS_WEBP +if HAS_JPEG +if HAS_PNG + SUBDIRS += webp_transform +endif +endif +endif + diff --git a/lib/atscppapi/examples/webp_transform/Common.h b/plugins/experimental/webp_transform/Common.h similarity index 100% rename from lib/atscppapi/examples/webp_transform/Common.h rename to plugins/experimental/webp_transform/Common.h diff --git a/lib/atscppapi/examples/webp_transform/ImageTransform.cc b/plugins/experimental/webp_transform/ImageTransform.cc similarity index 100% rename from lib/atscppapi/examples/webp_transform/ImageTransform.cc rename to plugins/experimental/webp_transform/ImageTransform.cc diff --git a/lib/atscppapi/examples/webp_transform/ImageTransform.h b/plugins/experimental/webp_transform/ImageTransform.h similarity index 100% rename from lib/atscppapi/examples/webp_transform/ImageTransform.h rename to plugins/experimental/webp_transform/ImageTransform.h diff --git a/lib/atscppapi/examples/webp_transform/Makefile.am b/plugins/experimental/webp_transform/Makefile.am similarity index 100% rename from lib/atscppapi/examples/webp_transform/Makefile.am rename to plugins/experimental/webp_transform/Makefile.am diff --git a/lib/atscppapi/examples/webp_transform/README b/plugins/experimental/webp_transform/README similarity index 100% rename from lib/atscppapi/examples/webp_transform/README rename to plugins/experimental/webp_transform/README diff --git a/lib/atscppapi/examples/webp_transform/compress.cc b/plugins/experimental/webp_transform/compress.cc similarity index 100% rename from lib/atscppapi/examples/webp_transform/compress.cc rename to plugins/experimental/webp_transform/compress.cc diff --git a/lib/atscppapi/examples/webp_transform/compress.h b/plugins/experimental/webp_transform/compress.h similarity index 100% rename from lib/atscppapi/examples/webp_transform/compress.h rename to plugins/experimental/webp_transform/compress.h diff --git a/lib/atscppapi/examples/webp_transform/jpegdec.cc b/plugins/experimental/webp_transform/jpegdec.cc similarity index 100% rename from lib/atscppapi/examples/webp_transform/jpegdec.cc rename to plugins/experimental/webp_transform/jpegdec.cc diff --git a/lib/atscppapi/examples/webp_transform/jpegdec.h b/plugins/experimental/webp_transform/jpegdec.h similarity index 100% rename from lib/atscppapi/examples/webp_transform/jpegdec.h rename to plugins/experimental/webp_transform/jpegdec.h diff --git a/lib/atscppapi/examples/webp_transform/metadata.cc b/plugins/experimental/webp_transform/metadata.cc similarity index 100% rename from lib/atscppapi/examples/webp_transform/metadata.cc rename to plugins/experimental/webp_transform/metadata.cc diff --git a/lib/atscppapi/examples/webp_transform/metadata.h b/plugins/experimental/webp_transform/metadata.h similarity index 100% rename from lib/atscppapi/examples/webp_transform/metadata.h rename to plugins/experimental/webp_transform/metadata.h diff --git a/lib/atscppapi/examples/webp_transform/pngdec.cc b/plugins/experimental/webp_transform/pngdec.cc similarity index 100% rename from lib/atscppapi/examples/webp_transform/pngdec.cc rename to plugins/experimental/webp_transform/pngdec.cc diff --git a/lib/atscppapi/examples/webp_transform/pngdec.h b/plugins/experimental/webp_transform/pngdec.h similarity index 100% rename from lib/atscppapi/examples/webp_transform/pngdec.h rename to plugins/experimental/webp_transform/pngdec.h From 48b09fd55d7306159131c40672cab57fa519c322 Mon Sep 17 00:00:00 2001 From: myraid Date: Mon, 28 Dec 2015 14:28:20 -0800 Subject: [PATCH 09/19] [TS-4095] add documentation for webp_transform --- doc/admin-guide/plugins/index.en.rst | 1 + doc/admin-guide/plugins/webp_transform.en.rst | 35 +++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 doc/admin-guide/plugins/webp_transform.en.rst diff --git a/doc/admin-guide/plugins/index.en.rst b/doc/admin-guide/plugins/index.en.rst index 37845d6784c..ed02f0dd93e 100644 --- a/doc/admin-guide/plugins/index.en.rst +++ b/doc/admin-guide/plugins/index.en.rst @@ -89,3 +89,4 @@ directory of the Apache Traffic Server source tree. Experimental plugins can be hipes.en stale_while_revalidate.en ts-lua: allows plugins to be written in Lua instead of C code + webp_transform: converts jpeg and png images to webp format diff --git a/doc/admin-guide/plugins/webp_transform.en.rst b/doc/admin-guide/plugins/webp_transform.en.rst new file mode 100644 index 00000000000..8075ea3a1ae --- /dev/null +++ b/doc/admin-guide/plugins/webp_transform.en.rst @@ -0,0 +1,35 @@ +.. _webp_transform: + +WebpTransform Plugin +**************** + +.. Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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. + +This plugin converts jpeg and png images and transforms them into webp format. + + +This plugin is a global plugin. + + add webp_transform.so in plugin.config file. + + +Note +=================== + +This plugin only supports jpeg and png and require libjpeg > 1.9 and libpng > 1.6.16 + \ No newline at end of file From 50b2d408834f8e2a955239528fe9eb49d6998827 Mon Sep 17 00:00:00 2001 From: myraid Date: Mon, 28 Dec 2015 14:44:20 -0800 Subject: [PATCH 10/19] [TS-4095] ]small changes to webp_transform doc --- doc/admin-guide/plugins/webp_transform.en.rst | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/doc/admin-guide/plugins/webp_transform.en.rst b/doc/admin-guide/plugins/webp_transform.en.rst index 8075ea3a1ae..fea928747a9 100644 --- a/doc/admin-guide/plugins/webp_transform.en.rst +++ b/doc/admin-guide/plugins/webp_transform.en.rst @@ -21,15 +21,18 @@ WebpTransform Plugin under the License. This plugin converts jpeg and png images and transforms them into webp format. +All response with content-type 'image/jpeg' or 'image/png' will go through the transform. +Content-type is changed to 'image/webp' on successful transformation. +Installation +============ -This plugin is a global plugin. +Add the following line to :file:`plugin.config`:: - add webp_transform.so in plugin.config file. + webp_transform.so Note =================== This plugin only supports jpeg and png and require libjpeg > 1.9 and libpng > 1.6.16 - \ No newline at end of file From 94e157422304c300537b65c0bd4e96edcec0657a Mon Sep 17 00:00:00 2001 From: myraid Date: Tue, 29 Dec 2015 10:55:40 -0800 Subject: [PATCH 11/19] [TS-4095] c-lang formatting --- .../webp_transform/ImageTransform.h | 2 +- .../experimental/webp_transform/compress.h | 22 ++++++++++--------- plugins/experimental/webp_transform/jpegdec.h | 20 ++++++++--------- .../experimental/webp_transform/metadata.h | 2 +- plugins/experimental/webp_transform/pngdec.cc | 2 +- plugins/experimental/webp_transform/pngdec.h | 12 +++++----- 6 files changed, 31 insertions(+), 29 deletions(-) diff --git a/plugins/experimental/webp_transform/ImageTransform.h b/plugins/experimental/webp_transform/ImageTransform.h index a3e69ca40de..24f385ebd1c 100644 --- a/plugins/experimental/webp_transform/ImageTransform.h +++ b/plugins/experimental/webp_transform/ImageTransform.h @@ -51,7 +51,7 @@ class ImageTransform : public atscppapi::TransformationPlugin private: std::stringstream _img; - WebpTransform _webp_transform; + WebpTransform _webp_transform; }; class GlobalHookPlugin : public atscppapi::GlobalPlugin diff --git a/plugins/experimental/webp_transform/compress.h b/plugins/experimental/webp_transform/compress.h index 3029c70c051..91685c84ab8 100644 --- a/plugins/experimental/webp_transform/compress.h +++ b/plugins/experimental/webp_transform/compress.h @@ -45,7 +45,9 @@ class WebpTransform bool init(); bool transform(std::stringstream &stream); void finalize(); - std::stringstream &getTransformedImage() { + std::stringstream & + getTransformedImage() + { return _stream; } @@ -67,15 +69,15 @@ class WebpTransform void _webpMemoryWriterClear(); static const std::string _errors[]; - bool _init; - WebPMemoryWriter _writer; + bool _init; + WebPMemoryWriter _writer; std::stringstream _stream; - WebPPicture _picture; - WebPConfig _config; - Metadata _metadata; - std::string _debug_tag; - PngDec _png_dec; - JpegDec _jpeg_dec; + WebPPicture _picture; + WebPConfig _config; + Metadata _metadata; + std::string _debug_tag; + PngDec _png_dec; + JpegDec _jpeg_dec; }; -#endif //WEBPTRANSFORM_H_ +#endif // WEBPTRANSFORM_H_ diff --git a/plugins/experimental/webp_transform/jpegdec.h b/plugins/experimental/webp_transform/jpegdec.h index ee9cef72be8..8ff5f5aadce 100644 --- a/plugins/experimental/webp_transform/jpegdec.h +++ b/plugins/experimental/webp_transform/jpegdec.h @@ -32,8 +32,8 @@ struct WebPPicture; typedef struct { const uint8_t *data; - size_t data_length; - int seq; // this segment's sequence number [1, 255] for use in reassembly. + size_t data_length; + int seq; // this segment's sequence number [1, 255] for use in reassembly. } ICCPSegment; class JpegDec @@ -48,14 +48,14 @@ class JpegDec private: struct ErrorMgr { struct jpeg_error_mgr pub; - jmp_buf setjmp_buffer; + jmp_buf setjmp_buffer; }; struct JpegMetadataMap { - int marker; + int marker; const char *signature; - size_t signature_length; - size_t storage_offset; + size_t signature_length; + size_t storage_offset; }; static int _compareICCPSegments(const void *a, const void *b); @@ -65,11 +65,11 @@ class JpegDec static void _error(j_common_ptr dinfo); - bool _init; - std::stringstream * _input_img; + bool _init; + std::stringstream *_input_img; volatile struct jpeg_decompress_struct _dinfo; - struct ErrorMgr _jerr; - static JpegMetadataMap _jpeg_metadata_map[]; + struct ErrorMgr _jerr; + static JpegMetadataMap _jpeg_metadata_map[]; }; #endif // JPEGDEC_H_ diff --git a/plugins/experimental/webp_transform/metadata.h b/plugins/experimental/webp_transform/metadata.h index fd0a1311b98..104760cb1ae 100644 --- a/plugins/experimental/webp_transform/metadata.h +++ b/plugins/experimental/webp_transform/metadata.h @@ -27,7 +27,7 @@ extern "C" { typedef struct MetadataPayload { uint8_t *bytes; - size_t size; + size_t size; } MetadataPayload; typedef struct Metadata { diff --git a/plugins/experimental/webp_transform/pngdec.cc b/plugins/experimental/webp_transform/pngdec.cc index beb508715e3..4f2025220d2 100644 --- a/plugins/experimental/webp_transform/pngdec.cc +++ b/plugins/experimental/webp_transform/pngdec.cc @@ -312,6 +312,6 @@ PngDec::readImage(WebPPicture *const pic, Metadata *const metadata) bool PngDec::_readData(png_bytep data, png_size_t length) { - _input_img->read((char *)data, length); + _input_img->read((char *)data, length); return true; } diff --git a/plugins/experimental/webp_transform/pngdec.h b/plugins/experimental/webp_transform/pngdec.h index 4c9d13506c5..82b7ffffe21 100644 --- a/plugins/experimental/webp_transform/pngdec.h +++ b/plugins/experimental/webp_transform/pngdec.h @@ -32,7 +32,7 @@ struct WebPPicture; class PngDec { public: - PngDec() : _init(false), _input_img(NULL), _info(NULL), _end_info(NULL) {} + PngDec() : _init(false), _input_img(NULL), _info(NULL), _end_info(NULL) {} ~PngDec() {} bool init(std::stringstream *img); int readImage(struct WebPPicture *const pic, struct Metadata *const metadata); @@ -55,11 +55,11 @@ class PngDec bool _readData(png_bytep data, png_size_t len); - bool _init; - std::stringstream * _input_img; - volatile png_structp _png; - volatile png_infop _info; - volatile png_infop _end_info; + bool _init; + std::stringstream *_input_img; + volatile png_structp _png; + volatile png_infop _info; + volatile png_infop _end_info; static PNGMetadataMap _png_metadata_map[]; }; #endif // PNGDEC_H_ From 937784267c96716138e2a7e802f7bc926a696cc2 Mon Sep 17 00:00:00 2001 From: myraid Date: Thu, 18 Feb 2016 16:19:33 -0800 Subject: [PATCH 12/19] [TS-4095] using ImageMagick instead of raw jpeg/png/webp api --- plugins/experimental/webp_transform/Common.h | 30 -- .../webp_transform/ImageTransform.cc | 123 ++++--- .../webp_transform/ImageTransform.h | 65 ---- .../experimental/webp_transform/Makefile.am | 7 +- plugins/experimental/webp_transform/README | 6 +- .../experimental/webp_transform/compress.cc | 198 ----------- .../experimental/webp_transform/compress.h | 83 ----- .../experimental/webp_transform/jpegdec.cc | 284 ---------------- plugins/experimental/webp_transform/jpegdec.h | 75 ----- .../experimental/webp_transform/metadata.cc | 64 ---- .../experimental/webp_transform/metadata.h | 52 --- plugins/experimental/webp_transform/pngdec.cc | 317 ------------------ plugins/experimental/webp_transform/pngdec.h | 65 ---- 13 files changed, 74 insertions(+), 1295 deletions(-) delete mode 100644 plugins/experimental/webp_transform/Common.h delete mode 100644 plugins/experimental/webp_transform/ImageTransform.h delete mode 100644 plugins/experimental/webp_transform/compress.cc delete mode 100644 plugins/experimental/webp_transform/compress.h delete mode 100644 plugins/experimental/webp_transform/jpegdec.cc delete mode 100644 plugins/experimental/webp_transform/jpegdec.h delete mode 100644 plugins/experimental/webp_transform/metadata.cc delete mode 100644 plugins/experimental/webp_transform/metadata.h delete mode 100644 plugins/experimental/webp_transform/pngdec.cc delete mode 100644 plugins/experimental/webp_transform/pngdec.h diff --git a/plugins/experimental/webp_transform/Common.h b/plugins/experimental/webp_transform/Common.h deleted file mode 100644 index 3f1f2f78818..00000000000 --- a/plugins/experimental/webp_transform/Common.h +++ /dev/null @@ -1,30 +0,0 @@ -/** @file - - ATSCPPAPI plugin to do webp transform. - - @section license License - - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you 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. -*/ - -#ifndef COMMON_H_ -#define COMMON_H_ - -#define TAG "img_transform" - - -#endif /* COMMON_H_ */ diff --git a/plugins/experimental/webp_transform/ImageTransform.cc b/plugins/experimental/webp_transform/ImageTransform.cc index 208b5cca0ac..d7b2b5819b1 100644 --- a/plugins/experimental/webp_transform/ImageTransform.cc +++ b/plugins/experimental/webp_transform/ImageTransform.cc @@ -19,79 +19,92 @@ #include #include #include +#include +#include #include -#include "compress.h" -#include "Common.h" -#include "ImageTransform.h" +#include -using namespace atscppapi; using std::string; +using namespace Magick; +using namespace atscppapi; - -std::string ImageTransform::FIELD_USER_AGENT("User-Agent"); -std::string ImageTransform::FIELD_CONTENT_TYPE("Content-Type"); -std::string ImageTransform::FIELD_TRANSFORM_IMAGE("@X-Transform-Image"); -std::string ImageTransform::CONTEXT_IMG_TRANSFORM("Transform-Image"); -std::string ImageTransform::USER_AGENT_CHROME("Chrome"); -std::string ImageTransform::FIELD_VARY("Vary"); -std::string ImageTransform::IMAGE_TYPE("image/webp"); - - -ImageTransform::ImageTransform(Transaction &transaction) - : TransformationPlugin(transaction, TransformationPlugin::RESPONSE_TRANSFORMATION), _webp_transform() +namespace { - TransformationPlugin::registerHook(HOOK_READ_RESPONSE_HEADERS); +#define TAG "webp_transform" } -ImageTransform::~ImageTransform() +class ImageTransform : public TransformationPlugin { - _webp_transform.finalize(); -} +public: + ImageTransform(Transaction &transaction) + : TransformationPlugin(transaction, TransformationPlugin::RESPONSE_TRANSFORMATION) + { + TransformationPlugin::registerHook(HOOK_READ_RESPONSE_HEADERS); + InitializeMagick(""); + } -void -ImageTransform::handleReadResponseHeaders(Transaction &transaction) -{ - transaction.getClientResponse().getHeaders()[ImageTransform::FIELD_CONTENT_TYPE] = ImageTransform::IMAGE_TYPE; - transaction.getClientResponse().getHeaders()[ImageTransform::FIELD_VARY] = ImageTransform::ImageTransform::FIELD_CONTENT_TYPE; + void handleReadResponseHeaders(Transaction &transaction) + { + transaction.getServerResponse().getHeaders()["Content-Type"] = "image/webp"; + transaction.getServerResponse().getHeaders()["Vary"] = "Content-Type"; //to have a separate cache entry. - TS_DEBUG(TAG, "Image Transformation Plugin for url %s", transaction.getServerRequest().getUrl().getUrlString().c_str()); - transaction.resume(); -} + TS_DEBUG(TAG, "url %s", transaction.getServerRequest().getUrl().getUrlString().c_str()); + transaction.resume(); + } -void -ImageTransform::consume(const string &data) -{ - _img.write(data.data(), data.size()); -} + void consume(const string &data) + { + _img.write(data.data(), data.size()); + } -void -ImageTransform::handleInputComplete() -{ - _webp_transform.init(); - _webp_transform.transform(_img); - produce(_webp_transform.getTransformedImage().str()); + void handleInputComplete() + { - setOutputComplete(); -} + string input_data = _img.str(); + Blob input_blob(input_data.data(), input_data.length()); + Image image; + image.read(input_blob); -GlobalHookPlugin::GlobalHookPlugin() -{ - registerHook(HOOK_READ_RESPONSE_HEADERS); -} + Blob output_blob; + image.magick( "WEBP" ); + image.write( &output_blob); + string output_data(reinterpret_cast(output_blob.data()), output_blob.length()); + produce(output_data); -void -GlobalHookPlugin::handleReadResponseHeaders(Transaction &transaction) + setOutputComplete(); + } + + virtual ~ImageTransform() { } + +private: + std::stringstream _img; +}; + + +class GlobalHookPlugin : public GlobalPlugin { - // add transformation only for jpeg files - string ctype = transaction.getServerResponse().getHeaders().values(ImageTransform::FIELD_CONTENT_TYPE); - string user_agent = transaction.getServerRequest().getHeaders().values(ImageTransform::FIELD_USER_AGENT); - if (user_agent.find(ImageTransform::USER_AGENT_CHROME) != string::npos && - (ctype.find("jpeg") != string::npos || ctype.find("png") != string::npos)) { - transaction.addPlugin(new ImageTransform(transaction)); +public: + GlobalHookPlugin() + { + registerHook(HOOK_READ_RESPONSE_HEADERS); } - transaction.resume(); -} + virtual void handleReadResponseHeaders(Transaction &transaction) + { + + string ctype = transaction.getServerResponse().getHeaders().values("Content-Type"); + string user_agent = transaction.getServerRequest().getHeaders().values("User-Agent"); + std::cout << "user_agent: %s" << user_agent << std::endl; + std::cout << "content_type: %s" << ctype << std::endl; + if (user_agent.find("Chrome") != string::npos && + (ctype.find("jpeg") != string::npos || ctype.find("png") != string::npos)) { + std::cout << "Content type is either jpeg or png. Converting to webp" << std::endl; + transaction.addPlugin(new ImageTransform(transaction)); + } + + transaction.resume(); + } +}; void TSPluginInit(int argc ATSCPPAPI_UNUSED, const char *argv[] ATSCPPAPI_UNUSED) diff --git a/plugins/experimental/webp_transform/ImageTransform.h b/plugins/experimental/webp_transform/ImageTransform.h deleted file mode 100644 index 24f385ebd1c..00000000000 --- a/plugins/experimental/webp_transform/ImageTransform.h +++ /dev/null @@ -1,65 +0,0 @@ -/** @file - - ATSCPPAPI plugin to do webp transform. - - @section license License - - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you 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. -*/ - -#ifndef IMAGETRANSFROM_H_ -#define IMAGETRANSFROM_H_ - -#include -#include -#include -#include -#include - - -class ImageTransform : public atscppapi::TransformationPlugin -{ -public: - ImageTransform(atscppapi::Transaction &transaction); - - void handleReadResponseHeaders(atscppapi::Transaction &transaction); - void consume(const std::string &data); - void handleInputComplete(); - virtual ~ImageTransform(); - - static std::string FIELD_USER_AGENT; - static std::string FIELD_TRANSFORM_IMAGE; - static std::string CONTEXT_IMG_TRANSFORM; - static std::string USER_AGENT_CHROME; - static std::string FIELD_CONTENT_TYPE; - static std::string FIELD_VARY; - static std::string IMAGE_TYPE; - -private: - std::stringstream _img; - WebpTransform _webp_transform; -}; - -class GlobalHookPlugin : public atscppapi::GlobalPlugin -{ -public: - GlobalHookPlugin(); - virtual void handleReadResponseHeaders(atscppapi::Transaction &transaction); -}; - - -#endif /* IMAGETRANSFROM_H_ */ diff --git a/plugins/experimental/webp_transform/Makefile.am b/plugins/experimental/webp_transform/Makefile.am index f9007cc1f9d..3a3ec025b8c 100644 --- a/plugins/experimental/webp_transform/Makefile.am +++ b/plugins/experimental/webp_transform/Makefile.am @@ -14,13 +14,14 @@ # 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. -AM_CPPFLAGS = -I$(top_srcdir)/lib/atscppapi/src/include -Wno-unused-variable +AM_CPPFLAGS = -I$(top_srcdir)/lib/atscppapi/src/include -Wno-unused-variable `Magick++-config --cppflags --cxxflags` target=WebpTransform.so pkglibdir = ${pkglibexecdir} pkglib_LTLIBRARIES = WebpTransform.la -WebpTransform_la_SOURCES = ImageTransform.cc jpegdec.cc pngdec.cc metadata.cc compress.cc -WebpTransform_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir)/lib/atscppapi/src/ -latscppapi -lwebp -ljpeg -lpng +WebpTransform_la_SOURCES = ImageTransform.cc +WebpTransform_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir)/lib/atscppapi/src/ -latscppapi $(TS_PLUGIN_LDFLAGS) `Magick++-config --ldflags --libs` + all: ln -sf .libs/$(target) diff --git a/plugins/experimental/webp_transform/README b/plugins/experimental/webp_transform/README index f088ae9d773..595d0e6ad1e 100644 --- a/plugins/experimental/webp_transform/README +++ b/plugins/experimental/webp_transform/README @@ -1,6 +1,4 @@ -Converting jpeg and png to webp +Converting jpeg and png to webp using ImageMagick Magick++ lib Pre-requisites -1. webp -2. jpeg version 9 and above -- http://ijg.org/files/jpegsrc.v9.tar.gz -3. png version 1.6.19 and above -- http://sourceforge.net/projects/libpng/files/libpng19/1.6.19/libpng-1.6.19.tar.xz/download +1. Magick++ api for ImageMagick diff --git a/plugins/experimental/webp_transform/compress.cc b/plugins/experimental/webp_transform/compress.cc deleted file mode 100644 index 848fbdc338e..00000000000 --- a/plugins/experimental/webp_transform/compress.cc +++ /dev/null @@ -1,198 +0,0 @@ -/** @file - - ATSCPPAPI plugin to do webp transform. - - @section license License - - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you 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. -*/ - -#include -#include -#include - - -#include -#include -#include "compress.h" -#include "Common.h" - -#define MAGIC_SIZE 12; -using std::string; -using std::vector; - - -static int -StreamWriter(const uint8_t *data, size_t data_size, const WebPPicture *const pic) -{ - WebpTransform *webp_transform = static_cast(pic->custom_ptr); - webp_transform->writeImage(reinterpret_cast(data), data_size); - return data_size ? data_size : 1; -} - -const string WebpTransform::_errors[] = { - "OK", "OUT_OF_MEMORY: Out of memory allocating objects", "BITSTREAM_OUT_OF_MEMORY: Out of memory re-allocating byte buffer", - "NULL_PARAMETER: NULL parameter passed to function", "INVALID_CONFIGURATION: configuration is invalid", - "BAD_DIMENSION: Bad picture dimension. Maximum width and height " - "allowed is 16383 pixels.", - "PARTITION0_OVERFLOW: Partition #0 is too big to fit 512k.\n" - "To reduce the size of this partition, try using less segments " - "with the -segments option, and eventually reduce the number of " - "header bits using -partition_limit. More details are available " - "in the manual (`man cwebp`)", - "PARTITION_OVERFLOW: Partition is too big to fit 16M", "BAD_WRITE: Picture writer returned an I/O error", - "FILE_TOO_BIG: File would be too big to fit in 4G", "USER_ABORT: encoding abort requested by user"}; - -void -WebpTransform::_webpMemoryWriterClear() -{ - if (_writer.mem != NULL) { - free(_writer.mem); - _writer.mem = NULL; - _writer.size = 0; - _writer.max_size = 0; - } -} - - -WebpTransform::InputFileFormat -WebpTransform::_getImageType(std::stringstream &input_img) -{ - InputFileFormat format = UNSUPPORTED; - uint32_t magic1, magic2; - uint8_t buf[12]; - input_img.read((char *)buf, 12); - input_img.seekg(0, input_img.beg); - - magic1 = ((uint32_t)buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; - magic2 = ((uint32_t)buf[8] << 24) | (buf[9] << 16) | (buf[10] << 8) | buf[11]; - if (magic1 == 0x89504E47U) { - format = PNG_; - } else if (magic1 >= 0xFFD8FF00U && magic1 <= 0xFFD8FFFFU) { - format = JPEG_; - } else if (magic1 == 0x52494646 && magic2 == 0x57454250) { - format = WEBP_; - } - return format; -} - -int -WebpTransform::_readImage(std::stringstream &input_img) -{ - int ok = 0; - - if (_picture.width == 0 || _picture.height == 0) { - // If no size specified, try to decode it as PNG/JPEG (as appropriate). - const InputFileFormat format = _getImageType(input_img); - if (format == PNG_) { - if (!_png_dec.init(&input_img)) { - _png_dec.finalize(); - return 0; - } - ok = _png_dec.readImage(&_picture, &_metadata); - } else if (format == JPEG_) { - if (!_jpeg_dec.init(&input_img)) { - _jpeg_dec.finalize(); - return 0; - } - ok = _jpeg_dec.readImage(&_picture, &_metadata); - } else if (format == WEBP_) { - TS_DEBUG(TAG, "Already webp file. Nothing to be done."); - } - } - if (!ok) - TS_DEBUG(TAG, "Unsupported image format. Failed to read image."); - - return ok; -} - - -void -WebpTransform::_allocExtraInfo() -{ - const int mb_w = (_picture.width + 15) / 16; - const int mb_h = (_picture.height + 15) / 16; - _picture.extra_info = (uint8_t *)malloc(mb_w * mb_h * sizeof(_picture.extra_info)); -} - -bool -WebpTransform::init() -{ - MetadataInit(&_metadata); - WebPMemoryWriterInit(&_writer); - if (!WebPPictureInit(&_picture) || !WebPConfigInit(&_config)) { - TS_DEBUG(TAG, "DEBUG! Version mismatch"); - return false; - } - WebPPreset preset = WEBP_PRESET_PICTURE; - if (!WebPConfigPreset(&_config, preset, _config.quality)) { - TS_DEBUG(TAG, "DEBUG! Could initialize configuration with preset."); - return false; - } - - if (!WebPValidateConfig(&_config)) { - TS_DEBUG(TAG, "DEBUG! Invalid configuration."); - return false; - } - _init = true; - return true; -} - - -bool -WebpTransform::transform(std::stringstream &input_img) -{ - if (!_readImage(input_img)) { - TS_DEBUG(TAG, "Cannot read input picture file ."); - return false; - } - _picture.progress_hook = NULL; - - _picture.writer = StreamWriter; - _picture.custom_ptr = (void *)this; - - if (_picture.extra_info_type > 0) { - _allocExtraInfo(); - } - - if (!WebPEncode(&_config, &_picture)) { - TS_DEBUG(TAG, "DEBUG! Cannot encode picture as WebP. Error code: %d (%s)", _picture.error_code, - WebpTransform::_errors[_picture.error_code].c_str()); - return false; - } - return true; -} - -void -WebpTransform::finalize() -{ - if (_init) { - _webpMemoryWriterClear(); - free(_picture.extra_info); - MetadataFree(&_metadata); - WebPPictureFree(&_picture); - - _png_dec.finalize(); - _jpeg_dec.finalize(); - } -} - -void -WebpTransform::writeImage(const char *data, size_t data_size) -{ - _stream.write(data, data_size); -} diff --git a/plugins/experimental/webp_transform/compress.h b/plugins/experimental/webp_transform/compress.h deleted file mode 100644 index 91685c84ab8..00000000000 --- a/plugins/experimental/webp_transform/compress.h +++ /dev/null @@ -1,83 +0,0 @@ -/** @file - - ATSCPPAPI plugin to do webp transform. - - @section license License - - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you 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. -*/ - -#ifndef WEBPTRANSFORM_H_ -#define WEBPTRANSFORM_H_ - -#include -#include -#include -#include - -#include -#include "jpegdec.h" -#include "pngdec.h" -#include "metadata.h" - - -class WebpTransform -{ -public: - WebpTransform() : _init(false), _png_dec(), _jpeg_dec() {} - - ~WebpTransform() {} - - bool init(); - bool transform(std::stringstream &stream); - void finalize(); - std::stringstream & - getTransformedImage() - { - return _stream; - } - - void writeImage(const char *data, size_t data_size); - -private: - typedef enum { PNG_ = 0, JPEG_, WEBP_, UNSUPPORTED } InputFileFormat; - - enum { - METADATA_EXIF = (1 << 0), - METADATA_ICC = (1 << 1), - METADATA_XMP = (1 << 2), - METADATA_ALL = METADATA_EXIF | METADATA_ICC | METADATA_XMP - }; - - InputFileFormat _getImageType(std::stringstream &input_msg); - int _readImage(std::stringstream &input_img); - void _allocExtraInfo(); - void _webpMemoryWriterClear(); - - static const std::string _errors[]; - bool _init; - WebPMemoryWriter _writer; - std::stringstream _stream; - WebPPicture _picture; - WebPConfig _config; - Metadata _metadata; - std::string _debug_tag; - PngDec _png_dec; - JpegDec _jpeg_dec; -}; - -#endif // WEBPTRANSFORM_H_ diff --git a/plugins/experimental/webp_transform/jpegdec.cc b/plugins/experimental/webp_transform/jpegdec.cc deleted file mode 100644 index bf6206ac567..00000000000 --- a/plugins/experimental/webp_transform/jpegdec.cc +++ /dev/null @@ -1,284 +0,0 @@ -/** - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you 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. - */ - -#include - -#include -#include -#include -#include -#include -#include "webp/encode.h" -#include "metadata.h" -#include "jpegdec.h" -#include "Common.h" - -#define JPEG_APP1 (JPEG_APP0 + 1) -#define JPEG_APP2 (JPEG_APP0 + 2) - - -JpegDec::JpegMetadataMap JpegDec::_jpeg_metadata_map[] = { - // Exif 2.2 Section 4.7.2 Interoperability Structure of APP1 ... - {JPEG_APP1, "Exif\0", 6, METADATA_OFFSET(exif)}, - // XMP Specification Part 3 Section 3 Embedding XMP Metadata ... #JPEG - // TODO(jzern) Add support for 'ExtendedXMP' - {JPEG_APP1, "http://ns.adobe.com/xap/1.0/", 29, METADATA_OFFSET(xmp)}, - {0, NULL, 0, 0}, -}; - -void -JpegDec::_saveMetadataMarkers() -{ - const unsigned int max_marker_length = 0xffff; - jpeg_save_markers((j_decompress_ptr)&_dinfo, JPEG_APP1, max_marker_length); // Exif/XMP - jpeg_save_markers((j_decompress_ptr)&_dinfo, JPEG_APP2, max_marker_length); // ICC profile -} - -int -JpegDec::_compareICCPSegments(const void *a, const void *b) -{ - const ICCPSegment *s1 = (const ICCPSegment *)a; - const ICCPSegment *s2 = (const ICCPSegment *)b; - return s1->seq - s2->seq; -} - - -int -JpegDec::_storeICCP(MetadataPayload *const iccp) -{ - // ICC.1:2010-12 (4.3.0.0) Annex B.4 Embedding ICC Profiles in JPEG files - static const char kICCPSignature[] = "ICC_PROFILE"; - static const size_t kICCPSignatureLength = 12; // signature includes '\0' - static const size_t kICCPSkipLength = 14; // signature + seq & count - int expected_count = 0; - int actual_count = 0; - int seq_max = 0; - size_t total_size = 0; - ICCPSegment iccp_segments[255]; - jpeg_saved_marker_ptr marker; - - memset(iccp_segments, 0, sizeof(iccp_segments)); - for (marker = _dinfo.marker_list; marker != NULL; marker = marker->next) { - if (marker->marker == JPEG_APP2 && marker->data_length > kICCPSkipLength && - !memcmp(marker->data, kICCPSignature, kICCPSignatureLength)) { - // ICC_PROFILE\0; 'seq' starts at 1. - const int seq = marker->data[kICCPSignatureLength]; - const int count = marker->data[kICCPSignatureLength + 1]; - const size_t segment_size = marker->data_length - kICCPSkipLength; - ICCPSegment *segment; - if (segment_size == 0 || count == 0 || seq == 0) { - TS_DEBUG(TAG, "[ICCP] size (%d) / count (%d) / sequence number (%d) cannot be 0!", (int)segment_size, seq, count); - return 0; - } - - if (expected_count == 0) { - expected_count = count; - } else if (expected_count != count) { - TS_DEBUG(TAG, "[ICCP] Inconsistent segment count (%d / %d)!\n", expected_count, count); - return 0; - } - - segment = iccp_segments + seq - 1; - if (segment->data_length != 0) { - TS_DEBUG(TAG, "[ICCP] Duplicate segment number (%d)!\n", seq); - return 0; - } - - segment->data = marker->data + kICCPSkipLength; - segment->data_length = segment_size; - segment->seq = seq; - total_size += segment_size; - if (seq > seq_max) - seq_max = seq; - ++actual_count; - } - } - - if (actual_count == 0) - return 1; - if (seq_max != actual_count) { - TS_DEBUG(TAG, "[ICCP] Discontinuous segments, expected: %d actual: %d!\n", actual_count, seq_max); - return 0; - } - if (expected_count != actual_count) { - TS_DEBUG(TAG, "[ICCP] Segment count: %d does not match expected: %d!\n", actual_count, expected_count); - return 0; - } - - // The segments may appear out of order in the file, sort them based on - // sequence number before assembling the payload. - qsort(iccp_segments, actual_count, sizeof(*iccp_segments), JpegDec::_compareICCPSegments); - - iccp->bytes = (uint8_t *)malloc(total_size); - if (iccp->bytes == NULL) - return 0; - iccp->size = total_size; - - { - int i; - size_t offset = 0; - for (i = 0; i < seq_max; ++i) { - memcpy(iccp->bytes + offset, iccp_segments[i].data, iccp_segments[i].data_length); - offset += iccp_segments[i].data_length; - } - } - return 1; -} - -// Returns true on success and false for memory errors and corrupt profiles. -// The caller must use MetadataFree() on 'metadata' in all cases. -int -JpegDec::_extractMetadataFromJPEG(Metadata *const metadata) -{ - jpeg_saved_marker_ptr marker; - // Treat ICC profiles separately as they may be segmented and out of order. - if (!_storeICCP(&metadata->iccp)) - return 0; - - for (marker = _dinfo.marker_list; marker != NULL; marker = marker->next) { - int i; - for (i = 0; _jpeg_metadata_map[i].marker != 0; ++i) { - if (marker->marker == _jpeg_metadata_map[i].marker && marker->data_length > _jpeg_metadata_map[i].signature_length && - !memcmp(marker->data, _jpeg_metadata_map[i].signature, _jpeg_metadata_map[i].signature_length)) { - MetadataPayload *const payload = (MetadataPayload *)((uint8_t *)metadata + _jpeg_metadata_map[i].storage_offset); - - if (payload->bytes == NULL) { - const char *marker_data = (const char *)marker->data + _jpeg_metadata_map[i].signature_length; - const size_t marker_data_length = marker->data_length - _jpeg_metadata_map[i].signature_length; - if (!MetadataCopy(marker_data, marker_data_length, payload)) - return 0; - } else { - TS_DEBUG(TAG, "Ignoring additional '%s' marker\n", _jpeg_metadata_map[i].signature); - } - } - } - } - return 1; -} - -#undef JPEG_APP1 -#undef JPEG_APP2 - -// ----------------------------------------------------------------------------- -// JPEG decoding - - -void -JpegDec::_error(j_common_ptr dinfo) -{ - struct JpegDec::ErrorMgr *err = (struct JpegDec::ErrorMgr *)dinfo->err; - dinfo->err->output_message(dinfo); - longjmp(err->setjmp_buffer, 1); -} - -bool -JpegDec::init(std::stringstream *img) -{ - _input_img = img; - - memset((j_decompress_ptr)&_dinfo, 0, sizeof(_dinfo)); // for setjmp sanity - _dinfo.err = jpeg_std_error(&_jerr.pub); - _jerr.pub.error_exit = JpegDec::_error; - - if (setjmp(_jerr.setjmp_buffer)) { - TS_DEBUG(TAG, " setjmp failed"); - jpeg_destroy_decompress((j_decompress_ptr)&_dinfo); - return false; - } - - jpeg_create_decompress((j_decompress_ptr)&_dinfo); - _init = true; - return true; -} - -int -JpegDec::readImage(WebPPicture *const pic, Metadata *const metadata) -{ - int ok = 0; - int stride, width, height; - uint8_t *volatile rgb = NULL; - JSAMPROW buffer[1]; - - std::string img_str = _input_img->str(); - // TODO: Can this copy be avoided. - jpeg_mem_src((j_decompress_ptr)&_dinfo, (unsigned char *)img_str.data(), img_str.size()); - - if (metadata != NULL) - _saveMetadataMarkers(); - jpeg_read_header((j_decompress_ptr)&_dinfo, TRUE); - - _dinfo.out_color_space = JCS_RGB; - _dinfo.do_fancy_upsampling = TRUE; - - jpeg_start_decompress((j_decompress_ptr)&_dinfo); - - if (_dinfo.output_components != 3) { - TS_DEBUG(TAG, "not enought output componenets available."); - return 0; - } - - width = _dinfo.output_width; - height = _dinfo.output_height; - stride = _dinfo.output_width * _dinfo.output_components * sizeof(*rgb); - - rgb = (uint8_t *)malloc(stride * height); - if (rgb == NULL) { - TS_DEBUG(TAG, "unable to alloc memory for rgb."); - return 0; - } - buffer[0] = (JSAMPLE *)rgb; - - while (_dinfo.output_scanline < _dinfo.output_height) { - if (jpeg_read_scanlines((j_decompress_ptr)&_dinfo, buffer, 1) != 1) { - free(rgb); - return 0; - } - buffer[0] += stride; - } - - if (metadata != NULL) { - ok = _extractMetadataFromJPEG(metadata); - if (!ok) { - TS_DEBUG(TAG, "Error extracting JPEG metadata!"); - free(rgb); - return 0; - } - } - - jpeg_finish_decompress((j_decompress_ptr)&_dinfo); - jpeg_destroy_decompress((j_decompress_ptr)&_dinfo); - - // WebP conversion. - pic->width = width; - pic->height = height; - pic->use_argb = 1; // store raw RGB samples - ok = WebPPictureImportRGB(pic, rgb, stride); - if (!ok) { - TS_DEBUG(TAG, "Unable to import inot webp"); - } - - free(rgb); - return ok; -} - -void -JpegDec::finalize() -{ - if (_init) - jpeg_destroy_decompress((j_decompress_ptr)&_dinfo); -} diff --git a/plugins/experimental/webp_transform/jpegdec.h b/plugins/experimental/webp_transform/jpegdec.h deleted file mode 100644 index 8ff5f5aadce..00000000000 --- a/plugins/experimental/webp_transform/jpegdec.h +++ /dev/null @@ -1,75 +0,0 @@ -/** - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you 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. - */ - -#ifndef JPEGDEC_H_ -#define JPEGDEC_H_ - -#include -#include -#include -#include -#include -#include -#include "jpegdec.h" -#include "metadata.h" - -struct WebPPicture; - -typedef struct { - const uint8_t *data; - size_t data_length; - int seq; // this segment's sequence number [1, 255] for use in reassembly. -} ICCPSegment; - -class JpegDec -{ -public: - JpegDec() : _init(false) {} - ~JpegDec() {} - bool init(std::stringstream *img); - int readImage(struct WebPPicture *const pic, struct Metadata *const metadata); - void finalize(); - -private: - struct ErrorMgr { - struct jpeg_error_mgr pub; - jmp_buf setjmp_buffer; - }; - - struct JpegMetadataMap { - int marker; - const char *signature; - size_t signature_length; - size_t storage_offset; - }; - - static int _compareICCPSegments(const void *a, const void *b); - int _storeICCP(MetadataPayload *const iccp); - int _extractMetadataFromJPEG(Metadata *const metadata); - void _saveMetadataMarkers(); - - static void _error(j_common_ptr dinfo); - - bool _init; - std::stringstream *_input_img; - volatile struct jpeg_decompress_struct _dinfo; - struct ErrorMgr _jerr; - static JpegMetadataMap _jpeg_metadata_map[]; -}; - -#endif // JPEGDEC_H_ diff --git a/plugins/experimental/webp_transform/metadata.cc b/plugins/experimental/webp_transform/metadata.cc deleted file mode 100644 index 8bcd7bc86a8..00000000000 --- a/plugins/experimental/webp_transform/metadata.cc +++ /dev/null @@ -1,64 +0,0 @@ -/** - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you 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. - */ - -#include -#include - -#include "webp/types.h" -#include "metadata.h" - -void -MetadataInit(Metadata *const metadata) -{ - if (metadata == NULL) - return; - memset(metadata, 0, sizeof(*metadata)); -} - -void -MetadataPayloadDelete(MetadataPayload *const payload) -{ - if (payload == NULL) - return; - free(payload->bytes); - payload->bytes = NULL; - payload->size = 0; -} - -void -MetadataFree(Metadata *const metadata) -{ - if (metadata == NULL) - return; - MetadataPayloadDelete(&metadata->exif); - MetadataPayloadDelete(&metadata->iccp); - MetadataPayloadDelete(&metadata->xmp); -} - -int -MetadataCopy(const char *metadata, size_t metadata_len, MetadataPayload *const payload) -{ - if (metadata == NULL || metadata_len == 0 || payload == NULL) - return 0; - payload->bytes = (uint8_t *)malloc(metadata_len); - if (payload->bytes == NULL) - return 0; - payload->size = metadata_len; - memcpy(payload->bytes, metadata, metadata_len); - return 1; -} diff --git a/plugins/experimental/webp_transform/metadata.h b/plugins/experimental/webp_transform/metadata.h deleted file mode 100644 index 104760cb1ae..00000000000 --- a/plugins/experimental/webp_transform/metadata.h +++ /dev/null @@ -1,52 +0,0 @@ -/** - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you 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. - */ - -#ifndef METADATA_H_ -#define METADATA_H_ - -#include "webp/types.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct MetadataPayload { - uint8_t *bytes; - size_t size; -} MetadataPayload; - -typedef struct Metadata { - MetadataPayload exif; - MetadataPayload iccp; - MetadataPayload xmp; -} Metadata; - -#define METADATA_OFFSET(x) offsetof(Metadata, x) - -void MetadataInit(Metadata *const metadata); -void MetadataPayloadDelete(MetadataPayload *const payload); -void MetadataFree(Metadata *const metadata); - -// Stores 'metadata' to 'payload->bytes', returns false on allocation error. -int MetadataCopy(const char *metadata, size_t metadata_len, MetadataPayload *const payload); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // METADATA_H_ diff --git a/plugins/experimental/webp_transform/pngdec.cc b/plugins/experimental/webp_transform/pngdec.cc deleted file mode 100644 index 4f2025220d2..00000000000 --- a/plugins/experimental/webp_transform/pngdec.cc +++ /dev/null @@ -1,317 +0,0 @@ -/** - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you 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. - */ - -#include -#include -#include -#include -#include // note: this must be included *after* png.h -#include -#include -#include - -#include "webp/encode.h" -#include "metadata.h" -#include "pngdec.h" -#include "Common.h" - -void -PngDec::_errorFunction(png_structp png, png_const_charp error) -{ - if (error != NULL) - TS_DEBUG("img_transform_png", "libpng error: %s\n", error); - longjmp(png_jmpbuf(png), 1); -} - -void -PngDec::_readFunction(png_structp pngPtr, png_bytep data, png_size_t length) -{ - PngDec *png_dec = reinterpret_cast(png_get_io_ptr(pngPtr)); - png_dec->_readData(data, length); -} - -PngDec::PNGMetadataMap PngDec::_png_metadata_map[] = { - // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PNG.html#TextualData - // See also: ExifTool on CPAN. - {"Raw profile type exif", PngDec::_processRawProfile, METADATA_OFFSET(exif)}, - {"Raw profile type xmp", PngDec::_processRawProfile, METADATA_OFFSET(xmp)}, - // Exiftool puts exif data in APP1 chunk, too. - {"Raw profile type APP1", PngDec::_processRawProfile, METADATA_OFFSET(exif)}, - // XMP Specification Part 3, Section 3 #PNG - {"XML:com.adobe.xmp", MetadataCopy, METADATA_OFFSET(xmp)}, - {NULL, NULL, 0}, -}; - -int -PngDec::_processRawProfile(const char *profile, size_t profile_len, MetadataPayload *const payload) -{ - const char *src = profile; - char *end; - int expected_length; - - if (profile == NULL || profile_len == 0) - return 0; - - // ImageMagick formats 'raw profiles' as - // '\n\n(%8lu)\n\n'. - if (*src != '\n') { - TS_DEBUG(TAG, "Malformed raw profile, expected '\\n' got '\\x%.2X'\n", *src); - return 0; - } - ++src; - // skip the profile name and extract the length. - while (*src != '\0' && *src++ != '\n') { - } - expected_length = (int)strtol(src, &end, 10); - if (*end != '\n') { - TS_DEBUG(TAG, "Malformed raw profile, expected '\\n' got '\\x%.2X'\n", *end); - return 0; - } - ++end; - - // 'end' now points to the profile payload. - payload->bytes = _hexStringToBytes(end, expected_length); - if (payload->bytes == NULL) { - TS_DEBUG(TAG, " failed"); - return 0; - } - payload->size = expected_length; - return 1; -} - -// Converts the NULL terminated 'hexstring' which contains 2-byte character -// representations of hex values to raw data. -// 'hexstring' may contain values consisting of [A-F][a-f][0-9] in pairs, -// e.g., 7af2..., separated by any number of newlines. -// 'expected_length' is the anticipated processed size. -// On success the raw buffer is returned with its length equivalent to -// 'expected_length'. NULL is returned if the processed length is less than -// 'expected_length' or any character aside from those above is encountered. -// The returned buffer must be freed by the caller. -uint8_t * -PngDec::_hexStringToBytes(const char *hexstring, size_t expected_length) -{ - const char *src = hexstring; - size_t actual_length = 0; - uint8_t *const raw_data = (uint8_t *)malloc(expected_length); - uint8_t *dst; - - if (raw_data == NULL) - return NULL; - - for (dst = raw_data; actual_length < expected_length && *src != '\0'; ++src) { - char *end; - char val[3]; - if (*src == '\n') - continue; - val[0] = *src++; - val[1] = *src; - val[2] = '\0'; - *dst++ = (uint8_t)strtol(val, &end, 16); - if (end != val + 2) - break; - ++actual_length; - } - if (actual_length != expected_length) { - free(raw_data); - return NULL; - } - return raw_data; -} - - -// Looks for metadata at both the beginning and end of the PNG file, giving -// preference to the head. -// Returns true on success. The caller must use MetadataFree() on 'metadata' in -// all cases. -int -PngDec::_extractMetadataFromPNG(Metadata *const metadata) -{ - int p; - for (p = 0; p < 2; ++p) { - png_infop const info = (p == 0) ? _info : _end_info; - png_textp text = NULL; - const int num = png_get_text(_png, info, &text, NULL); - int i; - // Look for EXIF / XMP metadata. - for (i = 0; i < num; ++i, ++text) { - int j; - for (j = 0; _png_metadata_map[j].name != NULL; ++j) { - if (!strcmp(text->key, _png_metadata_map[j].name)) { - MetadataPayload *const payload = (MetadataPayload *)((uint8_t *)metadata + _png_metadata_map[j].storage_offset); - png_size_t text_length; - switch (text->compression) { -#ifdef PNG_iTXt_SUPPORTED - case PNG_ITXT_COMPRESSION_NONE: - case PNG_ITXT_COMPRESSION_zTXt: - text_length = text->itxt_length; - break; -#endif - case PNG_TEXT_COMPRESSION_NONE: - case PNG_TEXT_COMPRESSION_zTXt: - default: - text_length = text->text_length; - break; - } - if (payload->bytes != NULL) { - TS_DEBUG(TAG, "Ignoring additional '%s'\n", text->key); - } else if (!_png_metadata_map[j].process(text->text, text_length, payload)) { - TS_DEBUG(TAG, "Failed to process: '%s'\n", text->key); - return 0; - } - break; - } - } - } - // Look for an ICC profile. - { - png_charp name; - int comp_type; -#if ((PNG_LIBPNG_VER_MAJOR << 8) | PNG_LIBPNG_VER_MINOR << 0) < ((1 << 8) | (5 << 0)) - png_charp profile; -#else // >= libpng 1.5.0 - png_bytep profile; -#endif - png_uint_32 len; - - if (png_get_iCCP(_png, info, &name, &comp_type, &profile, &len) == PNG_INFO_iCCP) { - if (!MetadataCopy((const char *)profile, len, &metadata->iccp)) - return 0; - } - } - } - - return 1; -} - -bool -PngDec::init(std::stringstream *img) -{ - _input_img = img; - _png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0); - if (_png == NULL) { - TS_DEBUG(TAG, "Error! Unable to create read structure"); - return false; - } - - png_set_error_fn(_png, 0, PngDec::_errorFunction, NULL); - if (setjmp(png_jmpbuf(_png))) { - TS_DEBUG(TAG, "Error! setjmp failed"); - return false; - } - - _info = png_create_info_struct(_png); - if (_info == NULL) { - TS_DEBUG(TAG, "Error! could not create info struct for info_"); - return false; - } - _end_info = png_create_info_struct(_png); - if (_end_info == NULL) { - TS_DEBUG(TAG, "Error! could not create info struct for info_"); - return false; - } - - // png_init_io(png, in_file); - png_set_read_fn(_png, (void *)this, PngDec::_readFunction); - png_read_info(_png, _info); - _init = true; - return true; -} - -void -PngDec::finalize() -{ - if (_init && _png != NULL) { - png_destroy_read_struct((png_structpp)&_png, (png_infopp)&_info, (png_infopp)&_end_info); - _png = NULL; - _info = _end_info = NULL; - } -} - -int -PngDec::readImage(WebPPicture *const pic, Metadata *const metadata) -{ - int color_type, bit_depth, interlaced; - int has_alpha; - int num_passes; - int p; - int ok = 0; - png_uint_32 width, height, y; - int stride; - uint8_t *volatile rgb = NULL; - - - if (!png_get_IHDR(_png, _info, &width, &height, &bit_depth, &color_type, &interlaced, NULL, NULL)) { - TS_DEBUG(TAG, "failed to get IHDR"); - return false; - } - - png_set_strip_16(_png); - png_set_packing(_png); - if (color_type == PNG_COLOR_TYPE_PALETTE) { - png_set_palette_to_rgb(_png); - } - if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { - if (bit_depth < 8) { - png_set_expand_gray_1_2_4_to_8(_png); - } - png_set_gray_to_rgb(_png); - } - if (png_get_valid(_png, _info, PNG_INFO_tRNS)) { - png_set_tRNS_to_alpha(_png); - has_alpha = 1; - } else { - has_alpha = !!(color_type & PNG_COLOR_MASK_ALPHA); - } - - num_passes = png_set_interlace_handling(_png); - png_read_update_info(_png, _info); - stride = (has_alpha ? 4 : 3) * width * sizeof(*rgb); - rgb = (uint8_t *)malloc(stride * height); - if (rgb == NULL) - return false; - for (p = 0; p < num_passes; ++p) { - for (y = 0; y < height; ++y) { - png_bytep row = (png_bytep)(rgb + y * stride); - png_read_rows(_png, &row, NULL, 1); - } - } - png_read_end(_png, _end_info); - - if (metadata != NULL && !_extractMetadataFromPNG(metadata)) { - TS_DEBUG(TAG, "Error!! extracting PNG metadata!"); - free(rgb); - return false; - } - - pic->width = width; - pic->height = height; - pic->use_argb = 1; - ok = has_alpha ? WebPPictureImportRGBA(pic, rgb, stride) : WebPPictureImportRGB(pic, rgb, stride); - - free(rgb); - return ok; -} - - -bool -PngDec::_readData(png_bytep data, png_size_t length) -{ - _input_img->read((char *)data, length); - return true; -} diff --git a/plugins/experimental/webp_transform/pngdec.h b/plugins/experimental/webp_transform/pngdec.h deleted file mode 100644 index 82b7ffffe21..00000000000 --- a/plugins/experimental/webp_transform/pngdec.h +++ /dev/null @@ -1,65 +0,0 @@ -/** - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you 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. - */ - -#ifndef PNGDEC_H_ -#define PNGDEC_H_ - -#include -#include -#include -#include -#include -#include "pngdec.h" -#include "metadata.h" - -struct WebPPicture; - -class PngDec -{ -public: - PngDec() : _init(false), _input_img(NULL), _info(NULL), _end_info(NULL) {} - ~PngDec() {} - bool init(std::stringstream *img); - int readImage(struct WebPPicture *const pic, struct Metadata *const metadata); - void finalize(); - -private: - struct PNGMetadataMap { - const char *name; - int (*process)(const char *profile, size_t profile_len, MetadataPayload *const payload); - size_t storage_offset; - }; - - void _read(png_structp pngPtr, png_bytep data, png_size_t length); - int _extractMetadataFromPNG(Metadata *const metadata); - - static uint8_t *_hexStringToBytes(const char *hexstring, size_t expected_length); - static int _processRawProfile(const char *profile, size_t profile_len, MetadataPayload *const payload); - static void _readFunction(png_structp pngPtr, png_bytep data, png_size_t length); - static void _errorFunction(png_structp png, png_const_charp error); - bool _readData(png_bytep data, png_size_t len); - - - bool _init; - std::stringstream *_input_img; - volatile png_structp _png; - volatile png_infop _info; - volatile png_infop _end_info; - static PNGMetadataMap _png_metadata_map[]; -}; -#endif // PNGDEC_H_ From 2940c6e2b3b1f8b57b3aef7d3e51904d5265e181 Mon Sep 17 00:00:00 2001 From: myraid Date: Thu, 18 Feb 2016 17:11:34 -0800 Subject: [PATCH 13/19] [TS-4095] use Magick++ pkg_check --- configure.ac | 21 ++++++------------- plugins/experimental/Makefile.am | 10 ++------- .../experimental/webp_transform/Makefile.am | 16 +++++++------- 3 files changed, 15 insertions(+), 32 deletions(-) diff --git a/configure.ac b/configure.ac index 26a7ab6175f..fc7084c1593 100644 --- a/configure.ac +++ b/configure.ac @@ -413,6 +413,12 @@ AM_CONDITIONAL([BUILD_EXPERIMENTAL_PLUGINS], [ test "x${enable_experimental_plug PKG_CHECK_MODULES([LIBMEMCACHED], [libmemcached >= 1.0], [have_libmemcached=yes], [have_libmemcached=no]) AM_CONDITIONAL([BUILD_MEMCACHED_REMAP_PLUGIN], [test "x${have_libmemcached}" = "xyes"]) +# +# Enable experimental/webp_transform plugin +# +PKG_CHECK_MODULES([LIBMAGICKCPP],[Magick++], [have_libmagick++=yes], [have_libmagick++=no]) +AM_CONDITIONAL([BUILD_WEBP_TRANSFORM_PLUGIN], [test "x${have_libmagic++}" = "xyes"]) + # # Example plugins. The example plugins are always built, but not always installed. Installing # them is useful for QA, but not useful for most users, so we default this to disabled. @@ -1937,21 +1943,6 @@ AS_IF([test "x$enable_experimental_plugins" = "xyes"], [ plugins/experimental/stream_editor/Makefile ])]) -AC_CHECK_HEADERS([webp/encode.h], [has_webp=1],[has_webp=0]) -AC_CHECK_LIB([webp],[WebPEncode],[AC_SUBST([LIB_WEBP],["-lwebp"])],[has_webp=0]) -AC_SUBST(has_webp) -AM_CONDITIONAL([HAS_WEBP], [ test "x${has_webp}" = "x1" ]) - -AC_CHECK_HEADERS([jpeglib.h], [has_jpeg=1],[has_jpeg=0]) -AC_CHECK_LIB([jpeg],[jpeg_mem_src],[AC_SUBST([LIB_JPEG],["-ljpeg"])],[has_jpeg=0]) -AC_SUBST(has_jpeg) -AM_CONDITIONAL([HAS_JPEG], [ test "x${has_jpeg}" = "x1" ]) - -AC_CHECK_HEADERS([png.h], [has_png=1],[has_png=0]) -AC_CHECK_LIB([png],[png_set_read_fn],[AC_SUBST([LIB_PNG],["-lpng"])],[has_png=0]) -AC_SUBST(has_png) -AM_CONDITIONAL([HAS_PNG], [ test "x${has_png}" = "x1" ]) - AS_IF([test "x$enable_experimental_plugins" = "xyes"], [ AS_IF([test "x$enable_cppapi" = "xyes"], [ AC_CONFIG_FILES([plugins/experimental/webp_transform/Makefile]) diff --git a/plugins/experimental/Makefile.am b/plugins/experimental/Makefile.am index 484cc537126..e88595ec194 100644 --- a/plugins/experimental/Makefile.am +++ b/plugins/experimental/Makefile.am @@ -44,7 +44,8 @@ SUBDIRS = \ url_sig \ xdebug \ mp4 \ - stream_editor + stream_editor \ + webp_transform if HAS_MYSQL SUBDIRS += mysql_remap @@ -54,11 +55,4 @@ if BUILD_LUAJIT SUBDIRS += ts_lua endif -if HAS_WEBP -if HAS_JPEG -if HAS_PNG - SUBDIRS += webp_transform -endif -endif -endif diff --git a/plugins/experimental/webp_transform/Makefile.am b/plugins/experimental/webp_transform/Makefile.am index 3a3ec025b8c..04bdd4ecf66 100644 --- a/plugins/experimental/webp_transform/Makefile.am +++ b/plugins/experimental/webp_transform/Makefile.am @@ -14,17 +14,15 @@ # 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. -AM_CPPFLAGS = -I$(top_srcdir)/lib/atscppapi/src/include -Wno-unused-variable `Magick++-config --cppflags --cxxflags` +include $(top_srcdir)/build/plugins.mk + +if BUILD_WEBP_TRANSFORM_PLUGIN + +AM_CPPFLAGS = -I$(top_srcdir)/lib/atscppapi/src/include -Wno-unused-variable $(LIBMAGICKCPP_CFLAGS) target=WebpTransform.so -pkglibdir = ${pkglibexecdir} pkglib_LTLIBRARIES = WebpTransform.la WebpTransform_la_SOURCES = ImageTransform.cc -WebpTransform_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir)/lib/atscppapi/src/ -latscppapi $(TS_PLUGIN_LDFLAGS) `Magick++-config --ldflags --libs` - - -all: - ln -sf .libs/$(target) +WebpTransform_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir)/lib/atscppapi/src/ -latscppapi $(TS_PLUGIN_LDFLAGS) $(LIBMAGICKCPP_LIBS) -clean-local: - rm -f $(target) +fi From 1c84ca736565ad7768049ad62d01717d20ae2502 Mon Sep 17 00:00:00 2001 From: myraid Date: Thu, 18 Feb 2016 17:14:35 -0800 Subject: [PATCH 14/19] [TS-4095] remove couts --- plugins/experimental/webp_transform/ImageTransform.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/plugins/experimental/webp_transform/ImageTransform.cc b/plugins/experimental/webp_transform/ImageTransform.cc index d7b2b5819b1..bba750b79ce 100644 --- a/plugins/experimental/webp_transform/ImageTransform.cc +++ b/plugins/experimental/webp_transform/ImageTransform.cc @@ -94,11 +94,9 @@ class GlobalHookPlugin : public GlobalPlugin string ctype = transaction.getServerResponse().getHeaders().values("Content-Type"); string user_agent = transaction.getServerRequest().getHeaders().values("User-Agent"); - std::cout << "user_agent: %s" << user_agent << std::endl; - std::cout << "content_type: %s" << ctype << std::endl; if (user_agent.find("Chrome") != string::npos && (ctype.find("jpeg") != string::npos || ctype.find("png") != string::npos)) { - std::cout << "Content type is either jpeg or png. Converting to webp" << std::endl; + TS_DEBUG(TAG, "Content type is either jpeg or png. Converting to webp"); transaction.addPlugin(new ImageTransform(transaction)); } From 00b6c4f61152ec459aa0862861da98d6bea7a53e Mon Sep 17 00:00:00 2001 From: myraid Date: Thu, 18 Feb 2016 17:15:50 -0800 Subject: [PATCH 15/19] [TS-4095] clang formatting --- .../webp_transform/ImageTransform.cc | 33 +++++++++---------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/plugins/experimental/webp_transform/ImageTransform.cc b/plugins/experimental/webp_transform/ImageTransform.cc index bba750b79ce..b636fd06581 100644 --- a/plugins/experimental/webp_transform/ImageTransform.cc +++ b/plugins/experimental/webp_transform/ImageTransform.cc @@ -37,45 +37,46 @@ namespace class ImageTransform : public TransformationPlugin { public: - ImageTransform(Transaction &transaction) - : TransformationPlugin(transaction, TransformationPlugin::RESPONSE_TRANSFORMATION) + ImageTransform(Transaction &transaction) : TransformationPlugin(transaction, TransformationPlugin::RESPONSE_TRANSFORMATION) { TransformationPlugin::registerHook(HOOK_READ_RESPONSE_HEADERS); InitializeMagick(""); } - void handleReadResponseHeaders(Transaction &transaction) + void + handleReadResponseHeaders(Transaction &transaction) { transaction.getServerResponse().getHeaders()["Content-Type"] = "image/webp"; - transaction.getServerResponse().getHeaders()["Vary"] = "Content-Type"; //to have a separate cache entry. + transaction.getServerResponse().getHeaders()["Vary"] = "Content-Type"; // to have a separate cache entry. TS_DEBUG(TAG, "url %s", transaction.getServerRequest().getUrl().getUrlString().c_str()); transaction.resume(); } - void consume(const string &data) + void + consume(const string &data) { _img.write(data.data(), data.size()); } - void handleInputComplete() + void + handleInputComplete() { - string input_data = _img.str(); Blob input_blob(input_data.data(), input_data.length()); Image image; image.read(input_blob); Blob output_blob; - image.magick( "WEBP" ); - image.write( &output_blob); + image.magick("WEBP"); + image.write(&output_blob); string output_data(reinterpret_cast(output_blob.data()), output_blob.length()); produce(output_data); setOutputComplete(); } - virtual ~ImageTransform() { } + virtual ~ImageTransform() {} private: std::stringstream _img; @@ -85,17 +86,13 @@ class ImageTransform : public TransformationPlugin class GlobalHookPlugin : public GlobalPlugin { public: - GlobalHookPlugin() - { - registerHook(HOOK_READ_RESPONSE_HEADERS); - } - virtual void handleReadResponseHeaders(Transaction &transaction) + GlobalHookPlugin() { registerHook(HOOK_READ_RESPONSE_HEADERS); } + virtual void + handleReadResponseHeaders(Transaction &transaction) { - string ctype = transaction.getServerResponse().getHeaders().values("Content-Type"); string user_agent = transaction.getServerRequest().getHeaders().values("User-Agent"); - if (user_agent.find("Chrome") != string::npos && - (ctype.find("jpeg") != string::npos || ctype.find("png") != string::npos)) { + if (user_agent.find("Chrome") != string::npos && (ctype.find("jpeg") != string::npos || ctype.find("png") != string::npos)) { TS_DEBUG(TAG, "Content type is either jpeg or png. Converting to webp"); transaction.addPlugin(new ImageTransform(transaction)); } From c6dd200cc7876b8b8796b3b190bc6ce12db057b5 Mon Sep 17 00:00:00 2001 From: myraid Date: Thu, 18 Feb 2016 18:45:43 -0800 Subject: [PATCH 16/19] [TS-4095] fix Makefile issues --- plugins/experimental/webp_transform/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/experimental/webp_transform/Makefile.am b/plugins/experimental/webp_transform/Makefile.am index 04bdd4ecf66..8678e15d0b5 100644 --- a/plugins/experimental/webp_transform/Makefile.am +++ b/plugins/experimental/webp_transform/Makefile.am @@ -19,10 +19,10 @@ include $(top_srcdir)/build/plugins.mk if BUILD_WEBP_TRANSFORM_PLUGIN -AM_CPPFLAGS = -I$(top_srcdir)/lib/atscppapi/src/include -Wno-unused-variable $(LIBMAGICKCPP_CFLAGS) +AM_CPPFLAGS += -I$(top_srcdir)/lib/atscppapi/src/include -Wno-unused-variable $(LIBMAGICKCPP_CFLAGS) target=WebpTransform.so pkglib_LTLIBRARIES = WebpTransform.la WebpTransform_la_SOURCES = ImageTransform.cc WebpTransform_la_LDFLAGS = -module -avoid-version -shared -L$(top_srcdir)/lib/atscppapi/src/ -latscppapi $(TS_PLUGIN_LDFLAGS) $(LIBMAGICKCPP_LIBS) -fi +endif From 729386465eb1b92a227782aaf86ecfd1b691edc9 Mon Sep 17 00:00:00 2001 From: myraid Date: Fri, 19 Feb 2016 12:00:27 -0800 Subject: [PATCH 17/19] [TS-4095] change name of conditional to BUILD_HAS_IMAGEMAGICKCPP --- configure.ac | 6 +++--- plugins/experimental/webp_transform/Makefile.am | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index fc7084c1593..293ec9ac52f 100644 --- a/configure.ac +++ b/configure.ac @@ -414,10 +414,10 @@ PKG_CHECK_MODULES([LIBMEMCACHED], [libmemcached >= 1.0], [have_libmemcached=yes] AM_CONDITIONAL([BUILD_MEMCACHED_REMAP_PLUGIN], [test "x${have_libmemcached}" = "xyes"]) # -# Enable experimental/webp_transform plugin +# Check Magick++ is available. Enable experimental/webp_transform plugin # -PKG_CHECK_MODULES([LIBMAGICKCPP],[Magick++], [have_libmagick++=yes], [have_libmagick++=no]) -AM_CONDITIONAL([BUILD_WEBP_TRANSFORM_PLUGIN], [test "x${have_libmagic++}" = "xyes"]) +PKG_CHECK_MODULES([LIBMAGICKCPP],[Magick++], [have_libmagickcpp=yes], [have_libmagickcpp=no]) +AM_CONDITIONAL([BUILD_HAS_IMAGEMAGICKCPP], [test "x${have_libmagickcpp}" = "xyes"]) # # Example plugins. The example plugins are always built, but not always installed. Installing diff --git a/plugins/experimental/webp_transform/Makefile.am b/plugins/experimental/webp_transform/Makefile.am index 8678e15d0b5..64ef1ab7e5e 100644 --- a/plugins/experimental/webp_transform/Makefile.am +++ b/plugins/experimental/webp_transform/Makefile.am @@ -17,7 +17,7 @@ include $(top_srcdir)/build/plugins.mk -if BUILD_WEBP_TRANSFORM_PLUGIN +if BUILD_HAS_IMAGEMAGICKCPP AM_CPPFLAGS += -I$(top_srcdir)/lib/atscppapi/src/include -Wno-unused-variable $(LIBMAGICKCPP_CFLAGS) target=WebpTransform.so From 8a129af08a7af41ea8f80a667404885b54bc2f24 Mon Sep 17 00:00:00 2001 From: myraid Date: Fri, 19 Feb 2016 12:01:16 -0800 Subject: [PATCH 18/19] [TS-4095] move ImageMagick Initialization to PluginInit --- plugins/experimental/webp_transform/ImageTransform.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/experimental/webp_transform/ImageTransform.cc b/plugins/experimental/webp_transform/ImageTransform.cc index b636fd06581..b5d22bbfb63 100644 --- a/plugins/experimental/webp_transform/ImageTransform.cc +++ b/plugins/experimental/webp_transform/ImageTransform.cc @@ -40,7 +40,6 @@ class ImageTransform : public TransformationPlugin ImageTransform(Transaction &transaction) : TransformationPlugin(transaction, TransformationPlugin::RESPONSE_TRANSFORMATION) { TransformationPlugin::registerHook(HOOK_READ_RESPONSE_HEADERS); - InitializeMagick(""); } void @@ -105,5 +104,6 @@ void TSPluginInit(int argc ATSCPPAPI_UNUSED, const char *argv[] ATSCPPAPI_UNUSED) { RegisterGlobalPlugin("CPP_Webp_Transform", "apache", "dev@trafficserver.apache.org"); + InitializeMagick(""); new GlobalHookPlugin(); } From 852ba2c97598d329b819d4dc652ab1b1dd03af5d Mon Sep 17 00:00:00 2001 From: myraid Date: Fri, 19 Feb 2016 12:08:15 -0800 Subject: [PATCH 19/19] [TS-4095] doc to reflect the correct dependency --- doc/admin-guide/plugins/webp_transform.en.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/admin-guide/plugins/webp_transform.en.rst b/doc/admin-guide/plugins/webp_transform.en.rst index fea928747a9..280aca6d18e 100644 --- a/doc/admin-guide/plugins/webp_transform.en.rst +++ b/doc/admin-guide/plugins/webp_transform.en.rst @@ -35,4 +35,5 @@ Add the following line to :file:`plugin.config`:: Note =================== -This plugin only supports jpeg and png and require libjpeg > 1.9 and libpng > 1.6.16 +This plugin only supports jpeg and png and requires Magick++ from ImageMagick. +Other image formats can easily be supported.