From 4a66b3cdf1a66827767ebf495cdebdf2f81d974a Mon Sep 17 00:00:00 2001 From: Dichen Zhang Date: Wed, 19 Oct 2022 18:04:47 +0000 Subject: libjpegrecoverymap: add jpeg encoder with YUV input bug: b/252835416 test: make, jpegencoder_test Change-Id: I36f9d56374f072d9a5bb356e8b584a9b9e03bc1e --- libs/jpegrecoverymap/jpegencoder.cpp | 197 +++++++++++++++++++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 libs/jpegrecoverymap/jpegencoder.cpp (limited to 'libs/jpegrecoverymap/jpegencoder.cpp') diff --git a/libs/jpegrecoverymap/jpegencoder.cpp b/libs/jpegrecoverymap/jpegencoder.cpp new file mode 100644 index 0000000000..b5d3a063ca --- /dev/null +++ b/libs/jpegrecoverymap/jpegencoder.cpp @@ -0,0 +1,197 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +#include + +namespace android::recoverymap { + +// The destination manager that can access |mResultBuffer| in JpegEncoder. +struct destination_mgr { +public: + struct jpeg_destination_mgr mgr; + JpegEncoder* encoder; +}; + +JpegEncoder::JpegEncoder() { +} + +JpegEncoder::~JpegEncoder() { +} + +bool JpegEncoder::compressImage(const void* image, int width, int height, int quality, + const void* iccBuffer, unsigned int iccSize) { + if (width % 8 != 0 || height % 2 != 0) { + ALOGE("Image size can not be handled: %dx%d", width, height); + return false; + } + + mResultBuffer.clear(); + if (!encode(image, width, height, quality, iccBuffer, iccSize)) { + return false; + } + ALOGI("Compressed JPEG: %d[%dx%d] -> %zu bytes", + (width * height * 12) / 8, width, height, mResultBuffer.size()); + return true; +} + +const void* JpegEncoder::getCompressedImagePtr() { + return mResultBuffer.data(); +} + +size_t JpegEncoder::getCompressedImageSize() { + return mResultBuffer.size(); +} + +void JpegEncoder::initDestination(j_compress_ptr cinfo) { + destination_mgr* dest = reinterpret_cast(cinfo->dest); + std::vector& buffer = dest->encoder->mResultBuffer; + buffer.resize(kBlockSize); + dest->mgr.next_output_byte = &buffer[0]; + dest->mgr.free_in_buffer = buffer.size(); +} + +boolean JpegEncoder::emptyOutputBuffer(j_compress_ptr cinfo) { + destination_mgr* dest = reinterpret_cast(cinfo->dest); + std::vector& buffer = dest->encoder->mResultBuffer; + size_t oldsize = buffer.size(); + buffer.resize(oldsize + kBlockSize); + dest->mgr.next_output_byte = &buffer[oldsize]; + dest->mgr.free_in_buffer = kBlockSize; + return true; +} + +void JpegEncoder::terminateDestination(j_compress_ptr cinfo) { + destination_mgr* dest = reinterpret_cast(cinfo->dest); + std::vector& buffer = dest->encoder->mResultBuffer; + buffer.resize(buffer.size() - dest->mgr.free_in_buffer); +} + +void JpegEncoder::outputErrorMessage(j_common_ptr cinfo) { + char buffer[JMSG_LENGTH_MAX]; + + /* Create the message */ + (*cinfo->err->format_message) (cinfo, buffer); + ALOGE("%s\n", buffer); +} + +bool JpegEncoder::encode(const void* inYuv, int width, int height, int jpegQuality, + const void* iccBuffer, unsigned int iccSize) { + jpeg_compress_struct cinfo; + jpeg_error_mgr jerr; + + cinfo.err = jpeg_std_error(&jerr); + // Override output_message() to print error log with ALOGE(). + cinfo.err->output_message = &outputErrorMessage; + jpeg_create_compress(&cinfo); + setJpegDestination(&cinfo); + + setJpegCompressStruct(width, height, jpegQuality, &cinfo); + jpeg_start_compress(&cinfo, TRUE); + + if (iccBuffer != nullptr && iccSize > 0) { + jpeg_write_marker(&cinfo, JPEG_APP0 + 2, static_cast(iccBuffer), iccSize); + } + + if (!compress(&cinfo, static_cast(inYuv))) { + return false; + } + jpeg_finish_compress(&cinfo); + jpeg_destroy_compress(&cinfo); + return true; +} + +void JpegEncoder::setJpegDestination(jpeg_compress_struct* cinfo) { + destination_mgr* dest = static_cast((*cinfo->mem->alloc_small) ( + (j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(destination_mgr))); + dest->encoder = this; + dest->mgr.init_destination = &initDestination; + dest->mgr.empty_output_buffer = &emptyOutputBuffer; + dest->mgr.term_destination = &terminateDestination; + cinfo->dest = reinterpret_cast(dest); +} + +void JpegEncoder::setJpegCompressStruct(int width, int height, int quality, + jpeg_compress_struct* cinfo) { + cinfo->image_width = width; + cinfo->image_height = height; + cinfo->input_components = 3; + cinfo->in_color_space = JCS_YCbCr; + jpeg_set_defaults(cinfo); + + jpeg_set_quality(cinfo, quality, TRUE); + jpeg_set_colorspace(cinfo, JCS_YCbCr); + cinfo->raw_data_in = TRUE; + cinfo->dct_method = JDCT_IFAST; + + // Configure sampling factors. The sampling factor is JPEG subsampling 420 because the + // source format is YUV420. + cinfo->comp_info[0].h_samp_factor = 2; + cinfo->comp_info[0].v_samp_factor = 2; + cinfo->comp_info[1].h_samp_factor = 1; + cinfo->comp_info[1].v_samp_factor = 1; + cinfo->comp_info[2].h_samp_factor = 1; + cinfo->comp_info[2].v_samp_factor = 1; +} + +bool JpegEncoder::compress(jpeg_compress_struct* cinfo, const uint8_t* yuv) { + JSAMPROW y[kCompressBatchSize]; + JSAMPROW cb[kCompressBatchSize / 2]; + JSAMPROW cr[kCompressBatchSize / 2]; + JSAMPARRAY planes[3] {y, cb, cr}; + + size_t y_plane_size = cinfo->image_width * cinfo->image_height; + size_t uv_plane_size = y_plane_size / 4; + uint8_t* y_plane = const_cast(yuv); + uint8_t* u_plane = const_cast(yuv + y_plane_size); + uint8_t* v_plane = const_cast(yuv + y_plane_size + uv_plane_size); + std::unique_ptr empty(new uint8_t[cinfo->image_width]); + memset(empty.get(), 0, cinfo->image_width); + + while (cinfo->next_scanline < cinfo->image_height) { + for (int i = 0; i < kCompressBatchSize; ++i) { + size_t scanline = cinfo->next_scanline + i; + if (scanline < cinfo->image_height) { + y[i] = y_plane + scanline * cinfo->image_width; + } else { + y[i] = empty.get(); + } + } + // cb, cr only have half scanlines + for (int i = 0; i < kCompressBatchSize / 2; ++i) { + size_t scanline = cinfo->next_scanline / 2 + i; + if (scanline < cinfo->image_height / 2) { + int offset = scanline * (cinfo->image_width / 2); + cb[i] = u_plane + offset; + cr[i] = v_plane + offset; + } else { + cb[i] = cr[i] = empty.get(); + } + } + + int processed = jpeg_write_raw_data(cinfo, planes, kCompressBatchSize); + if (processed != kCompressBatchSize) { + ALOGE("Number of processed lines does not equal input lines."); + return false; + } + } + return true; +} + +} // namespace android \ No newline at end of file -- cgit v1.2.3-59-g8ed1b From a4819140bca93820340f21cadc0a911ee10c2568 Mon Sep 17 00:00:00 2001 From: Dichen Zhang Date: Fri, 21 Oct 2022 04:12:30 +0000 Subject: libjpegrecoverymap: add JPEG encoder for single channel image test: jpegencoder_test bug: b/252835416 Change-Id: I6a13438ae4695569058645ad13c1182b7a626524 --- .../include/jpegrecoverymap/jpegencoder.h | 14 +- libs/jpegrecoverymap/jpegencoder.cpp | 80 +- libs/jpegrecoverymap/tests/data/minnie-320x240.y | 1930 ++++++++++++++++++++ libs/jpegrecoverymap/tests/jpegencoder_test.cpp | 17 +- 4 files changed, 2016 insertions(+), 25 deletions(-) create mode 100644 libs/jpegrecoverymap/tests/data/minnie-320x240.y (limited to 'libs/jpegrecoverymap/jpegencoder.cpp') diff --git a/libs/jpegrecoverymap/include/jpegrecoverymap/jpegencoder.h b/libs/jpegrecoverymap/include/jpegrecoverymap/jpegencoder.h index ec1291892d..9641fda24c 100644 --- a/libs/jpegrecoverymap/include/jpegrecoverymap/jpegencoder.h +++ b/libs/jpegrecoverymap/include/jpegrecoverymap/jpegencoder.h @@ -28,7 +28,8 @@ extern "C" { namespace android::recoverymap { /* - * Encapsulates a converter from YUV420Planer to JPEG format. This class is not thread-safe. + * Encapsulates a converter from raw image (YUV420planer or grey-scale) to JPEG format. + * This class is not thread-safe. */ class JpegEncoder { public: @@ -43,7 +44,7 @@ public: * Returns false if errors occur during compression. */ bool compressImage(const void* image, int width, int height, int quality, - const void* iccBuffer, unsigned int iccSize); + const void* iccBuffer, unsigned int iccSize, bool isSingleChannel = false); /* * Returns the compressed JPEG buffer pointer. This method must be called only after calling @@ -67,11 +68,14 @@ private: // Returns false if errors occur. bool encode(const void* inYuv, int width, int height, int jpegQuality, - const void* iccBuffer, unsigned int iccSize); + const void* iccBuffer, unsigned int iccSize, bool isSingleChannel); void setJpegDestination(jpeg_compress_struct* cinfo); - void setJpegCompressStruct(int width, int height, int quality, jpeg_compress_struct* cinfo); + void setJpegCompressStruct(int width, int height, int quality, jpeg_compress_struct* cinfo, + bool isSingleChannel); // Returns false if errors occur. - bool compress(jpeg_compress_struct* cinfo, const uint8_t* yuv); + bool compress(jpeg_compress_struct* cinfo, const uint8_t* image, bool isSingleChannel); + bool compressYuv(jpeg_compress_struct* cinfo, const uint8_t* yuv); + bool compressSingleChannel(jpeg_compress_struct* cinfo, const uint8_t* image); // The block size for encoded jpeg image buffer. static const int kBlockSize = 16384; diff --git a/libs/jpegrecoverymap/jpegencoder.cpp b/libs/jpegrecoverymap/jpegencoder.cpp index b5d3a063ca..d45d9b33c9 100644 --- a/libs/jpegrecoverymap/jpegencoder.cpp +++ b/libs/jpegrecoverymap/jpegencoder.cpp @@ -36,14 +36,15 @@ JpegEncoder::~JpegEncoder() { } bool JpegEncoder::compressImage(const void* image, int width, int height, int quality, - const void* iccBuffer, unsigned int iccSize) { + const void* iccBuffer, unsigned int iccSize, + bool isSingleChannel) { if (width % 8 != 0 || height % 2 != 0) { ALOGE("Image size can not be handled: %dx%d", width, height); return false; } mResultBuffer.clear(); - if (!encode(image, width, height, quality, iccBuffer, iccSize)) { + if (!encode(image, width, height, quality, iccBuffer, iccSize, isSingleChannel)) { return false; } ALOGI("Compressed JPEG: %d[%dx%d] -> %zu bytes", @@ -91,8 +92,8 @@ void JpegEncoder::outputErrorMessage(j_common_ptr cinfo) { ALOGE("%s\n", buffer); } -bool JpegEncoder::encode(const void* inYuv, int width, int height, int jpegQuality, - const void* iccBuffer, unsigned int iccSize) { +bool JpegEncoder::encode(const void* image, int width, int height, int jpegQuality, + const void* iccBuffer, unsigned int iccSize, bool isSingleChannel) { jpeg_compress_struct cinfo; jpeg_error_mgr jerr; @@ -102,14 +103,14 @@ bool JpegEncoder::encode(const void* inYuv, int width, int height, int jpegQuali jpeg_create_compress(&cinfo); setJpegDestination(&cinfo); - setJpegCompressStruct(width, height, jpegQuality, &cinfo); + setJpegCompressStruct(width, height, jpegQuality, &cinfo, isSingleChannel); jpeg_start_compress(&cinfo, TRUE); if (iccBuffer != nullptr && iccSize > 0) { jpeg_write_marker(&cinfo, JPEG_APP0 + 2, static_cast(iccBuffer), iccSize); } - if (!compress(&cinfo, static_cast(inYuv))) { + if (!compress(&cinfo, static_cast(image), isSingleChannel)) { return false; } jpeg_finish_compress(&cinfo); @@ -128,29 +129,44 @@ void JpegEncoder::setJpegDestination(jpeg_compress_struct* cinfo) { } void JpegEncoder::setJpegCompressStruct(int width, int height, int quality, - jpeg_compress_struct* cinfo) { + jpeg_compress_struct* cinfo, bool isSingleChannel) { cinfo->image_width = width; cinfo->image_height = height; - cinfo->input_components = 3; - cinfo->in_color_space = JCS_YCbCr; + if (isSingleChannel) { + cinfo->input_components = 1; + cinfo->in_color_space = JCS_GRAYSCALE; + } else { + cinfo->input_components = 3; + cinfo->in_color_space = JCS_YCbCr; + } jpeg_set_defaults(cinfo); jpeg_set_quality(cinfo, quality, TRUE); - jpeg_set_colorspace(cinfo, JCS_YCbCr); + jpeg_set_colorspace(cinfo, isSingleChannel ? JCS_GRAYSCALE : JCS_YCbCr); cinfo->raw_data_in = TRUE; cinfo->dct_method = JDCT_IFAST; - // Configure sampling factors. The sampling factor is JPEG subsampling 420 because the - // source format is YUV420. - cinfo->comp_info[0].h_samp_factor = 2; - cinfo->comp_info[0].v_samp_factor = 2; - cinfo->comp_info[1].h_samp_factor = 1; - cinfo->comp_info[1].v_samp_factor = 1; - cinfo->comp_info[2].h_samp_factor = 1; - cinfo->comp_info[2].v_samp_factor = 1; + if (!isSingleChannel) { + // Configure sampling factors. The sampling factor is JPEG subsampling 420 because the + // source format is YUV420. + cinfo->comp_info[0].h_samp_factor = 2; + cinfo->comp_info[0].v_samp_factor = 2; + cinfo->comp_info[1].h_samp_factor = 1; + cinfo->comp_info[1].v_samp_factor = 1; + cinfo->comp_info[2].h_samp_factor = 1; + cinfo->comp_info[2].v_samp_factor = 1; + } } -bool JpegEncoder::compress(jpeg_compress_struct* cinfo, const uint8_t* yuv) { +bool JpegEncoder::compress( + jpeg_compress_struct* cinfo, const uint8_t* image, bool isSingleChannel) { + if (isSingleChannel) { + return compressSingleChannel(cinfo, image); + } + return compressYuv(cinfo, image); +} + +bool JpegEncoder::compressYuv(jpeg_compress_struct* cinfo, const uint8_t* yuv) { JSAMPROW y[kCompressBatchSize]; JSAMPROW cb[kCompressBatchSize / 2]; JSAMPROW cr[kCompressBatchSize / 2]; @@ -194,4 +210,30 @@ bool JpegEncoder::compress(jpeg_compress_struct* cinfo, const uint8_t* yuv) { return true; } +bool JpegEncoder::compressSingleChannel(jpeg_compress_struct* cinfo, const uint8_t* image) { + JSAMPROW y[kCompressBatchSize]; + JSAMPARRAY planes[1] {y}; + + uint8_t* y_plane = const_cast(image); + std::unique_ptr empty(new uint8_t[cinfo->image_width]); + memset(empty.get(), 0, cinfo->image_width); + + while (cinfo->next_scanline < cinfo->image_height) { + for (int i = 0; i < kCompressBatchSize; ++i) { + size_t scanline = cinfo->next_scanline + i; + if (scanline < cinfo->image_height) { + y[i] = y_plane + scanline * cinfo->image_width; + } else { + y[i] = empty.get(); + } + } + int processed = jpeg_write_raw_data(cinfo, planes, kCompressBatchSize); + if (processed != kCompressBatchSize / 2) { + ALOGE("Number of processed lines does not equal input lines."); + return false; + } + } + return true; +} + } // namespace android \ No newline at end of file diff --git a/libs/jpegrecoverymap/tests/data/minnie-320x240.y b/libs/jpegrecoverymap/tests/data/minnie-320x240.y new file mode 100644 index 0000000000..f9d8371c18 --- /dev/null +++ b/libs/jpegrecoverymap/tests/data/minnie-320x240.y @@ -0,0 +1,1930 @@ +}vrswqnpsqqklspmjmnlknw{žW9¿¼f96999:7464336753/01,..2344NĽw:½r'Rouwwvzy{zxyzyxtsvurkgce_F UOº@:;:¾~o¿5M}>I1ÿ5TT1sF)sĿ¼2ZHeP@&-Hh»0b_gA8$A,&6Wÿ/l?S_8z06}V5$.Yž0xvXzvT^,C_;.2Mu2qW'LjI93Cj¼3$WmR.Tÿ5x ^iX/¾¿s2G#Lt gi1to0þɺ¾j.B!)#Jn"rzOXwZ;µb/M'()%dj"}Elw?`½ÿȺ^4u%&&'&/e'IEzXy|5ļ[9B%)'&'++y^-dmg@}PJÿĸƿX>9,+)))0.vY2q8}ʺQBZ04*+57FT6lAþξLIme=1bmO8}ICXVʿ}|7W|zGJ;¿º{|~5cEPoE¾Ŀ¹~zz|}6pAWDl{ȼyyy{|~2ym}<^8½ʽ{yz{z~|.|Rowc;c]Z}yyyxyw.iPsB7fĨA|yyxvsz/d_2hpRýĽ~{yxrlx.Qa~0l°Eÿ¾{yxwx~|vvtlv-_@+rzLÿ{wtstwvwvtrojq-t,~Itľ}ytrrrrqoqpmifm.W2Ŗ:þ¿}}vtrppnkkmkihch{T'BWcltzRImL¿}~~|zxuromkjihggeaev~eD;7630*0348;XdZ¿}|{{zurplkifde`XQVlw}nO::GdƯE}z{zxuromlgdaa]XRPgv{wP;2;X{{H||xwuroojfca`\XQK^sx}bJ:?:Һl>VIFHLMKMLOT]ds|{}z{}~ztqppqrrsvuxxz~s_RQaq~ц;C>>>ʕE-:<=9Qi'..4>IVfsɗ/*'&(&'$"!!6a!9q|xxz{}~~ytpopppqrsttvwwx{}}~vfVO[nw:DA?@үc.3<=?:hc243310.--/1/1552215Ɉ140.,*(''&#""!!  9Z " E~|ywxyy{}{uqmlmmmnooppopqsrsvvrutqqqrrnnj_UKTlk;B@=C˄80:=>9B^43225689:9877778:<@~.1/+*)'%$#!"! "! @N!#$%-|zzwuuvxy{xsmjiiiiikjllijjjijljhggfeeecb]WMIMe{[DC@9Iγc.4=@<9VU.123242024467:9797=s.1-*%*71/.,)(#" HC(%#"!%$&($.~_~zyxurstwwxtlifeecccedbcc`b``ac``_^^\ZYXTPF@I_xʽL<@@8SȔD3::;:;tK034.Byl\TJ:788669Zi10++&v{tmffdx@(x~vY3"$(*-&Ayuuu4^}{zwtqpqsutmifa`^^][XY[WVTWWWXYXYWUSQOMID;34]wȳ@48:6U¾s24<881DB256/_b)-+++47Q&*,,.'{ytrtv}@5`|{vwurooqrtqifc`^\XVURQPMNOOPRRPPOLKID@7,!T}ĩ93540OV-68760Só?3451jȿ_,.,(),=P(..0,O{sqnnpuzD@<^~~{xwutppprrqoida][YVSPPMHFECDIHHGEB@:0!P|-./.(LA&53350dú>4352nƿX++)&*'F6,/12<{qnnlmmptx{DCA8f||{zutsqnnnmnnjf`][XVRQMKHD>;99<=:3+' Hyƿ%)'()+."-.-,1l84493qĽQ%'%#'#MQ*//34}tllmjmmptsuxBCA;=jxwyvtrromllljjhb]ZXUSPMJGB;7542( D|ſ!&%%%$%))++.y53242tȾM%&#"%w\_(1263ýurkijkloqqtstx}||CCC@7?kuvxurqnlkkjjlhc^ZWTRPMIE@<851( =|ýp!!!!"$%&&%T/100.RH"$ #m eY/0588tolkiiklnqrsusx~tpqCBCA=8>outtrqmmlijhiheaZURRQMID>975(  8x}h#  ""$$3*--,,'(1>LauE#!FTSYYZ`dagigkpc " pA6346F{vqnkihhkmnqrqtv{wpor|AA@@>=5Bqrrtqnmkifffffc]WSROMHB=74* 0r|`5 !";t$,+)*+(('&$'/028:;5? @_ "&"zl59573tĿ|trqmlighmlnpqruwz}ytomrx~@@@?<=;1Jpprqnmkifcacca`[UUPMFB<9+ 3m|}}}||~~QeTMe))(*+,+,./25446872>D^##&$~/9875=zupljifehkkmooqtwz}~}yslknv|???>=:75,Nnqppmjgedaa_]^[XQNHB@8$ +  )jx~~|xwz||}|{z{{{z|}~{z{z{|~Io2jU%%'$)'%'+,.02147858 G\#&%(&j/7;:82ǽytpmhfeeeilmnpswz~}}|zvvnikrx~~w?>>=<:85/)Kpllkihfcb_][ZXUOIE@. + %ct{|{zxuwxzywyxvwxwwxxuttuwx||{}Cq~ xF!"#)~veTJB:9657670KV$&&)#^zs[:+49=<1xƽvqmlifdcehkmnsy}yxvvtpghmrx||{w?==;;8641-*Gjkgffdcc_]YVRLLE, + + %_ry}{zyxvwxwvuvvttttttqorsstwwwww{~:mg&7!! 2+*UTTQONKIHIIKJrN$''))&))%(*/34:6:}spmkidcdfiilqz}wuusrqkchoqv|xw><;;:54411/):_gfb`ab_ZUMKI:!  + Wrw}|yzzvwvuutvtssrsrqompqptutwwvwy6nJ6.7%CL$((*,-020234213P~vtpnhcbegklqwxvtqonlhdhnow{ww><::85434311,1Oa^\\ZVPNL7 + + Lqx|{{ywwvtuutttrqsrrpooqprrqssttx|6o~|}4G%:w JM&++-/-+.,-1/?b}|ysnidbdhmu{yuuspolhdefimwwuw<;9877655331/.)?ORRQLIA"   + LVasmtxslfcaensy{tpqonkecfghio|xwz;::877442320.--3?A@EG5 + *p{~~}{wvtqrrqrnqqqpnmnoppponpqruxz~/"u~{fpt>a]Q-16;<¿aanmjeabhmu|{tqoomlhb`cgiijuzwz97788842310/,0;A@;8=4   + $c{~}{xwurqsspnoooonnmnoooppqruuwz}})!w{Y(~~jD~~}~UeQ2369Hÿ}}|}}}|zzzz{z|}|~bYdhecabgkx|upnnmmjd__cfhhjmr|}ww5676665332/,1BGDA:90  + _}~}|{zwutttpopnoopqpprrsuvxwxy{{}v%&w~~{yG=~||z~_H|}}{||yxxz||}KsJ1344Jÿ~|zzzxwvxywvwvuuvtvyz{y{~~~}}~~}`[`fccbcglw|wsoonlke_^`ceggjkmszzxz}578645542219EIGB>?:   + + Ly~|{xvuusurqqqpqrqrtuy{~}{m )z}{{|}}~~4Mzzx}S.RV[bdhopsvv{~|~E"I5693Mÿ}|zxwvwvttutvtrrsrsqppqsuvxyyz|~~~~}zzyz}{`[`baabehox~|xsnmlkhb^]beggeffimx}yw|7865533414BJIGE@<@  + :x~}}{zwxwuvuurrrqrru{}yui"({zzy{|||v&^xv{M#(+06:R~=`twzH7776X|{yvuttrrrqsttrqqpqooooooqrsuvuvxyx||||||~~|{zvvvvz|x`[___`bcis|ztnmjigc^\`dfeggbglp{}}{vy77534322>JPJIFD>2   + + .w~zyz|}}}}}||yxwwvrrtvz|wro_PJE>Gwxzy{yzxx|dl{rwF/5!$&)+.1147õF7887hý|ywwwtrsrsrqprrqponllmmopnopprsrrstuuwyxxxyyzxwvtuvuwzv]Z[]_`delu}|tojkhie]Z\bdgffhfms{~|{{vv|7553229JVTPJHE:/!  + *f|xxwz||~}~{zyzyvy|~ytoqsx{{wvwx{{|}|{zV#&pvyB50"""%'(*+,//15ǮB:;<7rÿ}zwvutssrrqrrqqpomlkjiklmmnmmooppppprrsttvusstuvuuututuwoZYZ^aceinv}|vqniigfa[[aeejhhimu||}|zvz52123ASWTSKE<70,! + + + "[y~zwtrswwyz|{{{yz|wtrqprtsstuyz|}~}}|sjbXOI;[ww@A~. ""#&')*-/2359ǟ76530ľ|yvutttrrrqqqppoomkjihhhghijijlmmmnopoqrqppqssrsrttstrsssukVW]`efimsyyrnlgghe\Y\aefjkjnt|~{zvx31/-3AA?A=75320/#  + + + + U{{wrrqrrstyz}~~~{|~}zyyvuttuuuvz|||~}|}}}|x{}|{xxoaZSKD<62,)$#I) "!#%')*+-33/<ƛS\bvþ~zvuttsrqppqppoommljhhghhfdghfggijllmmnnmnpqppqqrrpqrpqqrpqtqbadfhjnty}wojigge^XY]cfjjlpsy}yut{1.,./.,.43334422' + + + + + Lyxwtqpqrssty|~{zz}~{zzzzy{zz|{{|zzz{}|z{zyzywxxwspnlhcYTQl?2.2300.1656;@FGNSZvþ|xvsrrqopooopoollklljjijmlifiigeffiklllmmnlnpomnopomoqponnnprqighjiovxqlihge`YX]cfijjmsw~zvqs.,+-.-/043566753   + + + + + + + + Euttsrsssstux{zxyz}~~|{xyz||~}~¾~yvtsrponmmmnonoomklnnnoorvurpmjihhfegjjilloonoononnmmlopnmlmmqpkijkox{tnieeb`XV[_dghkmqwzwurx,+,./00224677742  + + + + + + + :wwvvuvttuvwxy~yutux{}~¾~{xtqrrponnlmnnnmoomnopprsux{yxvrqonkigfgigiklnnonnolllkkklllkmnpoljkqzzslhfccaZTW^dfhikqv{zvssu}+++-/00344455762   + + + + + + + 1s{}}}|zxvvwwvz~usqqqty|ž~zwutrqpqpnnnnonooopppqqsstwxz|{{zywvutppjhhhjklmmmlmnljkkjjjjkijnrplov{|rjgedb_]USX^cegimsxxurrx)**,-./11214112*  + + + + + + + + +n|zzzzy~}vurqqsuw|¼~yywuspnonnnmnnnoprrrrsttuuxyz{}}}}}}{|{zxunkjkkmnkllmmlljlkjihhhikmqnov~yrleddb`\VTV\bdfilot|}wsot|&''(())(''''%$#   + + + + + + + + "k|~}}|yustsqsx}ý}zxvvspnmmmmlmnpqqstrrstvwwyz{||}}}||}}|{xqmlkmmklkllmlkjjjiighfghiojju{qjd^``^_ZRVZadefkkox~}xvqqy!! # ! !!"!   + + + + + + + + ]~}|{xusutsy{yxvtrpnllkjlnppqrsuvuwvwxz{{{|}~}~~}~}}}||ytqnnljkljljkjjjjhigfggfgjjYU_ijhfg`a^\Z]]ZTRX\`ccdgmpw}|xtrorz"""" !!##"#"!    + + + + + + + + N~xwvyz~mWMJJP_½þ|xvutrqonlloqqssrqstvwz{{{|}~~}~~~~}~}|||xurppnlllkkjjjihihffdeeeicMJKSSTWYXY[[[[ZUQTX]bdeehlqx~}xurnpv !!"""!"   + + + + + j{xxz|{|~~~~~}}}||||zywvtrollkkjhghgeaababgM=BFIKNOQVYXYXWQOQVZ^`bdgkotyyuopqot + + + + + + + + + + + + `ĚB'1524:95457;96784.Qїqc&*),+Mxstrqppont[f|ywxz{|}~}{{||}~~{zzxusrqnllkjhgfccaaac=3V16697Po0240K//qrqqqqpoyHi|||}~~}~}zxxwvurrrpopmlhdd>.379>DFJLNQSSPLOSUZ^^]_dghnsspnoprv|   + + + + + + + + + + + + +  `z-58::0Nǯf59;;:.P{+633576ž\49:4e¿t!-oqqrrsqsck~|{{zyxuxxvwuturp]/+18;;ADGJMPRQMKQTZ]]^]`dginropootv{|   + + + + + + + + + + + + + + + Rъ-4696/sÅ79<1MƢ//10114.kŻH6885~`,npqqrsrw1n|~|}|{{{|}|{zyws3%+-3:;?BEHMQRPJJPUY]^_`acdinmlmoswz   + + + + + + + + + =yͱ707<71¾ȉ32aH&0/0001/?˫:9874B#kpprspyRt~~~~}||U#*,7;?ADFKPOKIJOUY\]_``ceiljklov~  + + + + + + + + + + + + 'js+:<=2ƾn!--../1241ϔ4:889|zy.eqrrrshv~|r# + !(,7AGJJJIHJMPUXYZ[\_abeknt~    + + + + + +  + + + + + + + + + + + 0u-+052E(0./+::279:9a3979E~zxu|ADtsrxZ)|j "(+/9?CHIHFGHLNRUXY[\]^_ajr~  + + + + + + + + + + + + + + + + e%(),2½s$/0/01x-;8;6oS4765F|yxutn"$%prwo"*.: &).4BBCDEFFGGIMRRSVUVWX\`_cfhlnoonnsyxy{ + + + + + +  + + + + + + + + + + + + + + + + + + +  f~~~~\ȣ00113+Im08552lŇ+,(%!A~|wwxvuutsv1f|}/yM\_ + +  (07>AAEGDGHFGJMPPQSTUVXY[_acedgihkmquw~ + + + + +   + + + + + + + + + + + + + + + + + + + Nz~~~!FȿN,300/7Ż13223Cx%&" E|yxvuuvutttr)phOHd#  + + &/8?BBFJFEJHGILOOOPQTVXXYZ\^^acdhjnr}  +   + + + + + + +  + + + + + + It~}~Z]Ūl-630.,ξM-3251l!% N~|xutuuuuttui"%zA&F ! kJ  + + + + $-8?EGIKJFGIIIHLMLLPRSVXWWY]^`bflt  + +    + + + + + + + + + + + + Tk|~}}6b~?v̏19632/.[̀,5460^¿a !V}{xvuuuuvvuwc*}"dM!!"lk + + + + + +,7HGFHJKIGIIIGIIIJLOOTUUVY^`cnt  +  +    + + + + + + + + + + + + + + agm}~y$G_/83ɾű?56651--&$,>Qit{m364459S_}{yyzyvwvvxzy|[/V  1U!$o* + + + +/HKFHJJKKKIKIGHJKNPSSVZ_cgls  + +    + + + + + + + + + + + + $hfg{k.gl9'5997b287670+*+)*-*+-.0076446,tºBk{wwyyyyzzz{}W02#$s] #$kF + + + + + + 3HFIJJKNQQNPRPRTWX^`adjnruz|~|~     + + + + + + + + + + + + + + 'kda{}{c'E\a[C+ )12482Oć3989:3.%#&'+.232367754351D7$xyxxzzz|~~` 1v'$=`"%$bm  + + + +6@DCCGMQWWWYYXX\_adceikmoqrtttvx|} + +    + + + + + + + + + + + + + + + ,nf_o{z`!&(,03.<=79:=6K`='$(./1466242256*,3yvxy{~k"#%3J%$ul$(%\( + + + +  +4;;:>EGMSTWTUTVXZ]`cegfijklqswwy|  + + +  + + + + +  + + + + + 4rj]cy}||s0 #%)+&Jĺ_.;;<:7żvVGC?<>BD91541)I"E}wz{|o#%%(/-388;4ZN*-*(Lp h*++,*0))$:@  + + + + + + + + + + + + ,2269:<@DIMPSTRVW[^bfimqvy  + +   + + + + + + + + + +  + + + + + + + Gvm_]aoxP/ ,Gzx4;864<Ă#)($ %b #j1.-.+~6)*)5w* + + + + + + + + +/48;>BBFLPRUWWY[`dhmty~t  + + +   + + + + + + + + + Rwp`\af{ztt}Ŀ/$$ XT $d5,-,-s<(++.þc' + + + + + + + + + + + + 6:{l_cccedgz½nadgioo` + + + + + + +     $&&$&(&)*(G  + + + + + + + + + + + + + + + + A~o`bcgihgocbehlrmb" + + + + + +  +  +  +  #&$$'&&())J   + + + + + + + + + + + + + + + + K~saachkkkkvÿjcfikmund# + + + + + +  + + + + + + + +  "#%$%'(''()J   + + + + + + + + + + + + + Tva^chjlmklxOHu¿thfiikntmf$ + + + + + + + + + !!"$$$'&&()(D  + + + + + + + + + + + + ^|b`cfklllgoe ,,ž~hlɽrɭjhfdbgr¿qiikjkqtlh+ + + + + + + +  +    "#$%%$#'&&E  + + + + + + + djbeghllmjjx*%,)\Ŀ\)//}ɼE.M̫312:>;5.6^¿xmjkkknuvml/ + + + + + + + + + + + +  + + +  !"#$$$%&&&(C  + + + + + + + + + + + + kodfgikklkjp}a%$**y076,n]6?ȻH6Gb-3vqlilklqwxnk1 + + + + + + + + + + + +  +  +"#$#$%&&((? + + + + + + + + oqcceggijjiiu/!&!Lč2622,kn36[1AΒ8+e{mllnlnt{|pp5 + + + + + + + + + + + + + + +  #$##$%$'('B  + + + + + uvbccddfggigk~j.r!-1RR10lˇ23o25А6.sonnnlou}|ot= + + + + + + + + + + + + +  +  !!"#&%%$&}}: + + + + + + + !{ecc`adffeeiu7XEA)+^<4-xϖ32qɆ03Y1E¿}npoonmpy{qx? + + + + + + + + + + + + + + + +   "#$%%%&&~~|}4  + + + + + + + + %{hcc_`ccdeegk|t!w}((RÑ/4,72_Ɯ56is44soqrrpnr}szE + + + + + + + + + +   "$%$$$$$~}z|8   + + + &|hcba`abcdfgem|EOE>%#Ir'-1|;2N?7Pb21¾lpssrppv|v|P + + + + + + + + + + + + + + + + +!#$$$%&%~~|}|{yz= + + + + + + + 'kcbb`_``cefednazvtYlv;B %%*,roqsrqpr|}zZ + + + + + + + + + + + + + + + + +  !!"%%&'%~|{zz|{xz? + + + + + + +  +ofdb``abbdefghwD*|y~m-# ##%1E-.0-&c~vmortrqqu}~d + + + + + + + +  + +  "%%%&'}}|z{{zwv< + + + + + + + + 2thfdba`abdefhej~pKyte*c#=^sfT80{{}qnprsrqsx{g + + + + +  + +   #$$&&'}}~|{z{xywuC + + + + + +  2{jjhda__abfehhfr{|{vxzussrxB$T[]\]^^L!Zja nsrsx?]rx1">gonsz{~}{|z{tmorssrru|}d + + + + +  + + !###'('}}~}|zxwuusuE + + + + 2{mllgcb`abachiho|{yyywvtttrrqoolkje<59[kiiffffj]EC@\e@9:_iihhkI+*)Vfg?,1449AIS_hegjmqru{|y{z|~{yz|}~|mnpttssrvh + + + + + + +  + + + !##$')){|}|{yxturquP + + + + + + + 7qqnleb_abcceikio¾zvtutsrqrqnmmkhgea^]``^]^[^]^``aaa`^^_`cadeddcfcbb```_^`baaaababdfiknoqtutuuwzzz~|zz|~smpqtuussyo + + + + + + + +  +  #$$&(+|zy{ywttssorR +  + + + + + + + + + + 9vtumhea`bdcehjhiy¿}wrrsqoponjijffggecdddefecddefgeddcbdcddcdedccabb````^^]^`^^_aaddeilmoopqqruwy{}~{|}}~lnpsstuuvu  + +   +!#%%'+{{z}vvtssrpmI  + + + + + + >zuwrnhdabdcehiihm{wvrppommlnmmmoononnmmopmlmnmjjjhfghhhhghifefeddedbab```a`bccdfdejnpomoprsw{}~~}|~omprtutuvyx + + + + + + + + + +   +0!$%&&+yyzyuvssqpnnP  + + + + + B}u{yrmgcbcdegjjlku|zwttrtvwxwwvvwvvuvtrqsrqpqqpponmmmnlmkjjikihghhgfddcccdcdeefghjmoponqsw{~|}}zkoqstuuuv~y + + + + + + + +  * "#&&)+wxwvttrrollkW + + + +  Juz{uqleabcdfijkkm{½~|{yzxwxwuuttttrrrssrqnmmonmlllkihhhhiiikikmnpqsusrvz~|qmosutuvvzz + + + + + & "#&()+-ywttrrronlkhb + + +  Nvw|yuqkcbccegikkkrĿ~}}|zzz{|zwvuvuvvuqsqqppnpqosttwy{}{~tnoptvvwxw|{ + + + + + + + + + +  !' #&*)*+/ttrsrpmllkjfd + + +   Pxx~|ysngabbdghjlmox~~~~|}lnqswvwyzz + + + + + + +  #'#&*,-.13trsqonljjihec + + + +   N}v|~zwqkdaccdgjkkmr}||}~tmoquwuvyz  + + + +$&!'*-.035sqrpmlkhhgddd + + + + + +  Mx|~~{umhbcbefijjlpv¿~~|}~ynopsvwwwy| + + + + + + + + +  &&"$+/0246pnqmmkffffcac( + + + + + + + +   My|~{tneabdfgjjkou{½~}nmpsvywvy|~ + + + + + + + + +  +)(#!#(/4567mmlhkjgeddcb`3  + + + + + +    Szy}xslb`bdfgjlnqv~RA=;;<;98<7476=K\~X?320,.39Kp~}tmmpuxywv{z + + + + + +  +((&!#*46889jliihhfccc`\[9 + + +   W~w{tpgba`cgijnoru}¿?9:99::8;:6779;;5.@zƿf:+01/430111,*7V}lnptwzxxyw + + + + + + +  +%)'"!!%17::aa`_]^]WVVSRPJ + + + +  c}}zunfa^^aejlloru{+)))$PpJ.(10/311øŸ?0111/00),044.++2530...(k{opqtw{{{z}j  + + + 3M3$$"%%%,38:___\[XXSSUQPLE + + +  c~}xslea_``ehjloqv{'&$%qK&-,..1;¥=23/11,);]mG--0,,.,"qsoqswz|{{|f + + + + + + + + + + + + +#(1G2$%!$%'-138]\[XWVTRQPMLHB + + + + +  e~|uphebb`bfhjlnsu{ÿ#$#$ pc'-,--'YL010.0++kô:&,)&##$vopquy||||^ + + + + + + + + + + + + &)*-@/!#"$%+115ZXVRRSROMLHDEB! + + +  jxsmhfdcbahikmqruy¾#$#%#t]'.+,+-q,/-,.(5īP"&!"?¿|ooruxz|{|~W + + + + + + + + + + &())/A,"$!%%)034VSQONOLJIIFEC? + + + + +  f~wpmifcbaaeimoostz$&#$#p>'++,&]4**)+(5Lz¾rmoswy}}||S  + + + +  + + + ((()(+7*$ $%'/43SSOMLKLIFEDC?=& +  k|vrkeddcaafklnqru}$%$%$q'-+,*7j#)(')&1Pspoqvy{~~|~}N  + + + + +  ))()))+1*"!"'/35QOMJJFGECAAA><. + +  p|wqiggfbbbeimpqsuz¼$%$%#t;++*+*@"&&&!Xg4¿voprux{}~~||E  + + + + + + *)(()((*3*#!#-44MIGGHED@?@?=>:/ + + + +  r{vojggeda`fhlnorsy~~¿$&&(%wZ$))+&m+&$$$+''Ŀuonqtwy}~~}~=  + + + + + #)()(()))*/-" ".33GFFDBAA?>>=<;73 + + + + +    sztnihhfcbbegjmqsuv|¿%()*'~n())+'^~$'#%$G;'|wnmptx{}~}}; + + + + + + + #')(((*((''2- '/2GCAA?;<<=;<;876 + + + +     syrmjihgebcejmprruz|¿(-+,+z&)')'Uj $#%!_G%}ÿ|tkortx{~~~~~4  + + + + + + $(('(')('''(0-$,/DB>=<988987875/ + + + + + + +   o~wrnkjihfdegimppruxz{ʼn-/+-.%)&(%MW!"% oI+}ummptw{~~~|, + + +  + + + + + &('''%&&&'''(/+(,A?<<;999844543- + + + + + {{upnllkjhgfgkmpqqtvxz|-210/s%&$&#PP #"E3ulmrtv{}~{' + + + + + + + + +(''&&'&&'&$%&%/0%*<>>=9866543420/ + + +    0ztollllljgghknqqrtuwyzo59:7:Z!$#% ZQ!x=?yrmpuwx|~"  + + + + + (''''&&&&&%%%$&+-$'::::754420//.-) + + + + + + + +   T~ytommmnmkhiilpqrsttvxy~_89>=H?$$"$iZd(Wzrnpuxx||  + + + + + + + + !('&'''&%%%%%%$$$-0$776753210.-,++* + +  {}xsppnmnolkkknprsstuusuz¼O:9TgtthR4-42.00.:"fmi'axw~y- + + + + + + + + +  33-,,,++*+*+*)*)))++**)(()&((&' + + +  + + +  =Ľ|wsonpruvx+,F=) %*/3̨F4/..-.129ǂF523/*3./3Al Hw!!F  + ##$##%,,,/0.164.-,+********++*)))**(''((+.0/4956:758;89=@9:;7 B½{x(/rrkW}{y%/3$&%'%c1,.,14ƾŏ21,+0Tz$<%d¾f + + + +$##$$&-/.11-/172-*-+*****,*)()*))***''(),1-.11011345578<<==<5 V~}/'suyM#r}|}**b  1S&*(+*_}**)(*]s`b_[USKC<81`)0,:JVz, + + %$$%%)-0/00-,-26.+,,**+**)**(**)))))'(,+-../00//3355565799:95 + v3"mzvu)E0*,Xs$#'&5r%%%#$TC!Q/(@ fw'$RQ + + + &$$%&*///0/-,,-45,++++++++**)))()*)*'&3/000.10038766777596987! &2!o~{}\f3+\$|* #jm""C> T4!}_ '~1"'$Dr + + "&$$&(,//0/.--,-.72++++)*(*))))))))**((6324301128;667:88:=8:9:( + =8"s~321*25Q2o/7_: y'#.~='&(&~û5 %''&&),...-----,,091,,.,*)**())))()++**<8798549<9:6::<<=AB?@A@7 +  f:!xa^0(d(6@JOT[`cIhz]1_7 vK! )q>&%&%9[ ((*))+,///.-,-.-,,27.,,-,++*)))))()**)*<<=>AB@CEEFEHHGO + 44&}>&#y6-}.,{H.--/-$f3"{+ FrxZ&#"$$²y  ()*+,......--,-..-.22,,,+-+****)*)()(();<DFEEFKLLJMNNOKNLMILR]C  .tH'-~k?#x{{zkJtn+&b ""!!"#Tk + *()((&).0/.-././12:82270,++++++++*))*+**BBFIJJKKNOQLNOOPNOMLOQPSD \}{"`r!'M}zx|OG\!ut#+V!""$#f¼. #*((('(*.0//..////0638Kd¾½Y2/+-.++.00.//00/-./1420/...,+,/43.+****+-,SQRSRQPWWWRQQTVUSRTUWVSUTTW9 + Pȿʸ¿ýq4.,--*).///0/.//../07600.-..,+-/44,)**+++*[Y]ZT[[^eaZ]YX[YW\XXXW[XYVSGȺ˻ľE20,)++.0/./../../.0CÿM00.,,00//.-,-./-+,-/0372..--,*,-051-)***PRRWPPRSSTX[RPSRSQROLNPRQPPPNʹƲ¿ýg/31,,11//0/-,...-,,..132/.--+,,-,/3.+**)TXSTQQSTWVVXPNRTTQSSPNOPNOQNT0 CŵȶĿ¿~3*1+,/.////.-,-/-----./01-,,--,,+.030*'-UXSRSRWXZVVXPOQSTRPQRQQOOQPPY@ }Ųʺ~žF"//-.00.-..,-./.-,+-/02/,+,*+,,./47.+,TSQQSVTRWSUUPPPQPONPQSSSTUSTYM.˼}}~_.,,-/.----,--.-,++,.00,*++*,,,,/42-+RPMRUSPQSTSRSPPONRSOPQRQRTQQQS)eʼͿ}|}}~ü¿v$,-,../...,,,-..-*+-/.++**,-,+++.4/+SPQUTRVVSSTSTQQRQSQOQNQOQROOOQ=(ƹ«~~û=).////0..----+++,-.,*,,*,,*,,*,44- \ No newline at end of file diff --git a/libs/jpegrecoverymap/tests/jpegencoder_test.cpp b/libs/jpegrecoverymap/tests/jpegencoder_test.cpp index 2d144f07a9..4cd2a5ef8c 100644 --- a/libs/jpegrecoverymap/tests/jpegencoder_test.cpp +++ b/libs/jpegrecoverymap/tests/jpegencoder_test.cpp @@ -25,6 +25,9 @@ namespace android::recoverymap { #define VALID_IMAGE "/sdcard/Documents/minnie-320x240.yu12" #define VALID_IMAGE_WIDTH 320 #define VALID_IMAGE_HEIGHT 240 +#define SINGLE_CHANNEL_IMAGE "/sdcard/Documents/minnie-320x240.y" +#define SINGLE_CHANNEL_IMAGE_WIDTH VALID_IMAGE_WIDTH +#define SINGLE_CHANNEL_IMAGE_HEIGHT VALID_IMAGE_HEIGHT #define INVALID_SIZE_IMAGE "/sdcard/Documents/minnie-318x240.yu12" #define INVALID_SIZE_IMAGE_WIDTH 318 #define INVALID_SIZE_IMAGE_HEIGHT 240 @@ -43,7 +46,7 @@ protected: virtual void SetUp(); virtual void TearDown(); - Image mValidImage, mInvalidSizeImage; + Image mValidImage, mInvalidSizeImage, mSingleChannelImage; }; JpegEncoderTest::JpegEncoderTest() {} @@ -89,6 +92,11 @@ void JpegEncoderTest::SetUp() { } mInvalidSizeImage.width = INVALID_SIZE_IMAGE_WIDTH; mInvalidSizeImage.height = INVALID_SIZE_IMAGE_HEIGHT; + if (!loadFile(SINGLE_CHANNEL_IMAGE, &mSingleChannelImage)) { + FAIL() << "Load file " << SINGLE_CHANNEL_IMAGE << " failed"; + } + mSingleChannelImage.width = SINGLE_CHANNEL_IMAGE_WIDTH; + mSingleChannelImage.height = SINGLE_CHANNEL_IMAGE_HEIGHT; } void JpegEncoderTest::TearDown() {} @@ -106,5 +114,12 @@ TEST_F(JpegEncoderTest, invalidSizeImage) { mInvalidSizeImage.height, JPEG_QUALITY, NULL, 0)); } +TEST_F(JpegEncoderTest, singleChannelImage) { + JpegEncoder encoder; + EXPECT_TRUE(encoder.compressImage(mSingleChannelImage.buffer.get(), mSingleChannelImage.width, + mSingleChannelImage.height, JPEG_QUALITY, NULL, 0, true)); + ASSERT_GT(encoder.getCompressedImageSize(), static_cast(0)); +} + } -- cgit v1.2.3-59-g8ed1b