Home | History | Annotate | Download | only in plugins
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  * Copyright (C) 2016 Mopria Alliance, Inc.
      4  * Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
      5  *
      6  * Licensed under the Apache License, Version 2.0 (the "License");
      7  * you may not use this file except in compliance with the License.
      8  * You may obtain a copy of the License at
      9  *
     10  *      http://www.apache.org/licenses/LICENSE-2.0
     11  *
     12  * Unless required by applicable law or agreed to in writing, software
     13  * distributed under the License is distributed on an "AS IS" BASIS,
     14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15  * See the License for the specific language governing permissions and
     16  * limitations under the License.
     17  */
     18 
     19 #include <stdlib.h>
     20 #include <math.h>
     21 #include "wprint_image.h"
     22 #include "lib_wprint.h"
     23 
     24 #define TAG "wprint_image"
     25 #define MIN_DECODE_MEM (1 * 1024 * 1024)
     26 #define MAX_DECODE_MEM (4 * 1024 * 1024)
     27 
     28 void wprint_image_setup(wprint_image_info_t *image_info, const char *mime_type,
     29         const ifc_wprint_t *wprint_ifc, unsigned int output_resolution,
     30         int pdf_render_resolution) {
     31     if (image_info != NULL) {
     32         LOGD("image_setup");
     33         memset(image_info, 0, sizeof(wprint_image_info_t));
     34         image_info->wprint_ifc = wprint_ifc;
     35         image_info->mime_type = mime_type;
     36         image_info->print_resolution = output_resolution;
     37         image_info->pdf_render_resolution = pdf_render_resolution;
     38     }
     39 }
     40 
     41 status_t wprint_image_get_info(FILE *imgfile, wprint_image_info_t *image_info) {
     42     if (image_info == NULL) return ERROR;
     43 
     44     image_info->imgfile = imgfile;
     45     image_info->rotation = ROT_0;
     46     image_info->swath_start = -1;
     47     image_info->rows_cached = 0;
     48     image_info->output_cache = NULL;
     49     image_info->output_swath_start = -1;
     50     image_info->scaled_sample_size = 1;
     51 
     52     image_info->stripe_height = 0;
     53     image_info->unscaled_rows = NULL;
     54     image_info->unscaled_rows_needed = 0;
     55     image_info->mixed_memory = NULL;
     56     image_info->mixed_memory_needed = 0;
     57     image_info->scaled_width = -1;
     58     image_info->scaled_height = -1;
     59     image_info->unscaled_start_row = -1;
     60     image_info->unscaled_end_row = -1;
     61     image_info->scaling_needed = FALSE;
     62 
     63     image_info->output_padding_top = 0;
     64     image_info->output_padding_left = 0;
     65     image_info->output_padding_right = 0;
     66     image_info->output_padding_bottom = 0;
     67 
     68     const image_decode_ifc_t *decode_ifc = image_info->decode_ifc;
     69 
     70     if ((decode_ifc != NULL) && (decode_ifc->get_hdr != NULL)) {
     71         if (OK == decode_ifc->get_hdr(image_info)) {
     72             LOGI("wprint_image_get_info(): %s dim = %dx%d", image_info->mime_type,
     73                     image_info->width, image_info->height);
     74             return OK;
     75         } else {
     76             LOGE("ERROR: get_hdr for %s", image_info->mime_type);
     77             return ERROR;
     78         }
     79     }
     80     LOGE("Unsupported image type: %s", image_info->mime_type);
     81     return ERROR;
     82 }
     83 
     84 status_t wprint_image_set_output_properties(wprint_image_info_t *image_info,
     85         wprint_rotation_t rotation, unsigned int printable_width, unsigned int printable_height,
     86         unsigned int top_margin, unsigned int left_margin, unsigned int right_margin,
     87         unsigned int bottom_margin, unsigned int render_flags, unsigned int max_decode_stripe,
     88         unsigned int concurrent_stripes, unsigned int padding_options) {
     89     // validate rotation
     90     switch (rotation) {
     91         default:
     92             rotation = ROT_0;
     93         case ROT_0:
     94         case ROT_90:
     95         case ROT_180:
     96         case ROT_270:
     97             break;
     98     }
     99 
    100     // rotate margins
    101     switch (rotation) {
    102         case ROT_90:
    103         case ROT_270: {
    104             unsigned int temp;
    105             temp = top_margin;
    106             top_margin = left_margin;
    107             left_margin = bottom_margin;
    108             bottom_margin = right_margin;
    109             right_margin = temp;
    110             break;
    111         }
    112         default:
    113             break;
    114     }
    115 
    116     unsigned int input_render_flags = render_flags;
    117 
    118     // store padding options
    119     image_info->padding_options = (padding_options & PAD_ALL);
    120 
    121     // store margin adjusted printable area
    122     image_info->printable_width = printable_width - (left_margin + right_margin);
    123     image_info->printable_height = printable_height - (top_margin + bottom_margin);
    124 
    125     // store rendering parameters
    126     image_info->render_flags = render_flags;
    127     image_info->output_rows = max_decode_stripe;
    128     image_info->stripe_height = max_decode_stripe;
    129     image_info->concurrent_stripes = concurrent_stripes;
    130 
    131     // free data just in case
    132     if (image_info->unscaled_rows != NULL) {
    133         free(image_info->unscaled_rows);
    134     }
    135 
    136     // free data just in case
    137     if (image_info->mixed_memory != NULL) {
    138         free(image_info->mixed_memory);
    139     }
    140 
    141     image_info->row_offset = 0;
    142     image_info->col_offset = 0;
    143     image_info->scaled_sample_size = 1;
    144     image_info->scaled_width = -1;
    145     image_info->scaled_height = -1;
    146     image_info->unscaled_start_row = -1;
    147     image_info->unscaled_end_row = -1;
    148     image_info->unscaled_rows = NULL;
    149     image_info->unscaled_rows_needed = 0;
    150     image_info->mixed_memory = NULL;
    151     image_info->mixed_memory_needed = 0;
    152     image_info->rotation = rotation;
    153 
    154     unsigned int image_output_width;
    155     unsigned int image_output_height;
    156 
    157     // save margins
    158     switch (image_info->rotation) {
    159         case ROT_180:
    160         case ROT_270:
    161             image_info->output_padding_top = bottom_margin;
    162             image_info->output_padding_left = right_margin;
    163             image_info->output_padding_right = left_margin;
    164             image_info->output_padding_bottom = top_margin;
    165             break;
    166         case ROT_0:
    167         case ROT_90:
    168         default:
    169             image_info->output_padding_top = top_margin;
    170             image_info->output_padding_left = left_margin;
    171             image_info->output_padding_right = right_margin;
    172             image_info->output_padding_bottom = bottom_margin;
    173             break;
    174     }
    175 
    176     // swap dimensions
    177     switch (image_info->rotation) {
    178         case ROT_90:
    179         case ROT_270:
    180             image_output_width = image_info->height;
    181             image_output_height = image_info->width;
    182             break;
    183         case ROT_0:
    184         case ROT_180:
    185         default:
    186             image_output_width = image_info->width;
    187             image_output_height = image_info->height;
    188             break;
    189     }
    190 
    191     int native_units = 0;
    192 
    193     const image_decode_ifc_t *decode_ifc = image_info->decode_ifc;
    194     if ((image_info->render_flags & RENDER_FLAG_AUTO_FIT) && (decode_ifc != NULL) &&
    195             (decode_ifc->native_units != NULL)) {
    196         native_units = decode_ifc->native_units(image_info);
    197     }
    198 
    199     if (native_units <= 0) {
    200         native_units = image_info->print_resolution;
    201     }
    202 
    203     float native_scaling = 1.0f;
    204     unsigned int native_image_output_width = image_output_width;
    205     unsigned int native_image_output_height = image_output_height;
    206 
    207     if ((native_units != image_info->print_resolution)
    208             && !((image_info->render_flags & RENDER_FLAG_AUTO_SCALE)
    209                     || ((image_info->render_flags & RENDER_FLAG_AUTO_FIT)
    210                             && !(image_info->render_flags & RENDER_FLAG_DOCUMENT_SCALING)))) {
    211         native_scaling = (image_info->print_resolution * 1.0f) / (native_units * 1.0f);
    212         native_image_output_width = (int) floorf(image_output_width * native_scaling);
    213         native_image_output_height = (int) floorf(image_output_height * native_scaling);
    214         LOGD("need to do native scaling by %f factor to size %dx%d", native_scaling,
    215                 native_image_output_width, native_image_output_height);
    216     }
    217 
    218     // if we have to scale determine if we can use subsampling to scale down
    219     if ((image_info->render_flags & (RENDER_FLAG_AUTO_SCALE | RENDER_FLAG_AUTO_FIT)) &&
    220             (native_scaling == 1.0f)) {
    221         LOGD("calculating subsampling");
    222 
    223         /*
    224          * Find a subsampling scale factor that produces an image that is still bigger
    225          * than the printable area and then finish scaling later using the fine-scaler.
    226          * This produces better quality than subsampling to a smaller size and scaling up.
    227          */
    228         image_info->scaled_sample_size = 1;
    229         if ((decode_ifc != NULL) && (decode_ifc->supports_subsampling(image_info) == OK)) {
    230             // subsampling supported
    231             int next_width, next_height;
    232             next_width = image_output_width >> 1;
    233             next_height = image_output_height >> 1;
    234             while (((image_info->render_flags & RENDER_FLAG_AUTO_SCALE) &&
    235                     (next_width > image_info->printable_width) &&
    236                     (next_height > image_info->printable_height)) ||
    237                     ((image_info->render_flags & RENDER_FLAG_AUTO_FIT) &&
    238                             ((next_width > image_info->printable_width) ||
    239                                     (next_height > image_info->printable_height)))) {
    240                 image_info->scaled_sample_size <<= 1;
    241                 next_width >>= 1;
    242                 next_height >>= 1;
    243             }
    244         }
    245 
    246         LOGD("calculated sample size: %d", image_info->scaled_sample_size);
    247 
    248         // are we dong any subsampling?
    249         if (image_info->scaled_sample_size > 1) {
    250             // force the decoder to close and reopen with the new sample size setting
    251             decode_ifc->cleanup(image_info);
    252             decode_ifc->get_hdr(image_info);
    253 
    254             // update the output size
    255             image_output_width /= image_info->scaled_sample_size;
    256             image_output_height /= image_info->scaled_sample_size;
    257         }
    258 
    259         /*
    260          * have we reached our target size with subsampling?
    261          * if so disable further scaling
    262          */
    263         // check if width matches and height meets criteria
    264         if ((image_output_width == image_info->printable_width) &&
    265                 (((image_info->render_flags & RENDER_FLAG_AUTO_SCALE) &&
    266                         (image_output_height >= image_info->printable_height)) ||
    267                         ((image_info->render_flags & RENDER_FLAG_AUTO_FIT) &&
    268                                 (image_output_height < image_info->printable_height)))) {
    269             LOGD("disabling fine scaling since width matches and height meets criteria");
    270             image_info->render_flags &= ~(RENDER_FLAG_AUTO_SCALE | RENDER_FLAG_AUTO_FIT);
    271         } else if ((image_output_height == image_info->printable_height) &&
    272                 (((image_info->render_flags & RENDER_FLAG_AUTO_SCALE) &&
    273                         (image_output_width >= image_info->printable_width)) ||
    274                         ((image_info->render_flags & RENDER_FLAG_AUTO_FIT) &&
    275                                 (image_output_width < image_info->printable_width)))) {
    276             // height matches and width meets criteria
    277             LOGD("disabling fine scaling since height matches and width meets criteria");
    278             image_info->render_flags &= ~(RENDER_FLAG_AUTO_SCALE | RENDER_FLAG_AUTO_FIT);
    279         }
    280 
    281         if ((image_info->render_flags & RENDER_FLAG_DOCUMENT_SCALING)
    282                 && (image_output_height <= image_info->printable_height)
    283                 && (image_output_width <= image_info->printable_width)) {
    284             image_info->render_flags &= ~(RENDER_FLAG_AUTO_SCALE | RENDER_FLAG_AUTO_FIT);
    285         }
    286     } else if ((native_scaling != 1.0f) &&
    287             (image_info->render_flags & RENDER_FLAG_DOCUMENT_SCALING)) {
    288         LOGD("checking native document scaling factor");
    289         if ((native_image_output_height <= image_info->printable_height)
    290                 && (native_image_output_width <= image_output_width
    291                         <= image_info->printable_width)) {
    292             LOGD("fit in printable area, just scale to native units");
    293             image_info->render_flags &= ~(RENDER_FLAG_AUTO_SCALE | RENDER_FLAG_AUTO_FIT);
    294         } else {
    295             LOGD("we don't fit in printable area, continue with fit-to-page");
    296             native_scaling = 1.0f;
    297         }
    298     }
    299 
    300     // store the subsampled dimensions
    301     image_info->sampled_width = (image_info->width / image_info->scaled_sample_size);
    302     image_info->sampled_height = (image_info->height / image_info->scaled_sample_size);
    303 
    304     // do we have any additional scaling to do?
    305     if ((image_info->render_flags & (RENDER_FLAG_AUTO_SCALE | RENDER_FLAG_AUTO_FIT))
    306             || (native_scaling != 1.0f)) {
    307         LOGD("calculating fine-scaling");
    308         int i;
    309         float targetHeight, targetWidth;
    310         float sourceHeight, sourceWidth;
    311         float rw;
    312         int useHeight;
    313 
    314         sourceWidth = image_output_width * 1.0f;
    315         sourceHeight = image_output_height * 1.0f;
    316 
    317         if (image_info->render_flags & (RENDER_FLAG_AUTO_SCALE | RENDER_FLAG_AUTO_FIT)) {
    318             targetHeight = image_info->printable_height * 1.0f;
    319             targetWidth = image_info->printable_width * 1.0f;
    320 
    321             // determine what our bounding edge is
    322             rw = (targetHeight * sourceWidth) / sourceHeight;
    323             if (image_info->render_flags & RENDER_FLAG_AUTO_SCALE) {
    324                 useHeight = (rw >= targetWidth);
    325             } else {
    326                 useHeight = (rw < targetWidth);
    327             }
    328 
    329             // determine the scaling factor
    330             if (useHeight) {
    331                 image_info->scaled_width = (int) floorf(rw);
    332                 image_info->scaled_height = (int) floorf(targetHeight);
    333             } else {
    334                 image_info->scaled_height = (int) floorf(targetWidth * sourceHeight / sourceWidth);
    335                 image_info->scaled_width = (int) floorf(targetWidth);
    336             }
    337         } else {
    338             image_info->scaled_height = native_image_output_height;
    339             image_info->scaled_width = native_image_output_width;
    340         }
    341         image_info->scaling_needed = TRUE;
    342 
    343         /*
    344          * setup the fine-scaler
    345          * we use rotated image_output_width rather than the pre-rotated sampled_width
    346          */
    347         scaler_make_image_scaler_tables(image_output_width, BYTES_PER_PIXEL(image_output_width),
    348                 image_info->scaled_width, BYTES_PER_PIXEL(image_info->scaled_width),
    349                 image_output_height, image_info->scaled_height, &image_info->scaler_config);
    350 
    351         image_info->unscaled_rows_needed = 0;
    352         image_info->mixed_memory_needed = 0;
    353 
    354         // calculate memory requirements
    355         for (i = 0; i < image_info->printable_height; i += max_decode_stripe) {
    356             uint16 row;
    357             uint16 row_start, row_end, gen_rows, row_offset;
    358             uint32 mixed;
    359             row = i;
    360             if (row >= image_info->scaled_height) {
    361                 break;
    362             }
    363             scaler_calculate_scaling_rows(row,
    364                     MIN((row + (max_decode_stripe - 1)),
    365                             (image_info->scaled_height - 1)),
    366                     (void *) &image_info->scaler_config,
    367                     &row_start, &row_end, &gen_rows,
    368                     &row_offset, &mixed);
    369 
    370             image_info->output_rows = MAX(image_info->output_rows, gen_rows);
    371             image_info->unscaled_rows_needed = MAX(image_info->unscaled_rows_needed,
    372                     ((row_end - row_start) + 3));
    373             image_info->mixed_memory_needed = MAX(image_info->mixed_memory_needed, mixed);
    374         }
    375         int unscaled_size = BYTES_PER_PIXEL(
    376                 (MAX(image_output_width, image_output_height) * image_info->unscaled_rows_needed));
    377 
    378         // allocate memory required for scaling
    379         image_info->unscaled_rows = malloc(unscaled_size);
    380 
    381         if (image_info->unscaled_rows != NULL) {
    382             memset(image_info->unscaled_rows, 0xff, unscaled_size);
    383         }
    384         image_info->mixed_memory = (image_info->mixed_memory_needed != 0) ? malloc(
    385                 image_info->mixed_memory_needed) : NULL;
    386     } else {
    387         image_info->scaled_height = image_output_height;
    388         image_info->scaled_width = image_output_width;
    389     }
    390 
    391     // final calculations
    392     if ((image_info->render_flags & (RENDER_FLAG_AUTO_SCALE | RENDER_FLAG_AUTO_FIT)) ||
    393             image_info->scaling_needed) {
    394         /* use the full image size since both of the dimensions could be greater than
    395          * the printable area */
    396         image_info->output_width = image_output_width;
    397         image_info->output_height = image_output_height;
    398     } else {
    399         // clip the image within the printable area
    400         image_info->output_width = MIN(image_info->printable_width, image_output_width);
    401         image_info->output_height = MIN(image_info->printable_height, image_output_height);
    402     }
    403 
    404     int delta;
    405     switch (image_info->rotation) {
    406         case ROT_90:
    407             if (image_info->render_flags & RENDER_FLAG_AUTO_SCALE) {
    408             } else if (image_info->render_flags & RENDER_FLAG_CENTER_HORIZONTAL) {
    409                 if (image_info->scaled_width > image_info->printable_width) {
    410                     image_info->col_offset = (
    411                             (image_info->scaled_width - image_info->printable_width) / 2);
    412                 } else {
    413                     int paddingDelta = (image_info->printable_width - image_info->scaled_width);
    414                     delta = paddingDelta / 2;
    415                     image_info->output_padding_left += delta;
    416                     image_info->output_padding_right += delta + (paddingDelta & 0x1);
    417                 }
    418             } else if (image_info->scaled_width > image_info->printable_width) {
    419                 image_info->col_offset = (image_info->scaled_width - image_info->printable_width);
    420             } else if (image_info->scaled_width < image_info->printable_width) {
    421                 image_info->output_padding_right += (image_info->printable_width -
    422                         image_info->scaled_width);
    423             }
    424 
    425             if (image_info->render_flags & RENDER_FLAG_AUTO_SCALE) {
    426             } else if (image_info->render_flags & RENDER_FLAG_CENTER_VERTICAL) {
    427                 if (image_info->scaled_height > image_info->printable_height) {
    428                     image_info->row_offset = (
    429                             (image_info->scaled_height - image_info->printable_height) / 2);
    430                 } else {
    431                     int paddingDelta = (image_info->printable_height - image_info->scaled_height);
    432                     delta = paddingDelta / 2;
    433                     image_info->output_padding_top += delta;
    434                     image_info->output_padding_bottom += delta + (paddingDelta & 0x1);
    435                 }
    436             } else if (image_info->scaled_height < image_info->printable_height) {
    437                 image_info->output_padding_bottom += (image_info->printable_height -
    438                         image_info->scaled_height);
    439             }
    440             break;
    441         case ROT_180:
    442             if (image_info->render_flags & RENDER_FLAG_AUTO_SCALE) {
    443             } else if (image_info->render_flags & RENDER_FLAG_CENTER_HORIZONTAL) {
    444                 if (image_info->scaled_width > image_info->printable_width) {
    445                     image_info->col_offset = (
    446                             (image_info->scaled_width - image_info->printable_width) / 2);
    447                 } else {
    448                     int paddingDelta = (image_info->printable_width - image_info->scaled_width);
    449                     delta = paddingDelta / 2;
    450                     image_info->output_padding_left += delta;
    451                     image_info->output_padding_right += delta + (paddingDelta & 0x1);
    452                 }
    453             } else if (image_info->scaled_width > image_info->printable_width) {
    454                 image_info->col_offset = (image_info->scaled_width - image_info->printable_width);
    455             } else if (image_info->scaled_width < image_info->printable_width) {
    456                 image_info->output_padding_left += (image_info->printable_width -
    457                         image_info->scaled_width);
    458             }
    459 
    460             if (image_info->render_flags & RENDER_FLAG_AUTO_SCALE) {
    461             } else if (image_info->render_flags & RENDER_FLAG_CENTER_VERTICAL) {
    462                 if (image_info->scaled_height > image_info->printable_height) {
    463                     image_info->row_offset = (
    464                             (image_info->scaled_height - image_info->printable_height) / 2);
    465                 } else {
    466                     int paddingDelta = (image_info->printable_height - image_info->scaled_height);
    467                     delta = paddingDelta / 2;
    468                     image_info->output_padding_top += delta;
    469                     image_info->output_padding_bottom += delta + (paddingDelta & 0x1);
    470                 }
    471             } else if (image_info->scaled_height > image_info->printable_height) {
    472                 image_info->row_offset = (image_info->scaled_height - image_info->printable_height);
    473             } else if (image_info->scaled_height < image_info->printable_height) {
    474                 image_info->output_padding_top += (image_info->printable_height -
    475                         image_info->scaled_height);
    476             }
    477             break;
    478         case ROT_270:
    479             if (image_info->render_flags & RENDER_FLAG_AUTO_SCALE) {
    480             } else if (image_info->render_flags & RENDER_FLAG_CENTER_HORIZONTAL) {
    481                 if (image_info->scaled_width > image_info->printable_width) {
    482                     image_info->col_offset = (
    483                             (image_info->scaled_width - image_info->printable_width) / 2);
    484                 } else {
    485                     int paddingDelta = (image_info->printable_width - image_info->scaled_width);
    486                     delta = paddingDelta / 2;
    487                     image_info->output_padding_left += delta;
    488                     image_info->output_padding_right += delta + (paddingDelta & 0x1);
    489                 }
    490             } else if (image_info->scaled_width > image_info->printable_width) {
    491                 image_info->col_offset = (image_info->scaled_width - image_info->printable_width);
    492             } else if (image_info->scaled_width < image_info->printable_width) {
    493                 image_info->output_padding_left += (image_info->printable_width -
    494                         image_info->scaled_width);
    495             }
    496 
    497             if (image_info->render_flags & RENDER_FLAG_AUTO_SCALE) {
    498             } else if (image_info->render_flags & RENDER_FLAG_CENTER_VERTICAL) {
    499                 if (image_info->scaled_height > image_info->printable_height) {
    500                     image_info->row_offset = (
    501                             (image_info->scaled_height - image_info->printable_height) / 2);
    502                 } else {
    503                     int paddingDelta = (image_info->printable_height - image_info->scaled_height);
    504                     delta = paddingDelta / 2;
    505                     image_info->output_padding_top += delta;
    506                     image_info->output_padding_bottom += delta + (paddingDelta & 0x1);
    507                 }
    508             } else if (image_info->scaled_height < image_info->printable_height) {
    509                 image_info->output_padding_top += (image_info->printable_height -
    510                         image_info->scaled_height);
    511             } else if (image_info->scaled_height > image_info->printable_height) {
    512                 image_info->row_offset = (image_info->scaled_height - image_info->printable_height);
    513             }
    514             break;
    515         case ROT_0:
    516         default:
    517             if (image_info->render_flags & RENDER_FLAG_AUTO_SCALE) {
    518             } else if (image_info->render_flags & RENDER_FLAG_CENTER_HORIZONTAL) {
    519                 if (image_info->scaled_width > image_info->printable_width) {
    520                     image_info->col_offset = (
    521                             (image_info->scaled_width - image_info->printable_width) / 2);
    522                 } else {
    523                     int paddingDelta = (image_info->printable_width - image_info->scaled_width);
    524                     delta = paddingDelta / 2;
    525                     image_info->output_padding_left += delta;
    526                     image_info->output_padding_right += delta + (paddingDelta & 0x1);
    527                 }
    528             } else if (image_info->scaled_width < image_info->printable_width) {
    529                 image_info->output_padding_right += (image_info->printable_width -
    530                         image_info->scaled_width);
    531             }
    532 
    533             if (image_info->render_flags & RENDER_FLAG_AUTO_SCALE) {
    534             } else if (image_info->render_flags & RENDER_FLAG_CENTER_VERTICAL) {
    535                 if (image_info->scaled_height > image_info->printable_height) {
    536                     image_info->row_offset = (
    537                             (image_info->scaled_height - image_info->printable_height) / 2);
    538                 } else {
    539                     int paddingDelta = (image_info->printable_height - image_info->scaled_height);
    540                     delta = paddingDelta / 2;
    541                     image_info->output_padding_top += delta;
    542                     image_info->output_padding_bottom += delta + (paddingDelta & 0x1);
    543                 }
    544             } else if (image_info->scaled_height < image_info->printable_height) {
    545                 image_info->output_padding_bottom += (image_info->printable_height -
    546                         image_info->scaled_height);
    547             }
    548             break;
    549     }
    550 
    551     return OK;
    552 }
    553 
    554 static int _get_width(wprint_image_info_t *image_info, unsigned int padding_options) {
    555     int width;
    556     if (image_info->render_flags & RENDER_FLAG_AUTO_SCALE) {
    557         width = image_info->printable_width;
    558     } else if ((image_info->render_flags & RENDER_FLAG_AUTO_FIT) || image_info->scaling_needed) {
    559         width = image_info->scaled_width;
    560     } else {
    561         width = image_info->output_width;
    562     }
    563     if (padding_options & PAD_LEFT) {
    564         width += image_info->output_padding_left;
    565     }
    566     if (padding_options & PAD_RIGHT) {
    567         width += image_info->output_padding_right;
    568     }
    569     return width;
    570 }
    571 
    572 int wprint_image_get_width(wprint_image_info_t *image_info) {
    573     int width = _get_width(image_info, image_info->padding_options);
    574     LOGD("wprint_image_get_width(): %d", width);
    575     return width;
    576 }
    577 
    578 int wprint_image_get_output_buff_size(wprint_image_info_t *image_info) {
    579     int width = MAX(MAX(image_info->scaled_width, image_info->scaled_height),
    580             _get_width(image_info, image_info->padding_options));
    581     LOGD("wprint_image_get_output_buff_size(): %dx%d", width, image_info->output_rows);
    582     return (BYTES_PER_PIXEL(width * image_info->output_rows));
    583 }
    584 
    585 static int _get_height(wprint_image_info_t *image_info, unsigned int padding_options) {
    586     int height;
    587     if (image_info->render_flags & RENDER_FLAG_AUTO_SCALE) {
    588         height = image_info->printable_height;
    589     } else {
    590         height = MIN(image_info->scaled_height, image_info->printable_height);
    591     }
    592     if (padding_options & PAD_TOP) {
    593         height += image_info->output_padding_top;
    594     }
    595     if (padding_options & PAD_BOTTOM) {
    596         height += image_info->output_padding_bottom;
    597     }
    598     return height;
    599 }
    600 
    601 int wprint_image_get_height(wprint_image_info_t *image_info) {
    602     int height = _get_height(image_info, image_info->padding_options);
    603     LOGD("wprint_image_get_height(): %d", height);
    604     return height;
    605 }
    606 
    607 bool wprint_image_is_landscape(wprint_image_info_t *image_info) {
    608     return (image_info->width > image_info->height);
    609 }
    610 
    611 int _decode_stripe(wprint_image_info_t *image_info, int start_row, int num_rows,
    612         unsigned int padding_options, unsigned char *rgb_pixels) {
    613     int image_y, image_x;
    614     unsigned char *image_data;
    615     int nbytes = -1;
    616     int rbytes;
    617     int col_offset;
    618     int old_num_rows;
    619     const image_decode_ifc_t *decode_ifc = image_info->decode_ifc;
    620     if ((decode_ifc == NULL) || (decode_ifc->decode_row == NULL)) {
    621         return nbytes;
    622     }
    623 
    624     nbytes = 0;
    625     start_row += image_info->row_offset;
    626     rbytes = BYTES_PER_PIXEL(image_info->output_width);
    627 
    628     // get padding values
    629     int padding_left = ((padding_options & PAD_LEFT) ? BYTES_PER_PIXEL(
    630             image_info->output_padding_left) : 0);
    631     int padding_right = ((padding_options & PAD_RIGHT) ? BYTES_PER_PIXEL(
    632             image_info->output_padding_right) : 0);
    633 
    634     old_num_rows = ~num_rows;
    635     switch (image_info->rotation) {
    636         case ROT_90:
    637             col_offset = BYTES_PER_PIXEL(image_info->col_offset);
    638             while (num_rows > 0) {
    639                 if (start_row > image_info->sampled_width) {
    640                     return nbytes;
    641                 }
    642                 if (old_num_rows == num_rows) {
    643                     LOGE("Bad ROT_90 calculations. Exiting to prevent infinite loop");
    644                     return ERROR;
    645                 }
    646                 old_num_rows = num_rows;
    647                 if ((image_info->output_swath_start == -1) ||
    648                         (start_row < image_info->output_swath_start) ||
    649                         (start_row >= (image_info->output_swath_start + image_info->rows_cached))) {
    650                     if (image_info->output_swath_start == -1) {
    651                         if (decode_ifc->decode_row(image_info, 0) == NULL) {
    652                             return ERROR;
    653                         }
    654                     }
    655                     image_info->output_swath_start = ((start_row / image_info->rows_cached) *
    656                             image_info->rows_cached);
    657                     for (image_y = 0; image_y < image_info->sampled_height; image_y++) {
    658                         image_data = decode_ifc->decode_row(image_info, image_y);
    659                         if (image_data == NULL) {
    660                             return ERROR;
    661                         }
    662                         for (image_x = 0; (image_x < image_info->rows_cached &&
    663                                 ((image_x + image_info->output_swath_start) <
    664                                         image_info->sampled_width));
    665                                 image_x++) {
    666                             memcpy(image_info->output_cache[image_x] + BYTES_PER_PIXEL(
    667                                             (image_info->sampled_height - image_y - 1)),
    668                                     image_data + BYTES_PER_PIXEL(
    669                                             (image_info->output_swath_start + image_x)),
    670                                     BYTES_PER_PIXEL(1));
    671                         }
    672                     }
    673                 }
    674 
    675                 for (image_y = start_row; ((num_rows != 0) &&
    676                         (image_y < image_info->sampled_width) &&
    677                         (image_y < (image_info->output_swath_start + image_info->rows_cached)));
    678                         image_y++, num_rows--, start_row++) {
    679                     memcpy(rgb_pixels + padding_left,
    680                             image_info->output_cache[image_y - image_info->output_swath_start] +
    681                                     col_offset, rbytes);
    682                     nbytes += rbytes + padding_left + padding_right;
    683                     rgb_pixels += rbytes + padding_left + padding_right;
    684                 }
    685             }
    686             break;
    687         case ROT_180:
    688             col_offset = image_info->col_offset;
    689             for (image_y = start_row;
    690                     ((image_y < image_info->sampled_height) && (num_rows != 0));
    691                     image_y++, num_rows--) {
    692                 image_data = decode_ifc->decode_row(image_info,
    693                         (image_info->sampled_height - image_y - 1));
    694                 if (image_data == NULL) {
    695                     return ERROR;
    696                 }
    697                 for (image_x = 0; image_x < image_info->output_width; image_x++) {
    698                     memcpy(rgb_pixels + padding_left + BYTES_PER_PIXEL(image_x),
    699                             image_data + BYTES_PER_PIXEL(image_info->sampled_width -
    700                                     image_x - col_offset - 1),
    701                             BYTES_PER_PIXEL(1));
    702                 }
    703                 nbytes += rbytes + padding_left + padding_right;
    704                 rgb_pixels += rbytes + padding_left + padding_right;
    705             }
    706             break;
    707         case ROT_270:
    708             col_offset = BYTES_PER_PIXEL(image_info->col_offset);
    709             while (num_rows > 0) {
    710                 if (start_row > image_info->sampled_width) {
    711                     return nbytes;
    712                 }
    713                 if (old_num_rows == num_rows) {
    714                     LOGE("Bad ROT_270 calculations. Erroring out to prevent infinite loop.");
    715                     return ERROR;
    716                 }
    717                 old_num_rows = num_rows;
    718                 if ((image_info->output_swath_start == -1) ||
    719                         (start_row < image_info->output_swath_start) ||
    720                         (start_row >= (image_info->output_swath_start + image_info->rows_cached))) {
    721                     if (image_info->output_swath_start == -1) {
    722                         if (decode_ifc->decode_row(image_info, 0) == NULL) {
    723                             return ERROR;
    724                         }
    725                     }
    726                     image_info->output_swath_start = ((start_row / image_info->rows_cached) *
    727                             image_info->rows_cached);
    728                     for (image_y = 0; image_y < image_info->sampled_height; image_y++) {
    729                         image_data = decode_ifc->decode_row(image_info, image_y);
    730                         if (image_data == NULL) {
    731                             return ERROR;
    732                         }
    733                         for (image_x = 0; ((image_x < image_info->rows_cached) &&
    734                                 ((image_x + image_info->output_swath_start) <
    735                                         image_info->sampled_width));
    736                                 image_x++) {
    737                             memcpy(image_info->output_cache[image_x] + BYTES_PER_PIXEL(image_y),
    738                                     image_data + BYTES_PER_PIXEL(image_info->sampled_width -
    739                                             (image_info->output_swath_start +
    740                                                     image_x) - 1),
    741                                     BYTES_PER_PIXEL(1));
    742                         }
    743                     }
    744                 }
    745                 for (image_y = start_row;
    746                         ((num_rows != 0) &&
    747                                 (image_y < image_info->sampled_width) &&
    748                                 (image_y < (image_info->output_swath_start
    749                                         + image_info->rows_cached)));
    750                         image_y++, num_rows--, start_row++) {
    751                     memcpy(rgb_pixels + padding_left,
    752                             image_info->output_cache[image_y - image_info->output_swath_start] +
    753                                     col_offset, rbytes);
    754                     nbytes += rbytes + padding_left + padding_right;
    755                     rgb_pixels += rbytes + padding_left + padding_right;
    756                 }
    757             }
    758             break;
    759         case ROT_0:
    760         default:
    761             col_offset = BYTES_PER_PIXEL(image_info->col_offset);
    762             for (image_y = start_row;
    763                     ((image_y < image_info->sampled_height) && (num_rows != 0));
    764                     image_y++, num_rows--) {
    765                 image_data = decode_ifc->decode_row(image_info, image_y);
    766                 if (image_data == NULL) {
    767                     LOGE("ERROR: received no data for row: %d", image_y);
    768                     return ERROR;
    769                 }
    770                 memcpy(rgb_pixels + padding_left, image_data + col_offset, rbytes);
    771                 nbytes += rbytes + padding_left + padding_right;
    772                 rgb_pixels += rbytes + padding_left + padding_right;
    773             }
    774             break;
    775     }
    776     return nbytes;
    777 }
    778 
    779 int wprint_image_decode_stripe(wprint_image_info_t *image_info, int start_row, int *height,
    780         unsigned char *rgb_pixels) {
    781     int nbytes = 0;
    782     int bytes_per_row = BYTES_PER_PIXEL(_get_width(image_info, image_info->padding_options));
    783 
    784     if (height == NULL) {
    785         return -1;
    786     }
    787 
    788     int num_rows = *height;
    789 
    790     *height = 0;
    791 
    792     // get padding values
    793     int padding_left = ((image_info->padding_options & PAD_LEFT) ? BYTES_PER_PIXEL(
    794             image_info->output_padding_left) : 0);
    795     int padding_right = ((image_info->padding_options & PAD_RIGHT) ? BYTES_PER_PIXEL(
    796             image_info->output_padding_right) : 0);
    797     int padding_top = ((image_info->padding_options & PAD_TOP) ?
    798             image_info->output_padding_top : 0);
    799     // handle invalid requests
    800     if ((start_row < 0) || (start_row >= _get_height(image_info, image_info->padding_options))) {
    801         *height = 0;
    802         return ERROR;
    803     } else if ((image_info->padding_options & PAD_TOP) &&
    804             (start_row < padding_top)) {
    805         int blank_rows = MIN(num_rows, (padding_top - start_row));
    806         int bytesToBlank = (blank_rows * bytes_per_row);
    807         nbytes += bytesToBlank;
    808         num_rows -= blank_rows;
    809         *height += blank_rows;
    810         memset(rgb_pixels, 0xff, bytesToBlank);
    811         rgb_pixels += bytesToBlank;
    812         start_row += blank_rows;
    813     } else if ((image_info->padding_options & PAD_BOTTOM) &&
    814             (start_row >= _get_height(image_info, image_info->padding_options & PAD_TOP))) {
    815         // handle image padding on bottom
    816         int blank_rows = MIN(num_rows,
    817                 _get_height(image_info, image_info->padding_options) - start_row);
    818         int bytesToBlank = (blank_rows * bytes_per_row);
    819         nbytes += bytesToBlank;
    820         num_rows -= blank_rows;
    821         *height += blank_rows;
    822         memset(rgb_pixels, 0xff, bytesToBlank);
    823         rgb_pixels += bytesToBlank;
    824         start_row += blank_rows;
    825     }
    826 
    827     if (num_rows <= 0) {
    828         return nbytes;
    829     }
    830 
    831     unsigned char *pad_rgb_pixels = rgb_pixels;
    832     int unpadded_start_row = start_row;
    833     // adjust start row to fit within image bounds
    834     if (image_info->padding_options & PAD_TOP) {
    835         unpadded_start_row -= padding_top;
    836     }
    837 
    838     // check if we need to scaling
    839     if (image_info->scaling_needed) {
    840         // scaling required
    841         uint32 scaled_start_row = unpadded_start_row;
    842         if (image_info->scaled_height > image_info->printable_height) {
    843             scaled_start_row += ((image_info->scaled_height - image_info->printable_height) / 2);
    844         }
    845         uint32 stripe_height, mixed;
    846         uint16 unscaled_row_start, unscaled_row_end;
    847         uint16 generated_rows, row_offset;
    848         uint32 predecoded_rows;
    849 
    850         int scaled_num_rows = (((scaled_start_row + num_rows) > image_info->scaled_height) ?
    851                 (image_info->scaled_height - scaled_start_row) : num_rows);
    852         while (scaled_num_rows > 0) {
    853             stripe_height = MIN(scaled_num_rows, image_info->stripe_height);
    854             scaler_calculate_scaling_rows(scaled_start_row,
    855                     MIN((scaled_start_row + stripe_height - 1),
    856                             (image_info->scaled_height - 1)), (void *) &image_info->scaler_config,
    857                     &unscaled_row_start, &unscaled_row_end, &generated_rows, &row_offset, &mixed);
    858 
    859             if (mixed > image_info->mixed_memory_needed) {
    860                 LOGE("need more memory");
    861                 return -1;
    862             }
    863 
    864             predecoded_rows = 0;
    865             if (unscaled_row_start <= image_info->unscaled_end_row) {
    866                 // shift over any rows we need that were decoded in the previous pass
    867                 predecoded_rows = (image_info->unscaled_end_row - unscaled_row_start) + 1;
    868 
    869                 memmove(image_info->unscaled_rows, image_info->unscaled_rows +
    870                         BYTES_PER_PIXEL(((unscaled_row_start - image_info->unscaled_start_row) *
    871                                 image_info->output_width)),
    872                         BYTES_PER_PIXEL((predecoded_rows * image_info->output_width)));
    873             }
    874 
    875             image_info->unscaled_start_row = unscaled_row_start;
    876             image_info->unscaled_end_row = unscaled_row_end;
    877 
    878             /*
    879              * decode the remaining rows we need
    880              * don't pad the output since we need to move the data after scaling anyways
    881              */
    882             int rowsLeftToDecode = ((image_info->unscaled_end_row -
    883                     (image_info->unscaled_start_row + predecoded_rows)) + 1);
    884             if (rowsLeftToDecode > 0) {
    885                 int dbytes = _decode_stripe(image_info,
    886                         image_info->unscaled_start_row + predecoded_rows, rowsLeftToDecode,
    887                         PAD_NONE, (image_info->unscaled_rows + BYTES_PER_PIXEL(predecoded_rows *
    888                                 image_info->output_width)));
    889                 if (dbytes <= 0) {
    890                     if (dbytes < 0) {
    891                         LOGE("couldn't decode rows");
    892                     }
    893                     return dbytes;
    894                 }
    895             } else if (predecoded_rows <= 0) {
    896                 return 0;
    897             }
    898 
    899             // scale the data to it's final size
    900             scaler_scale_image_data(image_info->unscaled_rows, (void *) &image_info->scaler_config,
    901                     rgb_pixels, image_info->mixed_memory);
    902             // do we have to move the data around??
    903             if ((row_offset != 0) ||
    904                     (image_info->scaled_width > image_info->printable_width) ||
    905                     (padding_left > 0) ||
    906                     (padding_right > 0)) {
    907                 int delta = 0;
    908                 int pixelsToMove = BYTES_PER_PIXEL(MIN(image_info->scaled_width,
    909                         image_info->printable_width));
    910 
    911                 int memMoveRow = ((bytes_per_row < image_info->scaler_config.iOutBufWidth) ? 0 : (
    912                         stripe_height - 1));
    913                 int memMoveIncrement = ((bytes_per_row < image_info->scaler_config.iOutBufWidth)
    914                         ? 1 : -1);
    915 
    916                 // if scaled width is greater than the printable area drop pixels on either size
    917                 if (image_info->scaled_width > image_info->printable_width) {
    918                     delta = BYTES_PER_PIXEL(
    919                             ((image_info->scaled_width - image_info->printable_width) / 2));
    920                 }
    921 
    922                 // move the data into the correct location in the output buffer
    923                 for (generated_rows = 0; generated_rows < stripe_height; generated_rows++,
    924                         memMoveRow += memMoveIncrement) {
    925                     memmove(rgb_pixels + (memMoveRow * bytes_per_row) + padding_left,
    926                             rgb_pixels + ((memMoveRow + row_offset) *
    927                                     image_info->scaler_config.iOutBufWidth) + delta, pixelsToMove);
    928                 }
    929             }
    930 
    931             num_rows -= stripe_height;
    932             scaled_num_rows -= stripe_height;
    933             scaled_start_row += stripe_height;
    934             nbytes += (bytes_per_row * stripe_height);
    935             rgb_pixels += (bytes_per_row * stripe_height);
    936             *height += stripe_height;
    937             start_row += stripe_height;
    938         }
    939     } else {
    940         // no scaling needed
    941 
    942         // decode the request
    943         int dbytes = _decode_stripe(image_info, unpadded_start_row,
    944                 (((unpadded_start_row + num_rows) >
    945                         _get_height(image_info, PAD_NONE)) ?
    946                         (_get_height(image_info, PAD_NONE) - unpadded_start_row)
    947                         : num_rows),
    948                 image_info->padding_options, rgb_pixels);
    949         if (dbytes <= 0) {
    950             if (dbytes < 0) {
    951                 LOGE("couldn't decode rows");
    952             }
    953             return dbytes;
    954         }
    955 
    956         int rows = (dbytes / bytes_per_row);
    957         *height += rows;
    958         num_rows -= rows;
    959         start_row += rows;
    960         unpadded_start_row += rows;
    961         rgb_pixels += dbytes;
    962         nbytes += dbytes;
    963     }
    964 
    965     // white pad the left and right edges
    966     if ((pad_rgb_pixels != rgb_pixels) &&
    967             (image_info->padding_options & (PAD_LEFT | PAD_RIGHT)) &&
    968             ((padding_left != 0) || (padding_right != 0))) {
    969         while (pad_rgb_pixels != rgb_pixels) {
    970             if (padding_left != 0) {
    971                 memset(pad_rgb_pixels, 0xff, padding_left);
    972             }
    973             if (padding_right != 0) {
    974                 memset(pad_rgb_pixels + (bytes_per_row - padding_right), 0xff, padding_right);
    975             }
    976             pad_rgb_pixels += bytes_per_row;
    977         }
    978     }
    979 
    980     if ((image_info->padding_options & PAD_BOTTOM) && (num_rows > 0) &&
    981             (start_row >= _get_height(image_info, image_info->padding_options & PAD_TOP))) {
    982         int blank_rows = MIN(num_rows,
    983                 _get_height(image_info, image_info->padding_options) - start_row);
    984         int bytesToBlank = (blank_rows * bytes_per_row);
    985         nbytes += bytesToBlank;
    986         num_rows -= blank_rows;
    987         *height += blank_rows;
    988         memset(rgb_pixels, 0xff, bytesToBlank);
    989         rgb_pixels += bytesToBlank;
    990     }
    991 
    992     return nbytes;
    993 }
    994 
    995 int wprint_image_compute_rows_to_cache(wprint_image_info_t *image_info) {
    996     int i;
    997     int row_width, max_rows;
    998     unsigned char output_mem;
    999     int available_mem = MAX_DECODE_MEM;
   1000     int width, height;
   1001 
   1002     width = image_info->sampled_width;
   1003     height = image_info->sampled_height;
   1004 
   1005     switch (image_info->rotation) {
   1006         case ROT_90:
   1007         case ROT_270:
   1008             output_mem = 1;
   1009             row_width = height;
   1010             break;
   1011         case ROT_0:
   1012         case ROT_180:
   1013         default:
   1014             output_mem = 0;
   1015             row_width = width;
   1016             break;
   1017     }
   1018 
   1019     available_mem -= (wprint_image_get_output_buff_size(image_info) *
   1020             image_info->concurrent_stripes);
   1021     if (image_info->unscaled_rows != NULL) {
   1022         // remove any memory allocated for scaling from our pool
   1023         available_mem -= BYTES_PER_PIXEL(
   1024                 image_info->unscaled_rows_needed * image_info->output_width);
   1025         available_mem -= image_info->mixed_memory_needed;
   1026     }
   1027 
   1028     // make sure we have a valid amount of memory to work with
   1029     available_mem = MAX(available_mem, MIN_DECODE_MEM);
   1030 
   1031     LOGD("wprint_image_compute_rows_to_cache(): %d bytes available for row caching", available_mem);
   1032 
   1033     row_width = BYTES_PER_PIXEL(row_width);
   1034     max_rows = (available_mem / row_width);
   1035 
   1036     if (max_rows > 0xf) {
   1037         max_rows &= ~0xf;
   1038     }
   1039 
   1040     LOGD("wprint_image_compute_rows_to_cache(): based on row width %d (%d), %d rows can be cached",
   1041             row_width, output_mem, max_rows);
   1042 
   1043     if (output_mem) {
   1044         if (max_rows > (MAX(width, height))) {
   1045             max_rows = MAX(width, height);
   1046         }
   1047 
   1048         image_info->output_cache = (unsigned char **) malloc(sizeof(unsigned char *) * max_rows);
   1049         for (i = 0; i < max_rows; i++) {
   1050             image_info->output_cache[i] = (unsigned char *) malloc(row_width);
   1051         }
   1052     } else {
   1053         max_rows = MIN(max_rows, height);
   1054     }
   1055 
   1056     image_info->rows_cached = max_rows;
   1057     LOGD("wprint_image_compute_rows_to_cache(): %d rows being cached", max_rows);
   1058 
   1059     return wprint_image_input_rows_cached(image_info);
   1060 }
   1061 
   1062 int wprint_image_input_rows_cached(wprint_image_info_t *image_info) {
   1063     return ((image_info->output_cache != NULL) ? 1 : image_info->rows_cached);
   1064 }
   1065 
   1066 void wprint_image_cleanup(wprint_image_info_t *image_info) {
   1067     int i;
   1068     const image_decode_ifc_t *decode_ifc = image_info->decode_ifc;
   1069 
   1070     if ((decode_ifc != NULL) && (decode_ifc->cleanup != NULL)) {
   1071         decode_ifc->cleanup(image_info);
   1072     }
   1073 
   1074     // free memory allocated for saving unscaled rows
   1075     if (image_info->unscaled_rows != NULL) {
   1076         free(image_info->unscaled_rows);
   1077         image_info->unscaled_rows = NULL;
   1078     }
   1079 
   1080     // free memory allocated needed for mixed scaling
   1081     if (image_info->mixed_memory != NULL) {
   1082         free(image_info->mixed_memory);
   1083         image_info->mixed_memory = NULL;
   1084     }
   1085 
   1086     if (image_info->output_cache != NULL) {
   1087         for (i = 0; i < image_info->rows_cached; i++) {
   1088             free(image_info->output_cache[i]);
   1089         }
   1090         free(image_info->output_cache);
   1091         image_info->output_cache = NULL;
   1092     }
   1093 }