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
28void 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
41status_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
84status_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
554static 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
572int 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
578int 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
585static 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
601int 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
607bool wprint_image_is_landscape(wprint_image_info_t *image_info) {
608    return (image_info->width > image_info->height);
609}
610
611int _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
779int 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
995int 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
1062int 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
1066void 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}