123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373 |
- /*
- * transupp.c
- *
- * This file was part of the Independent JPEG Group's software:
- * Copyright (C) 1997-2019, Thomas G. Lane, Guido Vollbeding.
- * libjpeg-turbo Modifications:
- * Copyright (C) 2010, 2017, 2021-2022, D. R. Commander.
- * For conditions of distribution and use, see the accompanying README.ijg
- * file.
- *
- * This file contains image transformation routines and other utility code
- * used by the jpegtran sample application. These are NOT part of the core
- * JPEG library. But we keep these routines separate from jpegtran.c to
- * ease the task of maintaining jpegtran-like programs that have other user
- * interfaces.
- */
- /* Although this file really shouldn't have access to the library internals,
- * it's helpful to let it call jround_up() and jcopy_block_row().
- */
- #define JPEG_INTERNALS
- #include "jinclude.h"
- #include "jpeglib.h"
- #include "transupp.h" /* My own external interface */
- #include "jpegcomp.h"
- #include <ctype.h> /* to declare isdigit() */
- #if JPEG_LIB_VERSION >= 70
- #define dstinfo_min_DCT_h_scaled_size dstinfo->min_DCT_h_scaled_size
- #define dstinfo_min_DCT_v_scaled_size dstinfo->min_DCT_v_scaled_size
- #else
- #define dstinfo_min_DCT_h_scaled_size DCTSIZE
- #define dstinfo_min_DCT_v_scaled_size DCTSIZE
- #endif
- #if TRANSFORMS_SUPPORTED
- /*
- * Lossless image transformation routines. These routines work on DCT
- * coefficient arrays and thus do not require any lossy decompression
- * or recompression of the image.
- * Thanks to Guido Vollbeding for the initial design and code of this feature,
- * and to Ben Jackson for introducing the cropping feature.
- *
- * Horizontal flipping is done in-place, using a single top-to-bottom
- * pass through the virtual source array. It will thus be much the
- * fastest option for images larger than main memory.
- *
- * The other routines require a set of destination virtual arrays, so they
- * need twice as much memory as jpegtran normally does. The destination
- * arrays are always written in normal scan order (top to bottom) because
- * the virtual array manager expects this. The source arrays will be scanned
- * in the corresponding order, which means multiple passes through the source
- * arrays for most of the transforms. That could result in much thrashing
- * if the image is larger than main memory.
- *
- * If cropping or trimming is involved, the destination arrays may be smaller
- * than the source arrays. Note it is not possible to do horizontal flip
- * in-place when a nonzero Y crop offset is specified, since we'd have to move
- * data from one block row to another but the virtual array manager doesn't
- * guarantee we can touch more than one row at a time. So in that case,
- * we have to use a separate destination array.
- *
- * Some notes about the operating environment of the individual transform
- * routines:
- * 1. Both the source and destination virtual arrays are allocated from the
- * source JPEG object, and therefore should be manipulated by calling the
- * source's memory manager.
- * 2. The destination's component count should be used. It may be smaller
- * than the source's when forcing to grayscale.
- * 3. Likewise the destination's sampling factors should be used. When
- * forcing to grayscale the destination's sampling factors will be all 1,
- * and we may as well take that as the effective iMCU size.
- * 4. When "trim" is in effect, the destination's dimensions will be the
- * trimmed values but the source's will be untrimmed.
- * 5. When "crop" is in effect, the destination's dimensions will be the
- * cropped values but the source's will be uncropped. Each transform
- * routine is responsible for picking up source data starting at the
- * correct X and Y offset for the crop region. (The X and Y offsets
- * passed to the transform routines are measured in iMCU blocks of the
- * destination.)
- * 6. All the routines assume that the source and destination buffers are
- * padded out to a full iMCU boundary. This is true, although for the
- * source buffer it is an undocumented property of jdcoefct.c.
- */
- LOCAL(void)
- dequant_comp(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- jvirt_barray_ptr coef_array, JQUANT_TBL *qtblptr1)
- {
- JDIMENSION blk_x, blk_y;
- int offset_y, k;
- JQUANT_TBL *qtblptr;
- JBLOCKARRAY buffer;
- JBLOCKROW block;
- JCOEFPTR ptr;
- qtblptr = compptr->quant_table;
- for (blk_y = 0; blk_y < compptr->height_in_blocks;
- blk_y += compptr->v_samp_factor) {
- buffer = (*cinfo->mem->access_virt_barray)
- ((j_common_ptr)cinfo, coef_array, blk_y,
- (JDIMENSION)compptr->v_samp_factor, TRUE);
- for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
- block = buffer[offset_y];
- for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) {
- ptr = block[blk_x];
- for (k = 0; k < DCTSIZE2; k++)
- if (qtblptr->quantval[k] != qtblptr1->quantval[k])
- ptr[k] *= qtblptr->quantval[k] / qtblptr1->quantval[k];
- }
- }
- }
- }
- LOCAL(void)
- requant_comp(j_decompress_ptr cinfo, jpeg_component_info *compptr,
- jvirt_barray_ptr coef_array, JQUANT_TBL *qtblptr1)
- {
- JDIMENSION blk_x, blk_y;
- int offset_y, k;
- JQUANT_TBL *qtblptr;
- JBLOCKARRAY buffer;
- JBLOCKROW block;
- JCOEFPTR ptr;
- JCOEF temp, qval;
- qtblptr = compptr->quant_table;
- for (blk_y = 0; blk_y < compptr->height_in_blocks;
- blk_y += compptr->v_samp_factor) {
- buffer = (*cinfo->mem->access_virt_barray)
- ((j_common_ptr)cinfo, coef_array, blk_y,
- (JDIMENSION)compptr->v_samp_factor, TRUE);
- for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
- block = buffer[offset_y];
- for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) {
- ptr = block[blk_x];
- for (k = 0; k < DCTSIZE2; k++) {
- temp = qtblptr->quantval[k];
- qval = qtblptr1->quantval[k];
- if (temp != qval) {
- temp *= ptr[k];
- /* The following quantization code is copied from jcdctmgr.c */
- #ifdef FAST_DIVIDE
- #define DIVIDE_BY(a, b) a /= b
- #else
- #define DIVIDE_BY(a, b) if (a >= b) a /= b; else a = 0
- #endif
- if (temp < 0) {
- temp = -temp;
- temp += qval >> 1; /* for rounding */
- DIVIDE_BY(temp, qval);
- temp = -temp;
- } else {
- temp += qval >> 1; /* for rounding */
- DIVIDE_BY(temp, qval);
- }
- ptr[k] = temp;
- }
- }
- }
- }
- }
- }
- /*
- * Calculate largest common denominator using Euclid's algorithm.
- */
- LOCAL(JCOEF)
- largest_common_denominator(JCOEF a, JCOEF b)
- {
- JCOEF c;
- do {
- c = a % b;
- a = b;
- b = c;
- } while (c);
- return a;
- }
- LOCAL(void)
- adjust_quant(j_decompress_ptr srcinfo, jvirt_barray_ptr *src_coef_arrays,
- j_decompress_ptr dropinfo, jvirt_barray_ptr *drop_coef_arrays,
- boolean trim, j_compress_ptr dstinfo)
- {
- jpeg_component_info *compptr1, *compptr2;
- JQUANT_TBL *qtblptr1, *qtblptr2, *qtblptr3;
- int ci, k;
- for (ci = 0; ci < dstinfo->num_components && ci < dropinfo->num_components;
- ci++) {
- compptr1 = srcinfo->comp_info + ci;
- compptr2 = dropinfo->comp_info + ci;
- qtblptr1 = compptr1->quant_table;
- qtblptr2 = compptr2->quant_table;
- for (k = 0; k < DCTSIZE2; k++) {
- if (qtblptr1->quantval[k] != qtblptr2->quantval[k]) {
- if (trim)
- requant_comp(dropinfo, compptr2, drop_coef_arrays[ci], qtblptr1);
- else {
- qtblptr3 = dstinfo->quant_tbl_ptrs[compptr1->quant_tbl_no];
- for (k = 0; k < DCTSIZE2; k++)
- if (qtblptr1->quantval[k] != qtblptr2->quantval[k])
- qtblptr3->quantval[k] =
- largest_common_denominator(qtblptr1->quantval[k],
- qtblptr2->quantval[k]);
- dequant_comp(srcinfo, compptr1, src_coef_arrays[ci], qtblptr3);
- dequant_comp(dropinfo, compptr2, drop_coef_arrays[ci], qtblptr3);
- }
- break;
- }
- }
- }
- }
- LOCAL(void)
- do_drop(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
- JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
- jvirt_barray_ptr *src_coef_arrays,
- j_decompress_ptr dropinfo, jvirt_barray_ptr *drop_coef_arrays,
- JDIMENSION drop_width, JDIMENSION drop_height)
- /* Drop (insert) the contents of another image into the source image. If the
- * number of components in the drop image is smaller than the number of
- * components in the destination image, then we fill in the remaining
- * components with zero. This allows for dropping the contents of grayscale
- * images into (arbitrarily sampled) color images.
- */
- {
- JDIMENSION comp_width, comp_height;
- JDIMENSION blk_y, x_drop_blocks, y_drop_blocks;
- int ci, offset_y;
- JBLOCKARRAY src_buffer, dst_buffer;
- jpeg_component_info *compptr;
- for (ci = 0; ci < dstinfo->num_components; ci++) {
- compptr = dstinfo->comp_info + ci;
- comp_width = drop_width * compptr->h_samp_factor;
- comp_height = drop_height * compptr->v_samp_factor;
- x_drop_blocks = x_crop_offset * compptr->h_samp_factor;
- y_drop_blocks = y_crop_offset * compptr->v_samp_factor;
- for (blk_y = 0; blk_y < comp_height; blk_y += compptr->v_samp_factor) {
- dst_buffer = (*srcinfo->mem->access_virt_barray)
- ((j_common_ptr)srcinfo, src_coef_arrays[ci], blk_y + y_drop_blocks,
- (JDIMENSION)compptr->v_samp_factor, TRUE);
- if (ci < dropinfo->num_components) {
- src_buffer = (*dropinfo->mem->access_virt_barray)
- ((j_common_ptr)dropinfo, drop_coef_arrays[ci], blk_y,
- (JDIMENSION)compptr->v_samp_factor, FALSE);
- for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
- jcopy_block_row(src_buffer[offset_y],
- dst_buffer[offset_y] + x_drop_blocks, comp_width);
- }
- } else {
- for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
- memset(dst_buffer[offset_y] + x_drop_blocks, 0,
- comp_width * sizeof(JBLOCK));
- }
- }
- }
- }
- }
- LOCAL(void)
- do_crop(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
- JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
- jvirt_barray_ptr *src_coef_arrays,
- jvirt_barray_ptr *dst_coef_arrays)
- /* Crop. This is only used when no rotate/flip is requested with the crop. */
- {
- JDIMENSION dst_blk_y, x_crop_blocks, y_crop_blocks;
- int ci, offset_y;
- JBLOCKARRAY src_buffer, dst_buffer;
- jpeg_component_info *compptr;
- /* We simply have to copy the right amount of data (the destination's
- * image size) starting at the given X and Y offsets in the source.
- */
- for (ci = 0; ci < dstinfo->num_components; ci++) {
- compptr = dstinfo->comp_info + ci;
- x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
- y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
- for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
- dst_blk_y += compptr->v_samp_factor) {
- dst_buffer = (*srcinfo->mem->access_virt_barray)
- ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
- (JDIMENSION)compptr->v_samp_factor, TRUE);
- src_buffer = (*srcinfo->mem->access_virt_barray)
- ((j_common_ptr)srcinfo, src_coef_arrays[ci], dst_blk_y + y_crop_blocks,
- (JDIMENSION)compptr->v_samp_factor, FALSE);
- for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
- jcopy_block_row(src_buffer[offset_y] + x_crop_blocks,
- dst_buffer[offset_y], compptr->width_in_blocks);
- }
- }
- }
- }
- LOCAL(void)
- do_crop_ext_zero(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
- JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
- jvirt_barray_ptr *src_coef_arrays,
- jvirt_barray_ptr *dst_coef_arrays)
- /* Crop. This is only used when no rotate/flip is requested with the crop.
- * Extension: If the destination size is larger than the source, we fill in the
- * expanded region with zero (neutral gray). Note that we also have to zero
- * partial iMCUs at the right and bottom edge of the source image area in this
- * case.
- */
- {
- JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height;
- JDIMENSION dst_blk_y, x_crop_blocks, y_crop_blocks;
- int ci, offset_y;
- JBLOCKARRAY src_buffer, dst_buffer;
- jpeg_component_info *compptr;
- MCU_cols = srcinfo->output_width /
- (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
- MCU_rows = srcinfo->output_height /
- (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
- for (ci = 0; ci < dstinfo->num_components; ci++) {
- compptr = dstinfo->comp_info + ci;
- comp_width = MCU_cols * compptr->h_samp_factor;
- comp_height = MCU_rows * compptr->v_samp_factor;
- x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
- y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
- for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
- dst_blk_y += compptr->v_samp_factor) {
- dst_buffer = (*srcinfo->mem->access_virt_barray)
- ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
- (JDIMENSION)compptr->v_samp_factor, TRUE);
- if (dstinfo->_jpeg_height > srcinfo->output_height) {
- if (dst_blk_y < y_crop_blocks ||
- dst_blk_y >= y_crop_blocks + comp_height) {
- for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
- memset(dst_buffer[offset_y], 0,
- compptr->width_in_blocks * sizeof(JBLOCK));
- }
- continue;
- }
- src_buffer = (*srcinfo->mem->access_virt_barray)
- ((j_common_ptr)srcinfo, src_coef_arrays[ci],
- dst_blk_y - y_crop_blocks, (JDIMENSION)compptr->v_samp_factor,
- FALSE);
- } else {
- src_buffer = (*srcinfo->mem->access_virt_barray)
- ((j_common_ptr)srcinfo, src_coef_arrays[ci],
- dst_blk_y + y_crop_blocks, (JDIMENSION)compptr->v_samp_factor,
- FALSE);
- }
- for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
- if (dstinfo->_jpeg_width > srcinfo->output_width) {
- if (x_crop_blocks > 0) {
- memset(dst_buffer[offset_y], 0, x_crop_blocks * sizeof(JBLOCK));
- }
- jcopy_block_row(src_buffer[offset_y],
- dst_buffer[offset_y] + x_crop_blocks, comp_width);
- if (compptr->width_in_blocks > x_crop_blocks + comp_width) {
- memset(dst_buffer[offset_y] + x_crop_blocks + comp_width, 0,
- (compptr->width_in_blocks - x_crop_blocks - comp_width) *
- sizeof(JBLOCK));
- }
- } else {
- jcopy_block_row(src_buffer[offset_y] + x_crop_blocks,
- dst_buffer[offset_y], compptr->width_in_blocks);
- }
- }
- }
- }
- }
- LOCAL(void)
- do_crop_ext_flat(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
- JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
- jvirt_barray_ptr *src_coef_arrays,
- jvirt_barray_ptr *dst_coef_arrays)
- /* Crop. This is only used when no rotate/flip is requested with the crop.
- * Extension: The destination width is larger than the source, and we fill in
- * the expanded region with the DC coefficient of the adjacent block. Note
- * that we also have to fill partial iMCUs at the right and bottom edge of the
- * source image area in this case.
- */
- {
- JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height;
- JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks;
- int ci, offset_y;
- JCOEF dc;
- JBLOCKARRAY src_buffer, dst_buffer;
- jpeg_component_info *compptr;
- MCU_cols = srcinfo->output_width /
- (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
- MCU_rows = srcinfo->output_height /
- (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
- for (ci = 0; ci < dstinfo->num_components; ci++) {
- compptr = dstinfo->comp_info + ci;
- comp_width = MCU_cols * compptr->h_samp_factor;
- comp_height = MCU_rows * compptr->v_samp_factor;
- x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
- y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
- for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
- dst_blk_y += compptr->v_samp_factor) {
- dst_buffer = (*srcinfo->mem->access_virt_barray)
- ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
- (JDIMENSION)compptr->v_samp_factor, TRUE);
- if (dstinfo->_jpeg_height > srcinfo->output_height) {
- if (dst_blk_y < y_crop_blocks ||
- dst_blk_y >= y_crop_blocks + comp_height) {
- for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
- memset(dst_buffer[offset_y], 0,
- compptr->width_in_blocks * sizeof(JBLOCK));
- }
- continue;
- }
- src_buffer = (*srcinfo->mem->access_virt_barray)
- ((j_common_ptr)srcinfo, src_coef_arrays[ci],
- dst_blk_y - y_crop_blocks, (JDIMENSION)compptr->v_samp_factor,
- FALSE);
- } else {
- src_buffer = (*srcinfo->mem->access_virt_barray)
- ((j_common_ptr)srcinfo, src_coef_arrays[ci],
- dst_blk_y + y_crop_blocks, (JDIMENSION)compptr->v_samp_factor,
- FALSE);
- }
- for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
- if (x_crop_blocks > 0) {
- memset(dst_buffer[offset_y], 0, x_crop_blocks * sizeof(JBLOCK));
- dc = src_buffer[offset_y][0][0];
- for (dst_blk_x = 0; dst_blk_x < x_crop_blocks; dst_blk_x++) {
- dst_buffer[offset_y][dst_blk_x][0] = dc;
- }
- }
- jcopy_block_row(src_buffer[offset_y],
- dst_buffer[offset_y] + x_crop_blocks, comp_width);
- if (compptr->width_in_blocks > x_crop_blocks + comp_width) {
- memset(dst_buffer[offset_y] + x_crop_blocks + comp_width, 0,
- (compptr->width_in_blocks - x_crop_blocks - comp_width) *
- sizeof(JBLOCK));
- dc = src_buffer[offset_y][comp_width - 1][0];
- for (dst_blk_x = x_crop_blocks + comp_width;
- dst_blk_x < compptr->width_in_blocks; dst_blk_x++) {
- dst_buffer[offset_y][dst_blk_x][0] = dc;
- }
- }
- }
- }
- }
- }
- LOCAL(void)
- do_crop_ext_reflect(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
- JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
- jvirt_barray_ptr *src_coef_arrays,
- jvirt_barray_ptr *dst_coef_arrays)
- /* Crop. This is only used when no rotate/flip is requested with the crop.
- * Extension: The destination width is larger than the source, and we fill in
- * the expanded region with repeated reflections of the source image. Note
- * that we also have to fill partial iMCUs at the right and bottom edge of the
- * source image area in this case.
- */
- {
- JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, src_blk_x;
- JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks;
- int ci, k, offset_y;
- JBLOCKARRAY src_buffer, dst_buffer;
- JBLOCKROW src_row_ptr, dst_row_ptr;
- JCOEFPTR src_ptr, dst_ptr;
- jpeg_component_info *compptr;
- MCU_cols = srcinfo->output_width /
- (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
- MCU_rows = srcinfo->output_height /
- (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
- for (ci = 0; ci < dstinfo->num_components; ci++) {
- compptr = dstinfo->comp_info + ci;
- comp_width = MCU_cols * compptr->h_samp_factor;
- comp_height = MCU_rows * compptr->v_samp_factor;
- x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
- y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
- for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
- dst_blk_y += compptr->v_samp_factor) {
- dst_buffer = (*srcinfo->mem->access_virt_barray)
- ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
- (JDIMENSION)compptr->v_samp_factor, TRUE);
- if (dstinfo->_jpeg_height > srcinfo->output_height) {
- if (dst_blk_y < y_crop_blocks ||
- dst_blk_y >= y_crop_blocks + comp_height) {
- for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
- memset(dst_buffer[offset_y], 0,
- compptr->width_in_blocks * sizeof(JBLOCK));
- }
- continue;
- }
- src_buffer = (*srcinfo->mem->access_virt_barray)
- ((j_common_ptr)srcinfo, src_coef_arrays[ci],
- dst_blk_y - y_crop_blocks, (JDIMENSION)compptr->v_samp_factor,
- FALSE);
- } else {
- src_buffer = (*srcinfo->mem->access_virt_barray)
- ((j_common_ptr)srcinfo, src_coef_arrays[ci],
- dst_blk_y + y_crop_blocks, (JDIMENSION)compptr->v_samp_factor,
- FALSE);
- }
- for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
- /* Copy source region */
- jcopy_block_row(src_buffer[offset_y],
- dst_buffer[offset_y] + x_crop_blocks, comp_width);
- if (x_crop_blocks > 0) {
- /* Reflect to left */
- dst_row_ptr = dst_buffer[offset_y] + x_crop_blocks;
- for (dst_blk_x = x_crop_blocks; dst_blk_x > 0;) {
- src_row_ptr = dst_row_ptr; /* (re)set axis of reflection */
- for (src_blk_x = comp_width; src_blk_x > 0 && dst_blk_x > 0;
- src_blk_x--, dst_blk_x--) {
- dst_ptr = *(--dst_row_ptr); /* destination goes left */
- src_ptr = *src_row_ptr++; /* source goes right */
- /* This unrolled loop doesn't need to know which row it's on. */
- for (k = 0; k < DCTSIZE2; k += 2) {
- *dst_ptr++ = *src_ptr++; /* copy even column */
- *dst_ptr++ = -(*src_ptr++); /* copy odd column with sign
- change */
- }
- }
- }
- }
- if (compptr->width_in_blocks > x_crop_blocks + comp_width) {
- /* Reflect to right */
- dst_row_ptr = dst_buffer[offset_y] + x_crop_blocks + comp_width;
- for (dst_blk_x = compptr->width_in_blocks - x_crop_blocks - comp_width;
- dst_blk_x > 0;) {
- src_row_ptr = dst_row_ptr; /* (re)set axis of reflection */
- for (src_blk_x = comp_width; src_blk_x > 0 && dst_blk_x > 0;
- src_blk_x--, dst_blk_x--) {
- dst_ptr = *dst_row_ptr++; /* destination goes right */
- src_ptr = *(--src_row_ptr); /* source goes left */
- /* This unrolled loop doesn't need to know which row it's on. */
- for (k = 0; k < DCTSIZE2; k += 2) {
- *dst_ptr++ = *src_ptr++; /* copy even column */
- *dst_ptr++ = -(*src_ptr++); /* copy odd column with sign
- change */
- }
- }
- }
- }
- }
- }
- }
- }
- LOCAL(void)
- do_wipe(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
- JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
- jvirt_barray_ptr *src_coef_arrays,
- JDIMENSION drop_width, JDIMENSION drop_height)
- /* Wipe - discard image contents of specified region and fill with zero
- * (neutral gray)
- */
- {
- JDIMENSION x_wipe_blocks, wipe_width;
- JDIMENSION y_wipe_blocks, wipe_bottom;
- int ci, offset_y;
- JBLOCKARRAY buffer;
- jpeg_component_info *compptr;
- for (ci = 0; ci < dstinfo->num_components; ci++) {
- compptr = dstinfo->comp_info + ci;
- x_wipe_blocks = x_crop_offset * compptr->h_samp_factor;
- wipe_width = drop_width * compptr->h_samp_factor;
- y_wipe_blocks = y_crop_offset * compptr->v_samp_factor;
- wipe_bottom = drop_height * compptr->v_samp_factor + y_wipe_blocks;
- for (; y_wipe_blocks < wipe_bottom;
- y_wipe_blocks += compptr->v_samp_factor) {
- buffer = (*srcinfo->mem->access_virt_barray)
- ((j_common_ptr)srcinfo, src_coef_arrays[ci], y_wipe_blocks,
- (JDIMENSION)compptr->v_samp_factor, TRUE);
- for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
- memset(buffer[offset_y] + x_wipe_blocks, 0,
- wipe_width * sizeof(JBLOCK));
- }
- }
- }
- }
- LOCAL(void)
- do_flatten(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
- JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
- jvirt_barray_ptr *src_coef_arrays,
- JDIMENSION drop_width, JDIMENSION drop_height)
- /* Flatten - discard image contents of specified region, similarly to wipe,
- * but fill with the average of adjacent blocks instead of zero.
- */
- {
- JDIMENSION x_wipe_blocks, wipe_width, wipe_right;
- JDIMENSION y_wipe_blocks, wipe_bottom, blk_x;
- int ci, offset_y, dc_left_value, dc_right_value, average;
- JBLOCKARRAY buffer;
- jpeg_component_info *compptr;
- for (ci = 0; ci < dstinfo->num_components; ci++) {
- compptr = dstinfo->comp_info + ci;
- x_wipe_blocks = x_crop_offset * compptr->h_samp_factor;
- wipe_width = drop_width * compptr->h_samp_factor;
- wipe_right = wipe_width + x_wipe_blocks;
- y_wipe_blocks = y_crop_offset * compptr->v_samp_factor;
- wipe_bottom = drop_height * compptr->v_samp_factor + y_wipe_blocks;
- for (; y_wipe_blocks < wipe_bottom;
- y_wipe_blocks += compptr->v_samp_factor) {
- buffer = (*srcinfo->mem->access_virt_barray)
- ((j_common_ptr)srcinfo, src_coef_arrays[ci], y_wipe_blocks,
- (JDIMENSION)compptr->v_samp_factor, TRUE);
- for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
- memset(buffer[offset_y] + x_wipe_blocks, 0,
- wipe_width * sizeof(JBLOCK));
- if (x_wipe_blocks > 0) {
- dc_left_value = buffer[offset_y][x_wipe_blocks - 1][0];
- if (wipe_right < compptr->width_in_blocks) {
- dc_right_value = buffer[offset_y][wipe_right][0];
- average = (dc_left_value + dc_right_value) >> 1;
- } else {
- average = dc_left_value;
- }
- } else if (wipe_right < compptr->width_in_blocks) {
- average = buffer[offset_y][wipe_right][0];
- } else continue;
- for (blk_x = x_wipe_blocks; blk_x < wipe_right; blk_x++) {
- buffer[offset_y][blk_x][0] = (JCOEF)average;
- }
- }
- }
- }
- }
- LOCAL(void)
- do_reflect(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
- JDIMENSION x_crop_offset, jvirt_barray_ptr *src_coef_arrays,
- JDIMENSION drop_width, JDIMENSION drop_height)
- /* Reflect - discard image contents of specified region, similarly to wipe,
- * but fill with repeated reflections of the outside region instead of zero.
- * NB: y_crop_offset is assumed to be zero.
- */
- {
- JDIMENSION x_wipe_blocks, wipe_width;
- JDIMENSION y_wipe_blocks, wipe_bottom;
- JDIMENSION src_blk_x, dst_blk_x;
- int ci, k, offset_y;
- JBLOCKARRAY buffer;
- JBLOCKROW src_row_ptr, dst_row_ptr;
- JCOEFPTR src_ptr, dst_ptr;
- jpeg_component_info *compptr;
- for (ci = 0; ci < dstinfo->num_components; ci++) {
- compptr = dstinfo->comp_info + ci;
- x_wipe_blocks = x_crop_offset * compptr->h_samp_factor;
- wipe_width = drop_width * compptr->h_samp_factor;
- wipe_bottom = drop_height * compptr->v_samp_factor;
- for (y_wipe_blocks = 0; y_wipe_blocks < wipe_bottom;
- y_wipe_blocks += compptr->v_samp_factor) {
- buffer = (*srcinfo->mem->access_virt_barray)
- ((j_common_ptr)srcinfo, src_coef_arrays[ci], y_wipe_blocks,
- (JDIMENSION)compptr->v_samp_factor, TRUE);
- for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
- if (x_wipe_blocks > 0) {
- /* Reflect from left */
- dst_row_ptr = buffer[offset_y] + x_wipe_blocks;
- for (dst_blk_x = wipe_width; dst_blk_x > 0;) {
- src_row_ptr = dst_row_ptr; /* (re)set axis of reflection */
- for (src_blk_x = x_wipe_blocks;
- src_blk_x > 0 && dst_blk_x > 0; src_blk_x--, dst_blk_x--) {
- dst_ptr = *dst_row_ptr++; /* destination goes right */
- src_ptr = *(--src_row_ptr); /* source goes left */
- /* this unrolled loop doesn't need to know which row it's on... */
- for (k = 0; k < DCTSIZE2; k += 2) {
- *dst_ptr++ = *src_ptr++; /* copy even column */
- *dst_ptr++ = -(*src_ptr++); /* copy odd column with sign change */
- }
- }
- }
- } else if (compptr->width_in_blocks > x_wipe_blocks + wipe_width) {
- /* Reflect from right */
- dst_row_ptr = buffer[offset_y] + x_wipe_blocks + wipe_width;
- for (dst_blk_x = wipe_width; dst_blk_x > 0;) {
- src_row_ptr = dst_row_ptr; /* (re)set axis of reflection */
- src_blk_x = compptr->width_in_blocks - x_wipe_blocks - wipe_width;
- for (; src_blk_x > 0 && dst_blk_x > 0; src_blk_x--, dst_blk_x--) {
- dst_ptr = *(--dst_row_ptr); /* destination goes left */
- src_ptr = *src_row_ptr++; /* source goes right */
- /* this unrolled loop doesn't need to know which row it's on... */
- for (k = 0; k < DCTSIZE2; k += 2) {
- *dst_ptr++ = *src_ptr++; /* copy even column */
- *dst_ptr++ = -(*src_ptr++); /* copy odd column with sign change */
- }
- }
- }
- } else {
- memset(buffer[offset_y] + x_wipe_blocks, 0,
- wipe_width * sizeof(JBLOCK));
- }
- }
- }
- }
- }
- LOCAL(void)
- do_flip_h_no_crop(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
- JDIMENSION x_crop_offset, jvirt_barray_ptr *src_coef_arrays)
- /* Horizontal flip; done in-place, so no separate dest array is required.
- * NB: this only works when y_crop_offset is zero.
- */
- {
- JDIMENSION MCU_cols, comp_width, blk_x, blk_y, x_crop_blocks;
- int ci, k, offset_y;
- JBLOCKARRAY buffer;
- JCOEFPTR ptr1, ptr2;
- JCOEF temp1, temp2;
- jpeg_component_info *compptr;
- /* Horizontal mirroring of DCT blocks is accomplished by swapping
- * pairs of blocks in-place. Within a DCT block, we perform horizontal
- * mirroring by changing the signs of odd-numbered columns.
- * Partial iMCUs at the right edge are left untouched.
- */
- MCU_cols = srcinfo->output_width /
- (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
- for (ci = 0; ci < dstinfo->num_components; ci++) {
- compptr = dstinfo->comp_info + ci;
- comp_width = MCU_cols * compptr->h_samp_factor;
- x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
- for (blk_y = 0; blk_y < compptr->height_in_blocks;
- blk_y += compptr->v_samp_factor) {
- buffer = (*srcinfo->mem->access_virt_barray)
- ((j_common_ptr)srcinfo, src_coef_arrays[ci], blk_y,
- (JDIMENSION)compptr->v_samp_factor, TRUE);
- for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
- /* Do the mirroring */
- for (blk_x = 0; blk_x * 2 < comp_width; blk_x++) {
- ptr1 = buffer[offset_y][blk_x];
- ptr2 = buffer[offset_y][comp_width - blk_x - 1];
- /* this unrolled loop doesn't need to know which row it's on... */
- for (k = 0; k < DCTSIZE2; k += 2) {
- temp1 = *ptr1; /* swap even column */
- temp2 = *ptr2;
- *ptr1++ = temp2;
- *ptr2++ = temp1;
- temp1 = *ptr1; /* swap odd column with sign change */
- temp2 = *ptr2;
- *ptr1++ = -temp2;
- *ptr2++ = -temp1;
- }
- }
- if (x_crop_blocks > 0) {
- /* Now left-justify the portion of the data to be kept.
- * We can't use a single jcopy_block_row() call because that routine
- * depends on memcpy(), whose behavior is unspecified for overlapping
- * source and destination areas. Sigh.
- */
- for (blk_x = 0; blk_x < compptr->width_in_blocks; blk_x++) {
- jcopy_block_row(buffer[offset_y] + blk_x + x_crop_blocks,
- buffer[offset_y] + blk_x, (JDIMENSION)1);
- }
- }
- }
- }
- }
- }
- LOCAL(void)
- do_flip_h(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
- JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
- jvirt_barray_ptr *src_coef_arrays,
- jvirt_barray_ptr *dst_coef_arrays)
- /* Horizontal flip in general cropping case */
- {
- JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y;
- JDIMENSION x_crop_blocks, y_crop_blocks;
- int ci, k, offset_y;
- JBLOCKARRAY src_buffer, dst_buffer;
- JBLOCKROW src_row_ptr, dst_row_ptr;
- JCOEFPTR src_ptr, dst_ptr;
- jpeg_component_info *compptr;
- /* Here we must output into a separate array because we can't touch
- * different rows of a single virtual array simultaneously. Otherwise,
- * this is essentially the same as the routine above.
- */
- MCU_cols = srcinfo->output_width /
- (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
- for (ci = 0; ci < dstinfo->num_components; ci++) {
- compptr = dstinfo->comp_info + ci;
- comp_width = MCU_cols * compptr->h_samp_factor;
- x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
- y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
- for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
- dst_blk_y += compptr->v_samp_factor) {
- dst_buffer = (*srcinfo->mem->access_virt_barray)
- ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
- (JDIMENSION)compptr->v_samp_factor, TRUE);
- src_buffer = (*srcinfo->mem->access_virt_barray)
- ((j_common_ptr)srcinfo, src_coef_arrays[ci], dst_blk_y + y_crop_blocks,
- (JDIMENSION)compptr->v_samp_factor, FALSE);
- for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
- dst_row_ptr = dst_buffer[offset_y];
- src_row_ptr = src_buffer[offset_y];
- for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
- dst_blk_x++) {
- if (x_crop_blocks + dst_blk_x < comp_width) {
- /* Do the mirrorable blocks */
- dst_ptr = dst_row_ptr[dst_blk_x];
- src_ptr = src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
- /* this unrolled loop doesn't need to know which row it's on... */
- for (k = 0; k < DCTSIZE2; k += 2) {
- *dst_ptr++ = *src_ptr++; /* copy even column */
- *dst_ptr++ = -(*src_ptr++); /* copy odd column with sign
- change */
- }
- } else {
- /* Copy last partial block(s) verbatim */
- jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks,
- dst_row_ptr + dst_blk_x, (JDIMENSION)1);
- }
- }
- }
- }
- }
- }
- LOCAL(void)
- do_flip_v(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
- JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
- jvirt_barray_ptr *src_coef_arrays,
- jvirt_barray_ptr *dst_coef_arrays)
- /* Vertical flip */
- {
- JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y;
- JDIMENSION x_crop_blocks, y_crop_blocks;
- int ci, i, j, offset_y;
- JBLOCKARRAY src_buffer, dst_buffer;
- JBLOCKROW src_row_ptr, dst_row_ptr;
- JCOEFPTR src_ptr, dst_ptr;
- jpeg_component_info *compptr;
- /* We output into a separate array because we can't touch different
- * rows of the source virtual array simultaneously. Otherwise, this
- * is a pretty straightforward analog of horizontal flip.
- * Within a DCT block, vertical mirroring is done by changing the signs
- * of odd-numbered rows.
- * Partial iMCUs at the bottom edge are copied verbatim.
- */
- MCU_rows = srcinfo->output_height /
- (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
- for (ci = 0; ci < dstinfo->num_components; ci++) {
- compptr = dstinfo->comp_info + ci;
- comp_height = MCU_rows * compptr->v_samp_factor;
- x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
- y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
- for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
- dst_blk_y += compptr->v_samp_factor) {
- dst_buffer = (*srcinfo->mem->access_virt_barray)
- ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
- (JDIMENSION)compptr->v_samp_factor, TRUE);
- if (y_crop_blocks + dst_blk_y < comp_height) {
- /* Row is within the mirrorable area. */
- src_buffer = (*srcinfo->mem->access_virt_barray)
- ((j_common_ptr)srcinfo, src_coef_arrays[ci],
- comp_height - y_crop_blocks - dst_blk_y -
- (JDIMENSION)compptr->v_samp_factor,
- (JDIMENSION)compptr->v_samp_factor, FALSE);
- } else {
- /* Bottom-edge blocks will be copied verbatim. */
- src_buffer = (*srcinfo->mem->access_virt_barray)
- ((j_common_ptr)srcinfo, src_coef_arrays[ci],
- dst_blk_y + y_crop_blocks,
- (JDIMENSION)compptr->v_samp_factor, FALSE);
- }
- for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
- if (y_crop_blocks + dst_blk_y < comp_height) {
- /* Row is within the mirrorable area. */
- dst_row_ptr = dst_buffer[offset_y];
- src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1];
- src_row_ptr += x_crop_blocks;
- for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
- dst_blk_x++) {
- dst_ptr = dst_row_ptr[dst_blk_x];
- src_ptr = src_row_ptr[dst_blk_x];
- for (i = 0; i < DCTSIZE; i += 2) {
- /* copy even row */
- for (j = 0; j < DCTSIZE; j++)
- *dst_ptr++ = *src_ptr++;
- /* copy odd row with sign change */
- for (j = 0; j < DCTSIZE; j++)
- *dst_ptr++ = -(*src_ptr++);
- }
- }
- } else {
- /* Just copy row verbatim. */
- jcopy_block_row(src_buffer[offset_y] + x_crop_blocks,
- dst_buffer[offset_y], compptr->width_in_blocks);
- }
- }
- }
- }
- }
- LOCAL(void)
- do_transpose(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
- JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
- jvirt_barray_ptr *src_coef_arrays,
- jvirt_barray_ptr *dst_coef_arrays)
- /* Transpose source into destination */
- {
- JDIMENSION dst_blk_x, dst_blk_y, x_crop_blocks, y_crop_blocks;
- int ci, i, j, offset_x, offset_y;
- JBLOCKARRAY src_buffer, dst_buffer;
- JCOEFPTR src_ptr, dst_ptr;
- jpeg_component_info *compptr;
- /* Transposing pixels within a block just requires transposing the
- * DCT coefficients.
- * Partial iMCUs at the edges require no special treatment; we simply
- * process all the available DCT blocks for every component.
- */
- for (ci = 0; ci < dstinfo->num_components; ci++) {
- compptr = dstinfo->comp_info + ci;
- x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
- y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
- for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
- dst_blk_y += compptr->v_samp_factor) {
- dst_buffer = (*srcinfo->mem->access_virt_barray)
- ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
- (JDIMENSION)compptr->v_samp_factor, TRUE);
- for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
- for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
- dst_blk_x += compptr->h_samp_factor) {
- src_buffer = (*srcinfo->mem->access_virt_barray)
- ((j_common_ptr)srcinfo, src_coef_arrays[ci],
- dst_blk_x + x_crop_blocks,
- (JDIMENSION)compptr->h_samp_factor, FALSE);
- for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
- dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
- src_ptr =
- src_buffer[offset_x][dst_blk_y + offset_y + y_crop_blocks];
- for (i = 0; i < DCTSIZE; i++)
- for (j = 0; j < DCTSIZE; j++)
- dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
- }
- }
- }
- }
- }
- }
- LOCAL(void)
- do_rot_90(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
- JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
- jvirt_barray_ptr *src_coef_arrays,
- jvirt_barray_ptr *dst_coef_arrays)
- /* 90 degree rotation is equivalent to
- * 1. Transposing the image;
- * 2. Horizontal mirroring.
- * These two steps are merged into a single processing routine.
- */
- {
- JDIMENSION MCU_cols, comp_width, dst_blk_x, dst_blk_y;
- JDIMENSION x_crop_blocks, y_crop_blocks;
- int ci, i, j, offset_x, offset_y;
- JBLOCKARRAY src_buffer, dst_buffer;
- JCOEFPTR src_ptr, dst_ptr;
- jpeg_component_info *compptr;
- /* Because of the horizontal mirror step, we can't process partial iMCUs
- * at the (output) right edge properly. They just get transposed and
- * not mirrored.
- */
- MCU_cols = srcinfo->output_height /
- (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
- for (ci = 0; ci < dstinfo->num_components; ci++) {
- compptr = dstinfo->comp_info + ci;
- comp_width = MCU_cols * compptr->h_samp_factor;
- x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
- y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
- for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
- dst_blk_y += compptr->v_samp_factor) {
- dst_buffer = (*srcinfo->mem->access_virt_barray)
- ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
- (JDIMENSION)compptr->v_samp_factor, TRUE);
- for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
- for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
- dst_blk_x += compptr->h_samp_factor) {
- if (x_crop_blocks + dst_blk_x < comp_width) {
- /* Block is within the mirrorable area. */
- src_buffer = (*srcinfo->mem->access_virt_barray)
- ((j_common_ptr)srcinfo, src_coef_arrays[ci],
- comp_width - x_crop_blocks - dst_blk_x -
- (JDIMENSION)compptr->h_samp_factor,
- (JDIMENSION)compptr->h_samp_factor, FALSE);
- } else {
- /* Edge blocks are transposed but not mirrored. */
- src_buffer = (*srcinfo->mem->access_virt_barray)
- ((j_common_ptr)srcinfo, src_coef_arrays[ci],
- dst_blk_x + x_crop_blocks,
- (JDIMENSION)compptr->h_samp_factor, FALSE);
- }
- for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
- dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
- if (x_crop_blocks + dst_blk_x < comp_width) {
- /* Block is within the mirrorable area. */
- src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1]
- [dst_blk_y + offset_y + y_crop_blocks];
- for (i = 0; i < DCTSIZE; i++) {
- for (j = 0; j < DCTSIZE; j++)
- dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
- i++;
- for (j = 0; j < DCTSIZE; j++)
- dst_ptr[j * DCTSIZE + i] = -src_ptr[i * DCTSIZE + j];
- }
- } else {
- /* Edge blocks are transposed but not mirrored. */
- src_ptr = src_buffer[offset_x]
- [dst_blk_y + offset_y + y_crop_blocks];
- for (i = 0; i < DCTSIZE; i++)
- for (j = 0; j < DCTSIZE; j++)
- dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
- }
- }
- }
- }
- }
- }
- }
- LOCAL(void)
- do_rot_270(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
- JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
- jvirt_barray_ptr *src_coef_arrays,
- jvirt_barray_ptr *dst_coef_arrays)
- /* 270 degree rotation is equivalent to
- * 1. Horizontal mirroring;
- * 2. Transposing the image.
- * These two steps are merged into a single processing routine.
- */
- {
- JDIMENSION MCU_rows, comp_height, dst_blk_x, dst_blk_y;
- JDIMENSION x_crop_blocks, y_crop_blocks;
- int ci, i, j, offset_x, offset_y;
- JBLOCKARRAY src_buffer, dst_buffer;
- JCOEFPTR src_ptr, dst_ptr;
- jpeg_component_info *compptr;
- /* Because of the horizontal mirror step, we can't process partial iMCUs
- * at the (output) bottom edge properly. They just get transposed and
- * not mirrored.
- */
- MCU_rows = srcinfo->output_width /
- (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
- for (ci = 0; ci < dstinfo->num_components; ci++) {
- compptr = dstinfo->comp_info + ci;
- comp_height = MCU_rows * compptr->v_samp_factor;
- x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
- y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
- for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
- dst_blk_y += compptr->v_samp_factor) {
- dst_buffer = (*srcinfo->mem->access_virt_barray)
- ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
- (JDIMENSION)compptr->v_samp_factor, TRUE);
- for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
- for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
- dst_blk_x += compptr->h_samp_factor) {
- src_buffer = (*srcinfo->mem->access_virt_barray)
- ((j_common_ptr)srcinfo, src_coef_arrays[ci],
- dst_blk_x + x_crop_blocks,
- (JDIMENSION)compptr->h_samp_factor, FALSE);
- for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
- dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
- if (y_crop_blocks + dst_blk_y < comp_height) {
- /* Block is within the mirrorable area. */
- src_ptr = src_buffer[offset_x]
- [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1];
- for (i = 0; i < DCTSIZE; i++) {
- for (j = 0; j < DCTSIZE; j++) {
- dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
- j++;
- dst_ptr[j * DCTSIZE + i] = -src_ptr[i * DCTSIZE + j];
- }
- }
- } else {
- /* Edge blocks are transposed but not mirrored. */
- src_ptr = src_buffer[offset_x]
- [dst_blk_y + offset_y + y_crop_blocks];
- for (i = 0; i < DCTSIZE; i++)
- for (j = 0; j < DCTSIZE; j++)
- dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
- }
- }
- }
- }
- }
- }
- }
- LOCAL(void)
- do_rot_180(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
- JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
- jvirt_barray_ptr *src_coef_arrays,
- jvirt_barray_ptr *dst_coef_arrays)
- /* 180 degree rotation is equivalent to
- * 1. Vertical mirroring;
- * 2. Horizontal mirroring.
- * These two steps are merged into a single processing routine.
- */
- {
- JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y;
- JDIMENSION x_crop_blocks, y_crop_blocks;
- int ci, i, j, offset_y;
- JBLOCKARRAY src_buffer, dst_buffer;
- JBLOCKROW src_row_ptr, dst_row_ptr;
- JCOEFPTR src_ptr, dst_ptr;
- jpeg_component_info *compptr;
- MCU_cols = srcinfo->output_width /
- (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
- MCU_rows = srcinfo->output_height /
- (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
- for (ci = 0; ci < dstinfo->num_components; ci++) {
- compptr = dstinfo->comp_info + ci;
- comp_width = MCU_cols * compptr->h_samp_factor;
- comp_height = MCU_rows * compptr->v_samp_factor;
- x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
- y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
- for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
- dst_blk_y += compptr->v_samp_factor) {
- dst_buffer = (*srcinfo->mem->access_virt_barray)
- ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
- (JDIMENSION)compptr->v_samp_factor, TRUE);
- if (y_crop_blocks + dst_blk_y < comp_height) {
- /* Row is within the vertically mirrorable area. */
- src_buffer = (*srcinfo->mem->access_virt_barray)
- ((j_common_ptr)srcinfo, src_coef_arrays[ci],
- comp_height - y_crop_blocks - dst_blk_y -
- (JDIMENSION)compptr->v_samp_factor,
- (JDIMENSION)compptr->v_samp_factor, FALSE);
- } else {
- /* Bottom-edge rows are only mirrored horizontally. */
- src_buffer = (*srcinfo->mem->access_virt_barray)
- ((j_common_ptr)srcinfo, src_coef_arrays[ci],
- dst_blk_y + y_crop_blocks,
- (JDIMENSION)compptr->v_samp_factor, FALSE);
- }
- for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
- dst_row_ptr = dst_buffer[offset_y];
- if (y_crop_blocks + dst_blk_y < comp_height) {
- /* Row is within the mirrorable area. */
- src_row_ptr = src_buffer[compptr->v_samp_factor - offset_y - 1];
- for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
- dst_blk_x++) {
- dst_ptr = dst_row_ptr[dst_blk_x];
- if (x_crop_blocks + dst_blk_x < comp_width) {
- /* Process the blocks that can be mirrored both ways. */
- src_ptr =
- src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
- for (i = 0; i < DCTSIZE; i += 2) {
- /* For even row, negate every odd column. */
- for (j = 0; j < DCTSIZE; j += 2) {
- *dst_ptr++ = *src_ptr++;
- *dst_ptr++ = -(*src_ptr++);
- }
- /* For odd row, negate every even column. */
- for (j = 0; j < DCTSIZE; j += 2) {
- *dst_ptr++ = -(*src_ptr++);
- *dst_ptr++ = *src_ptr++;
- }
- }
- } else {
- /* Any remaining right-edge blocks are only mirrored vertically. */
- src_ptr = src_row_ptr[x_crop_blocks + dst_blk_x];
- for (i = 0; i < DCTSIZE; i += 2) {
- for (j = 0; j < DCTSIZE; j++)
- *dst_ptr++ = *src_ptr++;
- for (j = 0; j < DCTSIZE; j++)
- *dst_ptr++ = -(*src_ptr++);
- }
- }
- }
- } else {
- /* Remaining rows are just mirrored horizontally. */
- src_row_ptr = src_buffer[offset_y];
- for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
- dst_blk_x++) {
- if (x_crop_blocks + dst_blk_x < comp_width) {
- /* Process the blocks that can be mirrored. */
- dst_ptr = dst_row_ptr[dst_blk_x];
- src_ptr =
- src_row_ptr[comp_width - x_crop_blocks - dst_blk_x - 1];
- for (i = 0; i < DCTSIZE2; i += 2) {
- *dst_ptr++ = *src_ptr++;
- *dst_ptr++ = -(*src_ptr++);
- }
- } else {
- /* Any remaining right-edge blocks are only copied. */
- jcopy_block_row(src_row_ptr + dst_blk_x + x_crop_blocks,
- dst_row_ptr + dst_blk_x, (JDIMENSION)1);
- }
- }
- }
- }
- }
- }
- }
- LOCAL(void)
- do_transverse(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
- JDIMENSION x_crop_offset, JDIMENSION y_crop_offset,
- jvirt_barray_ptr *src_coef_arrays,
- jvirt_barray_ptr *dst_coef_arrays)
- /* Transverse transpose is equivalent to
- * 1. 180 degree rotation;
- * 2. Transposition;
- * or
- * 1. Horizontal mirroring;
- * 2. Transposition;
- * 3. Horizontal mirroring.
- * These steps are merged into a single processing routine.
- */
- {
- JDIMENSION MCU_cols, MCU_rows, comp_width, comp_height, dst_blk_x, dst_blk_y;
- JDIMENSION x_crop_blocks, y_crop_blocks;
- int ci, i, j, offset_x, offset_y;
- JBLOCKARRAY src_buffer, dst_buffer;
- JCOEFPTR src_ptr, dst_ptr;
- jpeg_component_info *compptr;
- MCU_cols = srcinfo->output_height /
- (dstinfo->max_h_samp_factor * dstinfo_min_DCT_h_scaled_size);
- MCU_rows = srcinfo->output_width /
- (dstinfo->max_v_samp_factor * dstinfo_min_DCT_v_scaled_size);
- for (ci = 0; ci < dstinfo->num_components; ci++) {
- compptr = dstinfo->comp_info + ci;
- comp_width = MCU_cols * compptr->h_samp_factor;
- comp_height = MCU_rows * compptr->v_samp_factor;
- x_crop_blocks = x_crop_offset * compptr->h_samp_factor;
- y_crop_blocks = y_crop_offset * compptr->v_samp_factor;
- for (dst_blk_y = 0; dst_blk_y < compptr->height_in_blocks;
- dst_blk_y += compptr->v_samp_factor) {
- dst_buffer = (*srcinfo->mem->access_virt_barray)
- ((j_common_ptr)srcinfo, dst_coef_arrays[ci], dst_blk_y,
- (JDIMENSION)compptr->v_samp_factor, TRUE);
- for (offset_y = 0; offset_y < compptr->v_samp_factor; offset_y++) {
- for (dst_blk_x = 0; dst_blk_x < compptr->width_in_blocks;
- dst_blk_x += compptr->h_samp_factor) {
- if (x_crop_blocks + dst_blk_x < comp_width) {
- /* Block is within the mirrorable area. */
- src_buffer = (*srcinfo->mem->access_virt_barray)
- ((j_common_ptr)srcinfo, src_coef_arrays[ci],
- comp_width - x_crop_blocks - dst_blk_x -
- (JDIMENSION)compptr->h_samp_factor,
- (JDIMENSION)compptr->h_samp_factor, FALSE);
- } else {
- src_buffer = (*srcinfo->mem->access_virt_barray)
- ((j_common_ptr)srcinfo, src_coef_arrays[ci],
- dst_blk_x + x_crop_blocks,
- (JDIMENSION)compptr->h_samp_factor, FALSE);
- }
- for (offset_x = 0; offset_x < compptr->h_samp_factor; offset_x++) {
- dst_ptr = dst_buffer[offset_y][dst_blk_x + offset_x];
- if (y_crop_blocks + dst_blk_y < comp_height) {
- if (x_crop_blocks + dst_blk_x < comp_width) {
- /* Block is within the mirrorable area. */
- src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1]
- [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1];
- for (i = 0; i < DCTSIZE; i++) {
- for (j = 0; j < DCTSIZE; j++) {
- dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
- j++;
- dst_ptr[j * DCTSIZE + i] = -src_ptr[i * DCTSIZE + j];
- }
- i++;
- for (j = 0; j < DCTSIZE; j++) {
- dst_ptr[j * DCTSIZE + i] = -src_ptr[i * DCTSIZE + j];
- j++;
- dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
- }
- }
- } else {
- /* Right-edge blocks are mirrored in y only */
- src_ptr = src_buffer[offset_x]
- [comp_height - y_crop_blocks - dst_blk_y - offset_y - 1];
- for (i = 0; i < DCTSIZE; i++) {
- for (j = 0; j < DCTSIZE; j++) {
- dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
- j++;
- dst_ptr[j * DCTSIZE + i] = -src_ptr[i * DCTSIZE + j];
- }
- }
- }
- } else {
- if (x_crop_blocks + dst_blk_x < comp_width) {
- /* Bottom-edge blocks are mirrored in x only */
- src_ptr = src_buffer[compptr->h_samp_factor - offset_x - 1]
- [dst_blk_y + offset_y + y_crop_blocks];
- for (i = 0; i < DCTSIZE; i++) {
- for (j = 0; j < DCTSIZE; j++)
- dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
- i++;
- for (j = 0; j < DCTSIZE; j++)
- dst_ptr[j * DCTSIZE + i] = -src_ptr[i * DCTSIZE + j];
- }
- } else {
- /* At lower right corner, just transpose, no mirroring */
- src_ptr = src_buffer[offset_x]
- [dst_blk_y + offset_y + y_crop_blocks];
- for (i = 0; i < DCTSIZE; i++)
- for (j = 0; j < DCTSIZE; j++)
- dst_ptr[j * DCTSIZE + i] = src_ptr[i * DCTSIZE + j];
- }
- }
- }
- }
- }
- }
- }
- }
- /* Parse an unsigned integer: subroutine for jtransform_parse_crop_spec.
- * Returns TRUE if valid integer found, FALSE if not.
- * *strptr is advanced over the digit string, and *result is set to its value.
- */
- LOCAL(boolean)
- jt_read_integer(const char **strptr, JDIMENSION *result)
- {
- const char *ptr = *strptr;
- JDIMENSION val = 0;
- for (; isdigit(*ptr); ptr++) {
- val = val * 10 + (JDIMENSION)(*ptr - '0');
- }
- *result = val;
- if (ptr == *strptr)
- return FALSE; /* oops, no digits */
- *strptr = ptr;
- return TRUE;
- }
- /* Parse a crop specification (written in X11 geometry style).
- * The routine returns TRUE if the spec string is valid, FALSE if not.
- *
- * The crop spec string should have the format
- * <width>[{fr}]x<height>[{fr}]{+-}<xoffset>{+-}<yoffset>
- * where width, height, xoffset, and yoffset are unsigned integers.
- * Each of the elements can be omitted to indicate a default value.
- * (A weakness of this style is that it is not possible to omit xoffset
- * while specifying yoffset, since they look alike.)
- *
- * This code is loosely based on XParseGeometry from the X11 distribution.
- */
- GLOBAL(boolean)
- jtransform_parse_crop_spec(jpeg_transform_info *info, const char *spec)
- {
- info->crop = FALSE;
- info->crop_width_set = JCROP_UNSET;
- info->crop_height_set = JCROP_UNSET;
- info->crop_xoffset_set = JCROP_UNSET;
- info->crop_yoffset_set = JCROP_UNSET;
- if (isdigit(*spec)) {
- /* fetch width */
- if (!jt_read_integer(&spec, &info->crop_width))
- return FALSE;
- if (*spec == 'f' || *spec == 'F') {
- spec++;
- info->crop_width_set = JCROP_FORCE;
- } else if (*spec == 'r' || *spec == 'R') {
- spec++;
- info->crop_width_set = JCROP_REFLECT;
- } else
- info->crop_width_set = JCROP_POS;
- }
- if (*spec == 'x' || *spec == 'X') {
- /* fetch height */
- spec++;
- if (!jt_read_integer(&spec, &info->crop_height))
- return FALSE;
- if (*spec == 'f' || *spec == 'F') {
- spec++;
- info->crop_height_set = JCROP_FORCE;
- } else if (*spec == 'r' || *spec == 'R') {
- spec++;
- info->crop_height_set = JCROP_REFLECT;
- } else
- info->crop_height_set = JCROP_POS;
- }
- if (*spec == '+' || *spec == '-') {
- /* fetch xoffset */
- info->crop_xoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS;
- spec++;
- if (!jt_read_integer(&spec, &info->crop_xoffset))
- return FALSE;
- }
- if (*spec == '+' || *spec == '-') {
- /* fetch yoffset */
- info->crop_yoffset_set = (*spec == '-') ? JCROP_NEG : JCROP_POS;
- spec++;
- if (!jt_read_integer(&spec, &info->crop_yoffset))
- return FALSE;
- }
- /* We had better have gotten to the end of the string. */
- if (*spec != '\0')
- return FALSE;
- info->crop = TRUE;
- return TRUE;
- }
- /* Trim off any partial iMCUs on the indicated destination edge */
- LOCAL(void)
- trim_right_edge(jpeg_transform_info *info, JDIMENSION full_width)
- {
- JDIMENSION MCU_cols;
- MCU_cols = info->output_width / info->iMCU_sample_width;
- if (MCU_cols > 0 && info->x_crop_offset + MCU_cols ==
- full_width / info->iMCU_sample_width)
- info->output_width = MCU_cols * info->iMCU_sample_width;
- }
- LOCAL(void)
- trim_bottom_edge(jpeg_transform_info *info, JDIMENSION full_height)
- {
- JDIMENSION MCU_rows;
- MCU_rows = info->output_height / info->iMCU_sample_height;
- if (MCU_rows > 0 && info->y_crop_offset + MCU_rows ==
- full_height / info->iMCU_sample_height)
- info->output_height = MCU_rows * info->iMCU_sample_height;
- }
- /* Request any required workspace.
- *
- * This routine figures out the size that the output image will be
- * (which implies that all the transform parameters must be set before
- * it is called).
- *
- * We allocate the workspace virtual arrays from the source decompression
- * object, so that all the arrays (both the original data and the workspace)
- * will be taken into account while making memory management decisions.
- * Hence, this routine must be called after jpeg_read_header (which reads
- * the image dimensions) and before jpeg_read_coefficients (which realizes
- * the source's virtual arrays).
- *
- * This function returns FALSE right away if -perfect is given
- * and transformation is not perfect. Otherwise returns TRUE.
- */
- GLOBAL(boolean)
- jtransform_request_workspace(j_decompress_ptr srcinfo,
- jpeg_transform_info *info)
- {
- jvirt_barray_ptr *coef_arrays;
- boolean need_workspace, transpose_it;
- jpeg_component_info *compptr;
- JDIMENSION xoffset, yoffset, dtemp;
- JDIMENSION width_in_iMCUs, height_in_iMCUs;
- JDIMENSION width_in_blocks, height_in_blocks;
- int itemp, ci, h_samp_factor, v_samp_factor;
- /* Determine number of components in output image */
- if (info->force_grayscale &&
- srcinfo->jpeg_color_space == JCS_YCbCr &&
- srcinfo->num_components == 3)
- /* We'll only process the first component */
- info->num_components = 1;
- else
- /* Process all the components */
- info->num_components = srcinfo->num_components;
- /* Compute output image dimensions and related values. */
- #if JPEG_LIB_VERSION >= 80
- jpeg_core_output_dimensions(srcinfo);
- #else
- srcinfo->output_width = srcinfo->image_width;
- srcinfo->output_height = srcinfo->image_height;
- #endif
- /* Return right away if -perfect is given and transformation is not perfect.
- */
- if (info->perfect) {
- if (info->num_components == 1) {
- if (!jtransform_perfect_transform(srcinfo->output_width,
- srcinfo->output_height,
- srcinfo->_min_DCT_h_scaled_size,
- srcinfo->_min_DCT_v_scaled_size,
- info->transform))
- return FALSE;
- } else {
- if (!jtransform_perfect_transform(srcinfo->output_width,
- srcinfo->output_height,
- srcinfo->max_h_samp_factor * srcinfo->_min_DCT_h_scaled_size,
- srcinfo->max_v_samp_factor * srcinfo->_min_DCT_v_scaled_size,
- info->transform))
- return FALSE;
- }
- }
- /* If there is only one output component, force the iMCU size to be 1;
- * else use the source iMCU size. (This allows us to do the right thing
- * when reducing color to grayscale, and also provides a handy way of
- * cleaning up "funny" grayscale images whose sampling factors are not 1x1.)
- */
- switch (info->transform) {
- case JXFORM_TRANSPOSE:
- case JXFORM_TRANSVERSE:
- case JXFORM_ROT_90:
- case JXFORM_ROT_270:
- info->output_width = srcinfo->output_height;
- info->output_height = srcinfo->output_width;
- if (info->num_components == 1) {
- info->iMCU_sample_width = srcinfo->_min_DCT_v_scaled_size;
- info->iMCU_sample_height = srcinfo->_min_DCT_h_scaled_size;
- } else {
- info->iMCU_sample_width =
- srcinfo->max_v_samp_factor * srcinfo->_min_DCT_v_scaled_size;
- info->iMCU_sample_height =
- srcinfo->max_h_samp_factor * srcinfo->_min_DCT_h_scaled_size;
- }
- break;
- default:
- info->output_width = srcinfo->output_width;
- info->output_height = srcinfo->output_height;
- if (info->num_components == 1) {
- info->iMCU_sample_width = srcinfo->_min_DCT_h_scaled_size;
- info->iMCU_sample_height = srcinfo->_min_DCT_v_scaled_size;
- } else {
- info->iMCU_sample_width =
- srcinfo->max_h_samp_factor * srcinfo->_min_DCT_h_scaled_size;
- info->iMCU_sample_height =
- srcinfo->max_v_samp_factor * srcinfo->_min_DCT_v_scaled_size;
- }
- break;
- }
- /* If cropping has been requested, compute the crop area's position and
- * dimensions, ensuring that its upper left corner falls at an iMCU boundary.
- */
- if (info->crop) {
- /* Insert default values for unset crop parameters */
- if (info->crop_xoffset_set == JCROP_UNSET)
- info->crop_xoffset = 0; /* default to +0 */
- if (info->crop_yoffset_set == JCROP_UNSET)
- info->crop_yoffset = 0; /* default to +0 */
- if (info->crop_width_set == JCROP_UNSET) {
- if (info->crop_xoffset >= info->output_width)
- ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
- info->crop_width = info->output_width - info->crop_xoffset;
- } else {
- /* Check for crop extension */
- if (info->crop_width > info->output_width) {
- /* Crop extension does not work when transforming! */
- if (info->transform != JXFORM_NONE ||
- info->crop_xoffset >= info->crop_width ||
- info->crop_xoffset > info->crop_width - info->output_width)
- ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
- } else {
- if (info->crop_xoffset >= info->output_width ||
- info->crop_width <= 0 ||
- info->crop_xoffset > info->output_width - info->crop_width)
- ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
- }
- }
- if (info->crop_height_set == JCROP_UNSET) {
- if (info->crop_yoffset >= info->output_height)
- ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
- info->crop_height = info->output_height - info->crop_yoffset;
- } else {
- /* Check for crop extension */
- if (info->crop_height > info->output_height) {
- /* Crop extension does not work when transforming! */
- if (info->transform != JXFORM_NONE ||
- info->crop_yoffset >= info->crop_height ||
- info->crop_yoffset > info->crop_height - info->output_height)
- ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
- } else {
- if (info->crop_yoffset >= info->output_height ||
- info->crop_height <= 0 ||
- info->crop_yoffset > info->output_height - info->crop_height)
- ERREXIT(srcinfo, JERR_BAD_CROP_SPEC);
- }
- }
- /* Convert negative crop offsets into regular offsets */
- if (info->crop_xoffset_set != JCROP_NEG)
- xoffset = info->crop_xoffset;
- else if (info->crop_width > info->output_width) /* crop extension */
- xoffset = info->crop_width - info->output_width - info->crop_xoffset;
- else
- xoffset = info->output_width - info->crop_width - info->crop_xoffset;
- if (info->crop_yoffset_set != JCROP_NEG)
- yoffset = info->crop_yoffset;
- else if (info->crop_height > info->output_height) /* crop extension */
- yoffset = info->crop_height - info->output_height - info->crop_yoffset;
- else
- yoffset = info->output_height - info->crop_height - info->crop_yoffset;
- /* Now adjust so that upper left corner falls at an iMCU boundary */
- switch (info->transform) {
- case JXFORM_DROP:
- /* Ensure the effective drop region will not exceed the requested */
- itemp = info->iMCU_sample_width;
- dtemp = itemp - 1 - ((xoffset + itemp - 1) % itemp);
- xoffset += dtemp;
- if (info->crop_width <= dtemp)
- info->drop_width = 0;
- else if (xoffset + info->crop_width - dtemp == info->output_width)
- /* Matching right edge: include partial iMCU */
- info->drop_width = (info->crop_width - dtemp + itemp - 1) / itemp;
- else
- info->drop_width = (info->crop_width - dtemp) / itemp;
- itemp = info->iMCU_sample_height;
- dtemp = itemp - 1 - ((yoffset + itemp - 1) % itemp);
- yoffset += dtemp;
- if (info->crop_height <= dtemp)
- info->drop_height = 0;
- else if (yoffset + info->crop_height - dtemp == info->output_height)
- /* Matching bottom edge: include partial iMCU */
- info->drop_height = (info->crop_height - dtemp + itemp - 1) / itemp;
- else
- info->drop_height = (info->crop_height - dtemp) / itemp;
- /* Check if sampling factors match for dropping */
- if (info->drop_width != 0 && info->drop_height != 0)
- for (ci = 0; ci < info->num_components &&
- ci < info->drop_ptr->num_components; ci++) {
- if (info->drop_ptr->comp_info[ci].h_samp_factor *
- srcinfo->max_h_samp_factor !=
- srcinfo->comp_info[ci].h_samp_factor *
- info->drop_ptr->max_h_samp_factor)
- ERREXIT6(srcinfo, JERR_BAD_DROP_SAMPLING, ci,
- info->drop_ptr->comp_info[ci].h_samp_factor,
- info->drop_ptr->max_h_samp_factor,
- srcinfo->comp_info[ci].h_samp_factor,
- srcinfo->max_h_samp_factor, 'h');
- if (info->drop_ptr->comp_info[ci].v_samp_factor *
- srcinfo->max_v_samp_factor !=
- srcinfo->comp_info[ci].v_samp_factor *
- info->drop_ptr->max_v_samp_factor)
- ERREXIT6(srcinfo, JERR_BAD_DROP_SAMPLING, ci,
- info->drop_ptr->comp_info[ci].v_samp_factor,
- info->drop_ptr->max_v_samp_factor,
- srcinfo->comp_info[ci].v_samp_factor,
- srcinfo->max_v_samp_factor, 'v');
- }
- break;
- case JXFORM_WIPE:
- /* Ensure the effective wipe region will cover the requested */
- info->drop_width = (JDIMENSION)jdiv_round_up
- ((long)(info->crop_width + (xoffset % info->iMCU_sample_width)),
- (long)info->iMCU_sample_width);
- info->drop_height = (JDIMENSION)jdiv_round_up
- ((long)(info->crop_height + (yoffset % info->iMCU_sample_height)),
- (long)info->iMCU_sample_height);
- break;
- default:
- /* Ensure the effective crop region will cover the requested */
- if (info->crop_width_set == JCROP_FORCE ||
- info->crop_width > info->output_width)
- info->output_width = info->crop_width;
- else
- info->output_width =
- info->crop_width + (xoffset % info->iMCU_sample_width);
- if (info->crop_height_set == JCROP_FORCE ||
- info->crop_height > info->output_height)
- info->output_height = info->crop_height;
- else
- info->output_height =
- info->crop_height + (yoffset % info->iMCU_sample_height);
- }
- /* Save x/y offsets measured in iMCUs */
- info->x_crop_offset = xoffset / info->iMCU_sample_width;
- info->y_crop_offset = yoffset / info->iMCU_sample_height;
- } else {
- info->x_crop_offset = 0;
- info->y_crop_offset = 0;
- }
- /* Figure out whether we need workspace arrays,
- * and if so whether they are transposed relative to the source.
- */
- need_workspace = FALSE;
- transpose_it = FALSE;
- switch (info->transform) {
- case JXFORM_NONE:
- if (info->x_crop_offset != 0 || info->y_crop_offset != 0 ||
- info->output_width > srcinfo->output_width ||
- info->output_height > srcinfo->output_height)
- need_workspace = TRUE;
- /* No workspace needed if neither cropping nor transforming */
- break;
- case JXFORM_FLIP_H:
- if (info->trim)
- trim_right_edge(info, srcinfo->output_width);
- if (info->y_crop_offset != 0 || info->slow_hflip)
- need_workspace = TRUE;
- /* do_flip_h_no_crop doesn't need a workspace array */
- break;
- case JXFORM_FLIP_V:
- if (info->trim)
- trim_bottom_edge(info, srcinfo->output_height);
- /* Need workspace arrays having same dimensions as source image. */
- need_workspace = TRUE;
- break;
- case JXFORM_TRANSPOSE:
- /* transpose does NOT have to trim anything */
- /* Need workspace arrays having transposed dimensions. */
- need_workspace = TRUE;
- transpose_it = TRUE;
- break;
- case JXFORM_TRANSVERSE:
- if (info->trim) {
- trim_right_edge(info, srcinfo->output_height);
- trim_bottom_edge(info, srcinfo->output_width);
- }
- /* Need workspace arrays having transposed dimensions. */
- need_workspace = TRUE;
- transpose_it = TRUE;
- break;
- case JXFORM_ROT_90:
- if (info->trim)
- trim_right_edge(info, srcinfo->output_height);
- /* Need workspace arrays having transposed dimensions. */
- need_workspace = TRUE;
- transpose_it = TRUE;
- break;
- case JXFORM_ROT_180:
- if (info->trim) {
- trim_right_edge(info, srcinfo->output_width);
- trim_bottom_edge(info, srcinfo->output_height);
- }
- /* Need workspace arrays having same dimensions as source image. */
- need_workspace = TRUE;
- break;
- case JXFORM_ROT_270:
- if (info->trim)
- trim_bottom_edge(info, srcinfo->output_width);
- /* Need workspace arrays having transposed dimensions. */
- need_workspace = TRUE;
- transpose_it = TRUE;
- break;
- case JXFORM_WIPE:
- break;
- case JXFORM_DROP:
- break;
- }
- /* Allocate workspace if needed.
- * Note that we allocate arrays padded out to the next iMCU boundary,
- * so that transform routines need not worry about missing edge blocks.
- */
- if (need_workspace) {
- coef_arrays = (jvirt_barray_ptr *)
- (*srcinfo->mem->alloc_small) ((j_common_ptr)srcinfo, JPOOL_IMAGE,
- sizeof(jvirt_barray_ptr) * info->num_components);
- width_in_iMCUs = (JDIMENSION)
- jdiv_round_up((long)info->output_width, (long)info->iMCU_sample_width);
- height_in_iMCUs = (JDIMENSION)
- jdiv_round_up((long)info->output_height, (long)info->iMCU_sample_height);
- for (ci = 0; ci < info->num_components; ci++) {
- compptr = srcinfo->comp_info + ci;
- if (info->num_components == 1) {
- /* we're going to force samp factors to 1x1 in this case */
- h_samp_factor = v_samp_factor = 1;
- } else if (transpose_it) {
- h_samp_factor = compptr->v_samp_factor;
- v_samp_factor = compptr->h_samp_factor;
- } else {
- h_samp_factor = compptr->h_samp_factor;
- v_samp_factor = compptr->v_samp_factor;
- }
- width_in_blocks = width_in_iMCUs * h_samp_factor;
- height_in_blocks = height_in_iMCUs * v_samp_factor;
- coef_arrays[ci] = (*srcinfo->mem->request_virt_barray)
- ((j_common_ptr)srcinfo, JPOOL_IMAGE, FALSE,
- width_in_blocks, height_in_blocks, (JDIMENSION)v_samp_factor);
- }
- info->workspace_coef_arrays = coef_arrays;
- } else
- info->workspace_coef_arrays = NULL;
- return TRUE;
- }
- /* Transpose destination image parameters */
- LOCAL(void)
- transpose_critical_parameters(j_compress_ptr dstinfo)
- {
- int tblno, i, j, ci, itemp;
- jpeg_component_info *compptr;
- JQUANT_TBL *qtblptr;
- JDIMENSION jtemp;
- UINT16 qtemp;
- /* Transpose image dimensions */
- jtemp = dstinfo->image_width;
- dstinfo->image_width = dstinfo->image_height;
- dstinfo->image_height = jtemp;
- #if JPEG_LIB_VERSION >= 70
- itemp = dstinfo->min_DCT_h_scaled_size;
- dstinfo->min_DCT_h_scaled_size = dstinfo->min_DCT_v_scaled_size;
- dstinfo->min_DCT_v_scaled_size = itemp;
- #endif
- /* Transpose sampling factors */
- for (ci = 0; ci < dstinfo->num_components; ci++) {
- compptr = dstinfo->comp_info + ci;
- itemp = compptr->h_samp_factor;
- compptr->h_samp_factor = compptr->v_samp_factor;
- compptr->v_samp_factor = itemp;
- }
- /* Transpose quantization tables */
- for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) {
- qtblptr = dstinfo->quant_tbl_ptrs[tblno];
- if (qtblptr != NULL) {
- for (i = 0; i < DCTSIZE; i++) {
- for (j = 0; j < i; j++) {
- qtemp = qtblptr->quantval[i * DCTSIZE + j];
- qtblptr->quantval[i * DCTSIZE + j] =
- qtblptr->quantval[j * DCTSIZE + i];
- qtblptr->quantval[j * DCTSIZE + i] = qtemp;
- }
- }
- }
- }
- }
- /* Adjust Exif image parameters.
- *
- * We try to adjust the Tags ExifImageWidth and ExifImageHeight if possible.
- */
- LOCAL(void)
- adjust_exif_parameters(JOCTET *data, unsigned int length, JDIMENSION new_width,
- JDIMENSION new_height)
- {
- boolean is_motorola; /* Flag for byte order */
- unsigned int number_of_tags, tagnum;
- unsigned int firstoffset, offset;
- JDIMENSION new_value;
- if (length < 12) return; /* Length of an IFD entry */
- /* Discover byte order */
- if (data[0] == 0x49 && data[1] == 0x49)
- is_motorola = FALSE;
- else if (data[0] == 0x4D && data[1] == 0x4D)
- is_motorola = TRUE;
- else
- return;
- /* Check Tag Mark */
- if (is_motorola) {
- if (data[2] != 0) return;
- if (data[3] != 0x2A) return;
- } else {
- if (data[3] != 0) return;
- if (data[2] != 0x2A) return;
- }
- /* Get first IFD offset (offset to IFD0) */
- if (is_motorola) {
- if (data[4] != 0) return;
- if (data[5] != 0) return;
- firstoffset = data[6];
- firstoffset <<= 8;
- firstoffset += data[7];
- } else {
- if (data[7] != 0) return;
- if (data[6] != 0) return;
- firstoffset = data[5];
- firstoffset <<= 8;
- firstoffset += data[4];
- }
- if (firstoffset > length - 2) return; /* check end of data segment */
- /* Get the number of directory entries contained in this IFD */
- if (is_motorola) {
- number_of_tags = data[firstoffset];
- number_of_tags <<= 8;
- number_of_tags += data[firstoffset + 1];
- } else {
- number_of_tags = data[firstoffset + 1];
- number_of_tags <<= 8;
- number_of_tags += data[firstoffset];
- }
- if (number_of_tags == 0) return;
- firstoffset += 2;
- /* Search for ExifSubIFD offset Tag in IFD0 */
- for (;;) {
- if (firstoffset > length - 12) return; /* check end of data segment */
- /* Get Tag number */
- if (is_motorola) {
- tagnum = data[firstoffset];
- tagnum <<= 8;
- tagnum += data[firstoffset + 1];
- } else {
- tagnum = data[firstoffset + 1];
- tagnum <<= 8;
- tagnum += data[firstoffset];
- }
- if (tagnum == 0x8769) break; /* found ExifSubIFD offset Tag */
- if (--number_of_tags == 0) return;
- firstoffset += 12;
- }
- /* Get the ExifSubIFD offset */
- if (is_motorola) {
- if (data[firstoffset + 8] != 0) return;
- if (data[firstoffset + 9] != 0) return;
- offset = data[firstoffset + 10];
- offset <<= 8;
- offset += data[firstoffset + 11];
- } else {
- if (data[firstoffset + 11] != 0) return;
- if (data[firstoffset + 10] != 0) return;
- offset = data[firstoffset + 9];
- offset <<= 8;
- offset += data[firstoffset + 8];
- }
- if (offset > length - 2) return; /* check end of data segment */
- /* Get the number of directory entries contained in this SubIFD */
- if (is_motorola) {
- number_of_tags = data[offset];
- number_of_tags <<= 8;
- number_of_tags += data[offset + 1];
- } else {
- number_of_tags = data[offset + 1];
- number_of_tags <<= 8;
- number_of_tags += data[offset];
- }
- if (number_of_tags < 2) return;
- offset += 2;
- /* Search for ExifImageWidth and ExifImageHeight Tags in this SubIFD */
- do {
- if (offset > length - 12) return; /* check end of data segment */
- /* Get Tag number */
- if (is_motorola) {
- tagnum = data[offset];
- tagnum <<= 8;
- tagnum += data[offset + 1];
- } else {
- tagnum = data[offset + 1];
- tagnum <<= 8;
- tagnum += data[offset];
- }
- if (tagnum == 0xA002 || tagnum == 0xA003) {
- if (tagnum == 0xA002)
- new_value = new_width; /* ExifImageWidth Tag */
- else
- new_value = new_height; /* ExifImageHeight Tag */
- if (is_motorola) {
- data[offset + 2] = 0; /* Format = unsigned long (4 octets) */
- data[offset + 3] = 4;
- data[offset + 4] = 0; /* Number Of Components = 1 */
- data[offset + 5] = 0;
- data[offset + 6] = 0;
- data[offset + 7] = 1;
- data[offset + 8] = 0;
- data[offset + 9] = 0;
- data[offset + 10] = (JOCTET)((new_value >> 8) & 0xFF);
- data[offset + 11] = (JOCTET)(new_value & 0xFF);
- } else {
- data[offset + 2] = 4; /* Format = unsigned long (4 octets) */
- data[offset + 3] = 0;
- data[offset + 4] = 1; /* Number Of Components = 1 */
- data[offset + 5] = 0;
- data[offset + 6] = 0;
- data[offset + 7] = 0;
- data[offset + 8] = (JOCTET)(new_value & 0xFF);
- data[offset + 9] = (JOCTET)((new_value >> 8) & 0xFF);
- data[offset + 10] = 0;
- data[offset + 11] = 0;
- }
- }
- offset += 12;
- } while (--number_of_tags);
- }
- /* Adjust output image parameters as needed.
- *
- * This must be called after jpeg_copy_critical_parameters()
- * and before jpeg_write_coefficients().
- *
- * The return value is the set of virtual coefficient arrays to be written
- * (either the ones allocated by jtransform_request_workspace, or the
- * original source data arrays). The caller will need to pass this value
- * to jpeg_write_coefficients().
- */
- GLOBAL(jvirt_barray_ptr *)
- jtransform_adjust_parameters(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
- jvirt_barray_ptr *src_coef_arrays,
- jpeg_transform_info *info)
- {
- /* If force-to-grayscale is requested, adjust destination parameters */
- if (info->force_grayscale) {
- /* First, ensure we have YCbCr or grayscale data, and that the source's
- * Y channel is full resolution. (No reasonable person would make Y
- * be less than full resolution, so actually coping with that case
- * isn't worth extra code space. But we check it to avoid crashing.)
- */
- if (((dstinfo->jpeg_color_space == JCS_YCbCr &&
- dstinfo->num_components == 3) ||
- (dstinfo->jpeg_color_space == JCS_GRAYSCALE &&
- dstinfo->num_components == 1)) &&
- srcinfo->comp_info[0].h_samp_factor == srcinfo->max_h_samp_factor &&
- srcinfo->comp_info[0].v_samp_factor == srcinfo->max_v_samp_factor) {
- /* We use jpeg_set_colorspace to make sure subsidiary settings get fixed
- * properly. Among other things, it sets the target h_samp_factor &
- * v_samp_factor to 1, which typically won't match the source.
- * We have to preserve the source's quantization table number, however.
- */
- int sv_quant_tbl_no = dstinfo->comp_info[0].quant_tbl_no;
- jpeg_set_colorspace(dstinfo, JCS_GRAYSCALE);
- dstinfo->comp_info[0].quant_tbl_no = sv_quant_tbl_no;
- } else {
- /* Sorry, can't do it */
- ERREXIT(dstinfo, JERR_CONVERSION_NOTIMPL);
- }
- } else if (info->num_components == 1) {
- /* For a single-component source, we force the destination sampling factors
- * to 1x1, with or without force_grayscale. This is useful because some
- * decoders choke on grayscale images with other sampling factors.
- */
- dstinfo->comp_info[0].h_samp_factor = 1;
- dstinfo->comp_info[0].v_samp_factor = 1;
- }
- /* Correct the destination's image dimensions as necessary
- * for rotate/flip, resize, and crop operations.
- */
- #if JPEG_LIB_VERSION >= 80
- dstinfo->jpeg_width = info->output_width;
- dstinfo->jpeg_height = info->output_height;
- #endif
- /* Transpose destination image parameters, adjust quantization */
- switch (info->transform) {
- case JXFORM_TRANSPOSE:
- case JXFORM_TRANSVERSE:
- case JXFORM_ROT_90:
- case JXFORM_ROT_270:
- #if JPEG_LIB_VERSION < 80
- dstinfo->image_width = info->output_height;
- dstinfo->image_height = info->output_width;
- #endif
- transpose_critical_parameters(dstinfo);
- break;
- case JXFORM_DROP:
- if (info->drop_width != 0 && info->drop_height != 0)
- adjust_quant(srcinfo, src_coef_arrays,
- info->drop_ptr, info->drop_coef_arrays,
- info->trim, dstinfo);
- break;
- default:
- #if JPEG_LIB_VERSION < 80
- dstinfo->image_width = info->output_width;
- dstinfo->image_height = info->output_height;
- #endif
- break;
- }
- /* Adjust Exif properties */
- if (srcinfo->marker_list != NULL &&
- srcinfo->marker_list->marker == JPEG_APP0 + 1 &&
- srcinfo->marker_list->data_length >= 6 &&
- srcinfo->marker_list->data[0] == 0x45 &&
- srcinfo->marker_list->data[1] == 0x78 &&
- srcinfo->marker_list->data[2] == 0x69 &&
- srcinfo->marker_list->data[3] == 0x66 &&
- srcinfo->marker_list->data[4] == 0 &&
- srcinfo->marker_list->data[5] == 0) {
- /* Suppress output of JFIF marker */
- dstinfo->write_JFIF_header = FALSE;
- /* Adjust Exif image parameters */
- #if JPEG_LIB_VERSION >= 80
- if (dstinfo->jpeg_width != srcinfo->image_width ||
- dstinfo->jpeg_height != srcinfo->image_height)
- /* Align data segment to start of TIFF structure for parsing */
- adjust_exif_parameters(srcinfo->marker_list->data + 6,
- srcinfo->marker_list->data_length - 6,
- dstinfo->jpeg_width, dstinfo->jpeg_height);
- #else
- if (dstinfo->image_width != srcinfo->image_width ||
- dstinfo->image_height != srcinfo->image_height)
- /* Align data segment to start of TIFF structure for parsing */
- adjust_exif_parameters(srcinfo->marker_list->data + 6,
- srcinfo->marker_list->data_length - 6,
- dstinfo->image_width, dstinfo->image_height);
- #endif
- }
- /* Return the appropriate output data set */
- if (info->workspace_coef_arrays != NULL)
- return info->workspace_coef_arrays;
- return src_coef_arrays;
- }
- /* Execute the actual transformation, if any.
- *
- * This must be called *after* jpeg_write_coefficients, because it depends
- * on jpeg_write_coefficients to have computed subsidiary values such as
- * the per-component width and height fields in the destination object.
- *
- * Note that some transformations will modify the source data arrays!
- */
- GLOBAL(void)
- jtransform_execute_transform(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
- jvirt_barray_ptr *src_coef_arrays,
- jpeg_transform_info *info)
- {
- jvirt_barray_ptr *dst_coef_arrays = info->workspace_coef_arrays;
- /* Note: conditions tested here should match those in switch statement
- * in jtransform_request_workspace()
- */
- switch (info->transform) {
- case JXFORM_NONE:
- if (info->output_width > srcinfo->output_width ||
- info->output_height > srcinfo->output_height) {
- if (info->output_width > srcinfo->output_width &&
- info->crop_width_set == JCROP_REFLECT)
- do_crop_ext_reflect(srcinfo, dstinfo,
- info->x_crop_offset, info->y_crop_offset,
- src_coef_arrays, dst_coef_arrays);
- else if (info->output_width > srcinfo->output_width &&
- info->crop_width_set == JCROP_FORCE)
- do_crop_ext_flat(srcinfo, dstinfo,
- info->x_crop_offset, info->y_crop_offset,
- src_coef_arrays, dst_coef_arrays);
- else
- do_crop_ext_zero(srcinfo, dstinfo,
- info->x_crop_offset, info->y_crop_offset,
- src_coef_arrays, dst_coef_arrays);
- } else if (info->x_crop_offset != 0 || info->y_crop_offset != 0)
- do_crop(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
- src_coef_arrays, dst_coef_arrays);
- break;
- case JXFORM_FLIP_H:
- if (info->y_crop_offset != 0 || info->slow_hflip)
- do_flip_h(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
- src_coef_arrays, dst_coef_arrays);
- else
- do_flip_h_no_crop(srcinfo, dstinfo, info->x_crop_offset,
- src_coef_arrays);
- break;
- case JXFORM_FLIP_V:
- do_flip_v(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
- src_coef_arrays, dst_coef_arrays);
- break;
- case JXFORM_TRANSPOSE:
- do_transpose(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
- src_coef_arrays, dst_coef_arrays);
- break;
- case JXFORM_TRANSVERSE:
- do_transverse(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
- src_coef_arrays, dst_coef_arrays);
- break;
- case JXFORM_ROT_90:
- do_rot_90(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
- src_coef_arrays, dst_coef_arrays);
- break;
- case JXFORM_ROT_180:
- do_rot_180(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
- src_coef_arrays, dst_coef_arrays);
- break;
- case JXFORM_ROT_270:
- do_rot_270(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
- src_coef_arrays, dst_coef_arrays);
- break;
- case JXFORM_WIPE:
- if (info->crop_width_set == JCROP_REFLECT &&
- info->y_crop_offset == 0 && info->drop_height ==
- (JDIMENSION)jdiv_round_up
- ((long)info->output_height, (long)info->iMCU_sample_height) &&
- (info->x_crop_offset == 0 ||
- info->x_crop_offset + info->drop_width ==
- (JDIMENSION)jdiv_round_up
- ((long)info->output_width, (long)info->iMCU_sample_width)))
- do_reflect(srcinfo, dstinfo, info->x_crop_offset,
- src_coef_arrays, info->drop_width, info->drop_height);
- else if (info->crop_width_set == JCROP_FORCE)
- do_flatten(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
- src_coef_arrays, info->drop_width, info->drop_height);
- else
- do_wipe(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
- src_coef_arrays, info->drop_width, info->drop_height);
- break;
- case JXFORM_DROP:
- if (info->drop_width != 0 && info->drop_height != 0)
- do_drop(srcinfo, dstinfo, info->x_crop_offset, info->y_crop_offset,
- src_coef_arrays, info->drop_ptr, info->drop_coef_arrays,
- info->drop_width, info->drop_height);
- break;
- }
- }
- /* jtransform_perfect_transform
- *
- * Determine whether lossless transformation is perfectly
- * possible for a specified image and transformation.
- *
- * Inputs:
- * image_width, image_height: source image dimensions.
- * MCU_width, MCU_height: pixel dimensions of MCU.
- * transform: transformation identifier.
- * Parameter sources from initialized jpeg_struct
- * (after reading source header):
- * image_width = cinfo.image_width
- * image_height = cinfo.image_height
- * MCU_width = cinfo.max_h_samp_factor * cinfo.block_size
- * MCU_height = cinfo.max_v_samp_factor * cinfo.block_size
- * Result:
- * TRUE = perfect transformation possible
- * FALSE = perfect transformation not possible
- * (may use custom action then)
- */
- GLOBAL(boolean)
- jtransform_perfect_transform(JDIMENSION image_width, JDIMENSION image_height,
- int MCU_width, int MCU_height,
- JXFORM_CODE transform)
- {
- boolean result = TRUE; /* initialize TRUE */
- switch (transform) {
- case JXFORM_FLIP_H:
- case JXFORM_ROT_270:
- if (image_width % (JDIMENSION)MCU_width)
- result = FALSE;
- break;
- case JXFORM_FLIP_V:
- case JXFORM_ROT_90:
- if (image_height % (JDIMENSION)MCU_height)
- result = FALSE;
- break;
- case JXFORM_TRANSVERSE:
- case JXFORM_ROT_180:
- if (image_width % (JDIMENSION)MCU_width)
- result = FALSE;
- if (image_height % (JDIMENSION)MCU_height)
- result = FALSE;
- break;
- default:
- break;
- }
- return result;
- }
- #endif /* TRANSFORMS_SUPPORTED */
- /* Setup decompression object to save desired markers in memory.
- * This must be called before jpeg_read_header() to have the desired effect.
- */
- GLOBAL(void)
- jcopy_markers_setup(j_decompress_ptr srcinfo, JCOPY_OPTION option)
- {
- #ifdef SAVE_MARKERS_SUPPORTED
- int m;
- /* Save comments except under NONE option */
- if (option != JCOPYOPT_NONE && option != JCOPYOPT_ICC) {
- jpeg_save_markers(srcinfo, JPEG_COM, 0xFFFF);
- }
- /* Save all types of APPn markers iff ALL option */
- if (option == JCOPYOPT_ALL || option == JCOPYOPT_ALL_EXCEPT_ICC) {
- for (m = 0; m < 16; m++) {
- if (option == JCOPYOPT_ALL_EXCEPT_ICC && m == 2)
- continue;
- jpeg_save_markers(srcinfo, JPEG_APP0 + m, 0xFFFF);
- }
- }
- /* Save only APP2 markers if ICC option selected */
- if (option == JCOPYOPT_ICC) {
- jpeg_save_markers(srcinfo, JPEG_APP0 + 2, 0xFFFF);
- }
- #endif /* SAVE_MARKERS_SUPPORTED */
- }
- /* Copy markers saved in the given source object to the destination object.
- * This should be called just after jpeg_start_compress() or
- * jpeg_write_coefficients().
- * Note that those routines will have written the SOI, and also the
- * JFIF APP0 or Adobe APP14 markers if selected.
- */
- GLOBAL(void)
- jcopy_markers_execute(j_decompress_ptr srcinfo, j_compress_ptr dstinfo,
- JCOPY_OPTION option)
- {
- jpeg_saved_marker_ptr marker;
- /* In the current implementation, we don't actually need to examine the
- * option flag here; we just copy everything that got saved.
- * But to avoid confusion, we do not output JFIF and Adobe APP14 markers
- * if the encoder library already wrote one.
- */
- for (marker = srcinfo->marker_list; marker != NULL; marker = marker->next) {
- if (dstinfo->write_JFIF_header &&
- marker->marker == JPEG_APP0 &&
- marker->data_length >= 5 &&
- marker->data[0] == 0x4A &&
- marker->data[1] == 0x46 &&
- marker->data[2] == 0x49 &&
- marker->data[3] == 0x46 &&
- marker->data[4] == 0)
- continue; /* reject duplicate JFIF */
- if (dstinfo->write_Adobe_marker &&
- marker->marker == JPEG_APP0 + 14 &&
- marker->data_length >= 5 &&
- marker->data[0] == 0x41 &&
- marker->data[1] == 0x64 &&
- marker->data[2] == 0x6F &&
- marker->data[3] == 0x62 &&
- marker->data[4] == 0x65)
- continue; /* reject duplicate Adobe */
- jpeg_write_marker(dstinfo, marker->marker,
- marker->data, marker->data_length);
- }
- }
|