summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Dichen Zhang <dichenzhang@google.com> 2022-10-21 04:12:30 +0000
committer Dichen Zhang <dichenzhang@google.com> 2022-10-25 17:05:23 +0000
commita4819140bca93820340f21cadc0a911ee10c2568 (patch)
tree7ac88023b73ee4b6f92fe1aeb23130f95d4d09dd
parent4a66b3cdf1a66827767ebf495cdebdf2f81d974a (diff)
libjpegrecoverymap: add JPEG encoder for single channel image
test: jpegencoder_test bug: b/252835416 Change-Id: I6a13438ae4695569058645ad13c1182b7a626524
-rw-r--r--libs/jpegrecoverymap/include/jpegrecoverymap/jpegencoder.h14
-rw-r--r--libs/jpegrecoverymap/jpegencoder.cpp80
-rw-r--r--libs/jpegrecoverymap/tests/data/minnie-320x240.y1930
-rw-r--r--libs/jpegrecoverymap/tests/jpegencoder_test.cpp17
4 files changed, 2016 insertions, 25 deletions
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<const JOCTET*>(iccBuffer), iccSize);
}
- if (!compress(&cinfo, static_cast<const uint8_t*>(inYuv))) {
+ if (!compress(&cinfo, static_cast<const uint8_t*>(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<uint8_t*>(image);
+ std::unique_ptr<uint8_t[]> 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=1bmO<Ajƿ½¾źFOH7LB:ľ¾¼ȼ;Q>8}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;<?DEKPROLQSSDEIw~|}}y{ywspmjiigefb\`r{`=243.6IOPOSWY]^ehy¿ǐ@ÿ~~|{{zwsomjihggcZV\nwuT?2>XdZ¿}|{{zurplkifde`XQVlw}nO::GdƯE}z{zxuromlgdaa]XRPgv{wP;2;X{{H||xwuroojfca`\XQK^sx}bJ:<GZoC}¿¿z~~yurqqnjeb`]WRLKYouz¿oYIABGVLl¿}z{vqoomida^[SLIGWqtwǼv|¿wz{xtonliea]ZOIDCOptwywz~{xtqolhec]UMHA@Iluxuw}zvtplifcaZRJE=9@gvzÿvtz|uqmkida]WOD9407cz|ow|~ztplkeb\YQD:41.1Xx}wty~{}~|vsojfb\VME?;620/Jv}¾su{~{{zz{~}vrmgb^ZQIHDB?9736Dk}¿tw|yxyz{|}upe`\WOIGHGCA@=;:Bdz¿t}}yxwvvxy{}k_VOMIJIGEBA@=?Yr}ջ]_lwy}wusvxxxz~xoeZRPIFDBPlzҫ:8752ȫĿ¾ýz~~xurssutuxy{{~}jYOKPhuә:?>?:Һl><ABDWȋexžqbUHD?866732489<>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"  
+ <t{}~~{yvussssssqqrpqqpnqpqpopqrtwz}5"w{{|t#b|<jTM)/164>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 !!"""!"  
+
+
+
+
+ <c<0034453048GwĻ{xursqpponokWZ]aitvuxxxz|~~}~~~~~}|||zyxusronnlklljifihfbcbbcf[FIJJMPQRVY[ZZZVQRV[^_cfeimqy}ytrpou~ !!"
+
+
+
+
+
+
+
+
+
+ )qf0(/7;889:9<::5.@{ûþzwutqrqpppoy>j{xxz|{|~~~~~}}}||||zywvtrollkkjhghgeaababgM=BFIKNOQVYXYXWQOQVZ^`bdgkotyyuopqot
+
+
+
+
+
+
+
+
+
+
+
+ `ĚB'1524:95457;96784.Qїqc&*),+Mxstrqppont[f|ywxz{|}~}{{||}~~{zzxusrqnllkjhgfccaaac=3<BGIKMOQTWWWSOOSY[_bbdgkptxvpqqosx 
+
+
+
+
+
+
+
+
+ Gˋ5172692.5=?;963367583Aү:-343ƺ˨ynadD6trsrqqpnpp'f~yyyz|}~~|{}~~~||{xuuusqnnlkkkheb`cQ248<BFIKMORTUSNMPTX]^_`deioswqppons| 
+
+
+
+
+
+
+
+
+
+
+ 1t|)1:7723Mwc=0:98=;>V16697Po0240K//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#
+ !(,7<?BGJLKJGJMRVYZ\]\acehijot}  
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ RxD-6:5X,+,./-/2286Vz5:89?|xycZtrrsz;#|{~B #(.8>AGJJJIHJMPUXYZ[\_abeknt~   
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+ 0u-+052E(0./+::279:9a3979E~zxu|ADtsrxZ)|j "(+/9?CHIHFGHLNRUXY[\]^_ajr~ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ e%(),2½s$/0/01x-;8;6oS4765F|yxutn"$%prwo"*.: &).4<AFFEDFILNPRTYZY]]\]amy   
+
+
+
+
+
+
+
+
+
+
+
+ O "$)3Ú11114,wʪ96589CĺF6763D}{xutxN#NWw|F8Y5` #)-4:@EFDCEIKNPRUVXZ\\[[[`fnuz
+
+
+
+   
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  ,w~ "*ñ@.4271L`066:2İ?7640D}{xutvt-:h-|j}UB,
+ !'+29@DCCCEIJJMPTUUYZYYYY[\^hmrx{}
+
+
+
+
+
+ 
+
+
+  
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ \$]*63352·.6685Vƣ7710)D|yywust`Iw3U7\OIi
+ $)28?CBBEEFGGJNPSSTWWWXY[[^cfiortxx{
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+  9u~}~6U¿~'2212,sǺB47587Ɣ/2-+#A~zxvwvtrwEY}Y2LR9
+
+
+
+
+ $(28>BBCDEFFGGIMRRSVUVWX\`_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#%%(/-<z(*)#PL 
+
+
+
+
+
+
+
+
+#5435;=AEJNPQSQSVWZ^_cdddinsuw{ 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 9qj^`m~}}L"#&f-68<<5}ô151-,$y%5/-/...--..(o{!''((n{*(("Au
+
+
+
+
+
+
+
+
+%0147:;=BHLOSSQRUW[\_cfhlmtx| 
+
+ 
+
+
+
+
+
+
+
+
+
+
+
+ Csk^]f|~uF<>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:<AEFJORVZ]]abfnruzyj]E82    
+
+
+
+
+
+
+
+
+
+
+
+ a{veY^`q¼Q/C #]8*(,-gM,0.)ÿlg$
+
+
+
+
+
+
+
+   /:AEILNVZ[]a`chmknkeYI?2(&&'(   
+
+
+
+
+
+
+
+
+
+
+ gywkZ]aet*& !p< !"#""$'+//447;BDy}df
+
+
+
+
+
+
+
+
+
+ 
+  $*3:<CFHNNOKFD<4)+&"%$&'&&   
+
+
+
+
+
+
+
+
+
+
+
+
+
+  kwwj\^adr{utr}}tw{{~cjb
+
+
+
+
+
+
+
+
+
+
+   $$!"!# """$%$"   
+
+
+
+
+
+
+
+
+
+
+  "rzyo^_aci|mbpa
+
+
+
+
+
+
+
+
+
+
+
+ 
+ !###$rbTE1   
+
+
+
+
+
+
+
+
+
+
+
+
+ %tz{r\]^acm»zagpa
+
+
+
+
+
+
+
+
+
+    #%%'|dF1 
+
+
+
+
+
+
+
+
+
+
+
+
+ .y}~s^[^adg~adjs]
+
+
+
+
+
+
+
+
+
+
+
+  "#'()j9 
+
+
+
+
+
+
+
+
+
+
+
+ 1}~~ud[]`ddoi_flu\
+
+
+
+
+
+
+
+
+
+
+   #&()*k  
+
+
+
+
+
+
+
+
+
+
+ 3zd[^_bdfu¿r\cimq]
+
+
+
+
+
+
+
+ 
+
+
+ 
+ !$#%%)*)g 
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <~{h\^`cedm¼acgknq\
+
+
+
+
+
+
+
+
+ 
+
+    "#%'&&&*+)S  
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >{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 %%*,<A2=ʌ67>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::<jhffgdd`a_[WU=
+
+
+
+
+ [w~}wtjdb_`eginnprw¾63446776546::978874/JǼõo6)021../210013793/Mútopsvzxwz}x
+
+
+
+
+
+
+
+
+
+
+
+ + ((% "%.6;=@gdcda``\XXVRQD
+
+
+
+
+ ]y~|wrhb_^`eilnnqtz0...0.0012/41,/3345731ƺL///00010//./0/04421+1ywonrsy|yxzp
+
+  %R6%' !$%*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:9<?O($!!%"lFiu|tlosyzz~{}
+
+
+
+
+
+
+
+
+ #'''''&&&%%&&%%##%+/65455300/-,+*)(!
+
+
+  6~yutronopommlprrsstustvx{±?6324M_ ! / %@+ý~tjlstwz{| 
+
+
+
+
+
+
+
+
+
+ $('''(('&&&&%&%$%#%,353310///,*'')&$
+
+
+
+
+
+  \|ywsqqsrpopqqrrrrstutux}¨5.+++O$M/ bjO}ulkotwxz||~{
+
+
+
+ &)))'&%&&%&&$%$%&%$&+.211/---,*('&&%"
+
+
+
+
+ #~|xutuvvutsssttstvvuxxzŸ53,,,Y4zU! !).Ľumkortx{~{
+
+
+
+
+
+ &***'%&&%%%&%%%$&(&&',/!001--.,))'&&&" 
+
+
+  ?|zyyz{zxvvtuuuuxz|~5:497j9= ! "#"7? A~volosuvz}|6 
+
+
+
+
+
+
+'++)(('&&&&%%%&%&&&&%&(1#/.,,++)%&&%$# 
+
+
+
+
+
+
+   b||~~}zyxxx{}+4361we)J$""#7@#  »wninsvwyy|Y  
+ !*-+)(((''&%%&&&'%$%%$$&+/$****&%&$$$"!
+
+
+
+
+
+  "}|q'0/0,nb9X(!#!! *fh1 !Txoimqtvxy{~{y!
+
+
+
+
+
+
+ %)++)(((''&&%%&&&&%%%$%%%(3$)(%$##$##" 
+
+
+
+
+
+
+ 5]!&'&%,@DAC<90&Gt 2Sq}|{qV5 ={qklqstvy{|~zI
+
+
+
+
+
+
+
+
+
+%*++)(((&&%%&%%&&'%$$$%$$%)/('#$&##$"
+
+
+
+
+
+
+
+ _NNZ#%$! :~skkpsrtvy|~o
+
+
+
+
+
+
+  )*,+)((('&'&&%%%%%%$$#%%%&'(('%%%##!
+
+
+
+
+    !|{|~C'bWBſ}ukmprrsvyz|~}-
+
+
+
+
+
+ ")++**)))('&'&%%&&&%$%$%%%&&%&$$$"""
+
+
+
+
+
+ 9zvrsuwy}6'Rh" Wztlmorrsuwz|{H
+
+
+
+
+
+
+
+ !*+*+*))(((&&&$%''&%%%%$%%%&$%$#"!
+
+
+
+
+
+
+
+ X÷{upnmnopquxz{zyzy=-Ce{C<zvllnqrssuxy~n 
+
+
+
+
+
+
+
+
+
+ !$*+****))((&''%%%%%&&%%%%%%$%$$# 
+
+
+
+  ~~zxqnnlkkkloprssssspmfca\[X[[[Y]bju|zJ))Asÿztnknprssuuxz~~8  
+
+
+
+
+  !"',+******)((('('&&&('&&&%%$%&#$#
+
+
+
+  .ÿzwuqomjjiikmooopqpppmmklnnmpsxsaOINW`vþysokmpqrrtwvx{{Y 
+
+
+
+
+
+
+!(,+***+,+*)()(')(&'&&&%&&$#&&"# 
+
+
+
+
+ Qƽwvsonmkijkmnnnopoooonllmllmotz}Ŀ~yrjlmnoqprvwxz~~v 
+
+
+
+
+  "(++++**+)))))('(('&%&%%%$&''&
+
+
+
+
+ {Žzwtrpmnmnoopqpppooppomnopptw{¾zrkonqromoqsy{~}4
+
+
+
+
+
+
+ !(*+,,+*+*+)('''')(&&'%%%%&'&%
+
+
+
+   -ŻPm¶zvvsrrssusstrrstqqrtuuvuw|¾z{kOB9ATjrqru{~}V 
+
+
+
+
+
+
+
+ ")++,,+***+)((('()('(''%&&&&&%
+
+
+
+
+  MƹZ")0PƵ}||||zzxxxxvuuvzyyyvvy~z{_*$Inwx~t
+
+
+
+
+
+
+
+
+
+ !)++*+,***)((())(((&&&''''%%'%
+
+ rĹ»*(+)8ȶ|yxyy|}ÿ~wzV,f}: 
+
+ "(++++,*)***+*))())'&&'(''&''&
+
+
+
+
+
+
+  #º](*(=Ƴ³|zx{{vwY!%kW
+ $)*********+*))''))((''(&%&''(
+
+
+
+
+
+
+   :Ƚú}|8"&'LŸW?GRap}|}~{uwa'8s
+
+
+
+
+
+
+$)+++++++))*)*,((((((('&''%'('
+
+
+
+
+
+
+
+
+
+ Sɼú|zx{  %%Sǽ]088485H¼¿whed_x}ttm,E3
+
+
+
+
+
+
+ %+*)**)*)'(())*'''('&&&&''&''%
+
+
+
+
+
+
+
+ s˽ļ~zxx}m Z`0234367\¾:!kxrr8+Pae\?}O
+
+
+
+
+ '+)))***('()))((())'&&%'''(''&
+
+ 
+
+
+
+ (Ⱦ¾{vuu{VRi35465572z¿{9BGQs/2tpyS?mtuv|f(V¿l 
+
+
+
+
+
+
+
+
+ '+**)+*))***)))**)('(('&'&)('% 
+ 
+
+
+ <½|xttu}A6|,311566:;E-,-+BȼfYNG@:62118Mſ#Nqqc"Grosw|j<y. 
+
+
+
+
+ !(*++*))+)*+))))))(()*)('(''&%'
+
+
+
+
+ 
+ \~zvrruz6{.)*,./37:FĿk43.,,2ğsU<6533332//.0/25Rt!gln1?uoty|Q
+
+
+ !*+***+**)**))*)))'(())('''&'&(
+
+
+ 
+
+
+
+  ý{xuqpsy}/F9'&(,,/56Wϊ8630163xɝd=54642-,'')),020243AXBpmL.tuv|j
+
+
+
+ !$*.+,+,,,*)****)))**)**(()('('%'
+
+
+
+ 
+   ,ľ|ytpnqvy~+!!re !$%).45n΢?5210148Sѭf=6651++>TgtthR4-42.00.:"fmi'axw~y-
+
+
+
+
+
+
+
+
+  33-,,,++*+*+*)*)))++**)(()&((&'
+
+
+ 
+
+
+  =Ľ|wsonpruvx+,F=) %*/3̨F4/..-.129ǂF523/*<dd,*,+&qn"AnoM8~zG
+
+
+
++81,,++**+))*++)()***)((('&(('( !% 
+
+
+
+
+
+ Rľ{uponmoor;%jl]!%+3˳K50/-++++,+rи_5824,/i-(&kS]jn0]g
+ !"+38--,++++**+-+()()*++)((''(((( !$'),/
+
+
+   r½~zsqommmqU oB?01%1ĸS/110*))))+*HѱM4231+K1d}4.nmg  x<
+
+
+
+
+
+
+  #*.69-,,,+*)*)*+**)))*,+())))()'"&,-/005&
+  *~zvsmnnmj%XpolD[3_3522-9I'*+./ͳO3311)`~m%Dwu[0^
+
+ !! #%+,-:7,-,**)))*,*)*))*))***))((' $)+-0101*
+
+
+
+
+ ?ſ|wuqomp::yO8=xc5|4:6479σ(,+-.X]3400(eeST;þt,
+
+ ! ").-,181,+*)**+++)*+*(()(),)(*('( ""$'*+..1200.
+
+ ^þ}zwrnpO%kv,Ci2866675|ĭ7../17ˋ4402/IeXY:P
+
+
+
+  !!&..,+49/++**++*+)***)()((+*('(()!%()))+.///13331  þ}xstaWyalm.I*0-/.WY-2013p[21041üj Rg0t&
+
+
+ ##$#!#+,./-.65--+*+*)****)**)*)))))))* '''&(0./20021/445558 *½zvn$Auu=6z|p/u%)*)+2*1//1IƬ>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.,,-,++*)))))()**)*<<=><?=BD@@>AB@CEEFEHHGO
+ 44&}>&#y6-}.,{H.--/-$f3"{+ FrxZ&#"$$²y  ()*+,......--,-..-.22,,,+-+****)*)()(();<<?BDABEGDEIJFFGIKIILMT4  e.)!qlU~}FC}}sm0$~t"$#!"$%_G  ')))(*.--.,-/,-013.063,+*,-*)*+*****)**==>DFEEFKLLJMNNOKNLMILR]C  .tH'-~k?#x{{zkJtn+&b ""!!"#Tk
+ *()((&).0/.-././12:82270,++++++++*))*+**BBFIJJKKNOQLNOOPNOMLOQPSD \}{"`r!'M}zx|OG\!ut#+V!""$#f¼. #*((('(*.0//..////0<N6-47-*+**+**++)(*,*(ILJIKLJJLOSRQOOMMNOLONLIH #y"W~D uuncYNJCA=81-*h{z|{xuy76rs#$|r,] !"$";þO  !'''((**-../.-//.,/1KK-.78**+)**)*+*))***LOPPQRQONOPSSRSPLNONJKNMM1
+ Yƺ|%J~v#D~|c7{ywxvtvv/ RW,k*o8!*Iļq &''(''(+.../..-..-/15B7,/63,+*)()**,*(*+*PSSPSXTPSMPPRRSPNNLKMOQROA  ƴǽ'A}Wn~{AW}xxywyx1%=[nxvfG*We)v`Ycw¿= '(''&((*.../00-,-./1034-,05/**+*,,++*)***WWWY]^[YXTXSZ]ZURRSQPRWTMK Vó?#7}|/?}||t ,y}{}=Eh&d&))''()(,/.-010/.-/110/1/,-26,)(,..-,+***)UUUVXZ[ZXYYTY`^ZWY[YR\[YVZ$
+ ̿ĵ~{vpmfjB-$g~{zULT:i z¼|)*+*)**))....-//...020/-.//,,43-++,,,,+***)NOQQORRRSPQNMSPNQPQSSWVWVU5
+ NȾƹ~~qj~~4#ry0?`({I ++***))*./--...//.2510.../-+-64.,(*,,++*)(PRWVPOQTXTTRQQLLQOOOSVSTTSK ƻ̾x][\[Z]|_&UhH[vi,0-,,+++-//.-.///0/254//...-+-/71.+*++++*+*TXZXVQRYb^[[ZYXV\YVUZ][XW[_  T÷ð`2D{¿D62/-,--.00/..//...04511.-.--,+151-+*++*+--TUTTTQPPVZUUVVVWWUWY\ZZZ[[[)  "ƵhT>638Kd¾½Y2/+-.++.00.//00/-./1420/...,+,/43.+****+-,SQRSRQPWWWRQQTVUSRTUWVSUTTW9
+ Pȿʸ¿ýq4.,--*).///0/.//../07600.-..,+-/44,)**+++*[Y]ZT[[^eaZ]YX[YW\XXXW[XYVSGȺ˻ľE20,)++.0/./../../.0<C4/00.-,,,,05.++,++*)UVUSTWUV[[X\VXZ[]_`acac_b^YT LǶ;¿c10-**,.0/////....-.2<512/./-,+*-23,*,+*()MKPOPSRQNRONMQRTVTUUWWXZ[WTS% ðy80.+**///..0.---,,-.02351-/.,++-.53--+)*,MOPSOQRSQSSXQSSRSSTRPRSSTSSO>Cÿ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<uint32_t>(0));
+}
+
}