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
wprint_image_setup(wprint_image_info_t * image_info,const char * mime_type,const ifc_wprint_t * wprint_ifc,unsigned int output_resolution,int pdf_render_resolution)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
wprint_image_get_info(FILE * imgfile,wprint_image_info_t * image_info)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
wprint_image_set_output_properties(wprint_image_info_t * image_info,wprint_rotation_t rotation,unsigned int printable_width,unsigned int printable_height,unsigned int top_margin,unsigned int left_margin,unsigned int right_margin,unsigned int bottom_margin,unsigned int render_flags,unsigned int max_decode_stripe,unsigned int concurrent_stripes,unsigned int padding_options)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 LOGD("wprint_image_set_output_properties(): input render flags - %d (0x%8.8x)",
552 input_render_flags, input_render_flags);
553 LOGD("wprint_image_set_output_properties(): printable area - %dx%d",
554 printable_width, printable_height);
555 LOGD("wprint_image_set_output_properties(): input margins: Top:%d Left:%d Right:%d Bottom:%d",
556 top_margin, left_margin, right_margin, bottom_margin);
557 LOGD("wprint_image_set_output_properties(): padding options: %d (0x%2.2x)",
558 image_info->padding_options, image_info->padding_options);
559 LOGD("wprint_image_set_output_properties(): concurrent stripes - %d",
560 image_info->concurrent_stripes);
561 LOGD("wprint_image_set_output_properties(): stripe height - %d", image_info->stripe_height);
562 LOGD("wprint_image_set_output_properties(): image dimensions: %dx%d",
563 image_info->width, image_info->height);
564 LOGD("wprint_image_set_output_properties(): image rotation: %d", image_info->rotation);
565 LOGD("wprint_image_set_output_properties(): final render flags - %d (0x%8.8x)",
566 image_info->render_flags, image_info->render_flags);
567 LOGD("wprint_image_set_output_properties(): printable area after margins - %dx%d",
568 image_info->printable_width, image_info->printable_height);
569 LOGD("wprint_image_set_output_properties(): output_padding: Top:%d Left:%d Right:%d Bottom:%d",
570 image_info->output_padding_top, image_info->output_padding_left,
571 image_info->output_padding_right, image_info->output_padding_bottom);
572 LOGD("wprint_image_set_output_properties(): output dimensions: %dx%d", image_info->output_width,
573 image_info->output_height);
574 LOGD("wprint_image_set_output_properties(): subsampled image dimensions - %dx%d",
575 image_info->sampled_width, image_info->sampled_height);
576 LOGD("wprint_image_set_output_properties(): scaled image dimensions - %dx%d",
577 image_info->scaled_width, image_info->scaled_height);
578 LOGD("wprint_image_set_output_properties(): image offsets - row: %d, col: %d",
579 image_info->row_offset, image_info->col_offset);
580 LOGD("wprint_image_set_output_properties(): margins - top: %d, left: %d, right: %d, bottom: %d",
581 image_info->output_padding_top, image_info->output_padding_left,
582 image_info->output_padding_right, image_info->output_padding_bottom);
583
584 return OK;
585 }
586
_get_width(wprint_image_info_t * image_info,unsigned int padding_options)587 static int _get_width(wprint_image_info_t *image_info, unsigned int padding_options) {
588 int width;
589 if (image_info->render_flags & RENDER_FLAG_AUTO_SCALE) {
590 width = image_info->printable_width;
591 } else if ((image_info->render_flags & RENDER_FLAG_AUTO_FIT) || image_info->scaling_needed) {
592 width = image_info->scaled_width;
593 } else {
594 width = image_info->output_width;
595 }
596 if (padding_options & PAD_LEFT) {
597 width += image_info->output_padding_left;
598 }
599 if (padding_options & PAD_RIGHT) {
600 width += image_info->output_padding_right;
601 }
602 return width;
603 }
604
wprint_image_get_width(wprint_image_info_t * image_info)605 int wprint_image_get_width(wprint_image_info_t *image_info) {
606 int width = _get_width(image_info, image_info->padding_options);
607 LOGD("wprint_image_get_width(): %d", width);
608 return width;
609 }
610
wprint_image_get_output_buff_size(wprint_image_info_t * image_info)611 int wprint_image_get_output_buff_size(wprint_image_info_t *image_info) {
612 int width = MAX(MAX(image_info->scaled_width, image_info->scaled_height),
613 _get_width(image_info, image_info->padding_options));
614 LOGD("wprint_image_get_output_buff_size(): %dx%d", width, image_info->output_rows);
615 return (BYTES_PER_PIXEL(width * image_info->output_rows));
616 }
617
_get_height(wprint_image_info_t * image_info,unsigned int padding_options)618 static int _get_height(wprint_image_info_t *image_info, unsigned int padding_options) {
619 int height;
620 if (image_info->render_flags & RENDER_FLAG_AUTO_SCALE) {
621 height = image_info->printable_height;
622 } else {
623 height = MIN(image_info->scaled_height, image_info->printable_height);
624 }
625 if (padding_options & PAD_TOP) {
626 height += image_info->output_padding_top;
627 }
628 if (padding_options & PAD_BOTTOM) {
629 height += image_info->output_padding_bottom;
630 }
631 return height;
632 }
633
wprint_image_get_height(wprint_image_info_t * image_info)634 int wprint_image_get_height(wprint_image_info_t *image_info) {
635 int height = _get_height(image_info, image_info->padding_options);
636 LOGD("wprint_image_get_height(): %d", height);
637 return height;
638 }
639
wprint_image_is_landscape(wprint_image_info_t * image_info)640 bool wprint_image_is_landscape(wprint_image_info_t *image_info) {
641 return (image_info->width > image_info->height);
642 }
643
_decode_stripe(wprint_image_info_t * image_info,int start_row,int num_rows,unsigned int padding_options,unsigned char * rgb_pixels)644 int _decode_stripe(wprint_image_info_t *image_info, int start_row, int num_rows,
645 unsigned int padding_options, unsigned char *rgb_pixels) {
646 int image_y, image_x;
647 unsigned char *image_data;
648 int nbytes = -1;
649 int rbytes;
650 int col_offset;
651 int old_num_rows;
652 const image_decode_ifc_t *decode_ifc = image_info->decode_ifc;
653 if ((decode_ifc == NULL) || (decode_ifc->decode_row == NULL)) {
654 return nbytes;
655 }
656
657 nbytes = 0;
658 start_row += image_info->row_offset;
659 rbytes = BYTES_PER_PIXEL(image_info->output_width);
660
661 // get padding values
662 int padding_left = ((padding_options & PAD_LEFT) ? BYTES_PER_PIXEL(
663 image_info->output_padding_left) : 0);
664 int padding_right = ((padding_options & PAD_RIGHT) ? BYTES_PER_PIXEL(
665 image_info->output_padding_right) : 0);
666
667 old_num_rows = ~num_rows;
668 switch (image_info->rotation) {
669 case ROT_90:
670 col_offset = BYTES_PER_PIXEL(image_info->col_offset);
671 while (num_rows > 0) {
672 if (start_row > image_info->sampled_width) {
673 return nbytes;
674 }
675 if (old_num_rows == num_rows) {
676 LOGE("Bad ROT_90 calculations. Exiting to prevent infinite loop");
677 return ERROR;
678 }
679 old_num_rows = num_rows;
680 if ((image_info->output_swath_start == -1) ||
681 (start_row < image_info->output_swath_start) ||
682 (start_row >= (image_info->output_swath_start + image_info->rows_cached))) {
683 if (image_info->output_swath_start == -1) {
684 if (decode_ifc->decode_row(image_info, 0) == NULL) {
685 return ERROR;
686 }
687 }
688 image_info->output_swath_start = ((start_row / image_info->rows_cached) *
689 image_info->rows_cached);
690 for (image_y = 0; image_y < image_info->sampled_height; image_y++) {
691 image_data = decode_ifc->decode_row(image_info, image_y);
692 if (image_data == NULL) {
693 return ERROR;
694 }
695 for (image_x = 0; (image_x < image_info->rows_cached &&
696 ((image_x + image_info->output_swath_start) <
697 image_info->sampled_width));
698 image_x++) {
699 memcpy(image_info->output_cache[image_x] + BYTES_PER_PIXEL(
700 (image_info->sampled_height - image_y - 1)),
701 image_data + BYTES_PER_PIXEL(
702 (image_info->output_swath_start + image_x)),
703 BYTES_PER_PIXEL(1));
704 }
705 }
706 }
707
708 for (image_y = start_row; ((num_rows != 0) &&
709 (image_y < image_info->sampled_width) &&
710 (image_y < (image_info->output_swath_start + image_info->rows_cached)));
711 image_y++, num_rows--, start_row++) {
712 memcpy(rgb_pixels + padding_left,
713 image_info->output_cache[image_y - image_info->output_swath_start] +
714 col_offset, rbytes);
715 nbytes += rbytes + padding_left + padding_right;
716 rgb_pixels += rbytes + padding_left + padding_right;
717 }
718 }
719 break;
720 case ROT_180:
721 col_offset = image_info->col_offset;
722 for (image_y = start_row;
723 ((image_y < image_info->sampled_height) && (num_rows != 0));
724 image_y++, num_rows--) {
725 image_data = decode_ifc->decode_row(image_info,
726 (image_info->sampled_height - image_y - 1));
727 if (image_data == NULL) {
728 return ERROR;
729 }
730 for (image_x = 0; image_x < image_info->output_width; image_x++) {
731 memcpy(rgb_pixels + padding_left + BYTES_PER_PIXEL(image_x),
732 image_data + BYTES_PER_PIXEL(image_info->sampled_width -
733 image_x - col_offset - 1),
734 BYTES_PER_PIXEL(1));
735 }
736 nbytes += rbytes + padding_left + padding_right;
737 rgb_pixels += rbytes + padding_left + padding_right;
738 }
739 break;
740 case ROT_270:
741 col_offset = BYTES_PER_PIXEL(image_info->col_offset);
742 while (num_rows > 0) {
743 if (start_row > image_info->sampled_width) {
744 return nbytes;
745 }
746 if (old_num_rows == num_rows) {
747 LOGE("Bad ROT_270 calculations. Erroring out to prevent infinite loop.");
748 return ERROR;
749 }
750 old_num_rows = num_rows;
751 if ((image_info->output_swath_start == -1) ||
752 (start_row < image_info->output_swath_start) ||
753 (start_row >= (image_info->output_swath_start + image_info->rows_cached))) {
754 if (image_info->output_swath_start == -1) {
755 if (decode_ifc->decode_row(image_info, 0) == NULL) {
756 return ERROR;
757 }
758 }
759 image_info->output_swath_start = ((start_row / image_info->rows_cached) *
760 image_info->rows_cached);
761 for (image_y = 0; image_y < image_info->sampled_height; image_y++) {
762 image_data = decode_ifc->decode_row(image_info, image_y);
763 if (image_data == NULL) {
764 return ERROR;
765 }
766 for (image_x = 0; ((image_x < image_info->rows_cached) &&
767 ((image_x + image_info->output_swath_start) <
768 image_info->sampled_width));
769 image_x++) {
770 memcpy(image_info->output_cache[image_x] + BYTES_PER_PIXEL(image_y),
771 image_data + BYTES_PER_PIXEL(image_info->sampled_width -
772 (image_info->output_swath_start +
773 image_x) - 1),
774 BYTES_PER_PIXEL(1));
775 }
776 }
777 }
778 for (image_y = start_row;
779 ((num_rows != 0) &&
780 (image_y < image_info->sampled_width) &&
781 (image_y < (image_info->output_swath_start
782 + image_info->rows_cached)));
783 image_y++, num_rows--, start_row++) {
784 memcpy(rgb_pixels + padding_left,
785 image_info->output_cache[image_y - image_info->output_swath_start] +
786 col_offset, rbytes);
787 nbytes += rbytes + padding_left + padding_right;
788 rgb_pixels += rbytes + padding_left + padding_right;
789 }
790 }
791 break;
792 case ROT_0:
793 default:
794 col_offset = BYTES_PER_PIXEL(image_info->col_offset);
795 for (image_y = start_row;
796 ((image_y < image_info->sampled_height) && (num_rows != 0));
797 image_y++, num_rows--) {
798 image_data = decode_ifc->decode_row(image_info, image_y);
799 if (image_data == NULL) {
800 LOGE("ERROR: received no data for row: %d", image_y);
801 return ERROR;
802 }
803 memcpy(rgb_pixels + padding_left, image_data + col_offset, rbytes);
804 nbytes += rbytes + padding_left + padding_right;
805 rgb_pixels += rbytes + padding_left + padding_right;
806 }
807 break;
808 }
809 return nbytes;
810 }
811
wprint_image_decode_stripe(wprint_image_info_t * image_info,int start_row,int * height,unsigned char * rgb_pixels)812 int wprint_image_decode_stripe(wprint_image_info_t *image_info, int start_row, int *height,
813 unsigned char *rgb_pixels) {
814 int nbytes = 0;
815 int bytes_per_row = BYTES_PER_PIXEL(_get_width(image_info, image_info->padding_options));
816
817 if (height == NULL) {
818 return -1;
819 }
820
821 int num_rows = *height;
822
823 *height = 0;
824
825 // get padding values
826 int padding_left = ((image_info->padding_options & PAD_LEFT) ? BYTES_PER_PIXEL(
827 image_info->output_padding_left) : 0);
828 int padding_right = ((image_info->padding_options & PAD_RIGHT) ? BYTES_PER_PIXEL(
829 image_info->output_padding_right) : 0);
830 int padding_top = ((image_info->padding_options & PAD_TOP) ?
831 image_info->output_padding_top : 0);
832 // handle invalid requests
833 if ((start_row < 0) || (start_row >= _get_height(image_info, image_info->padding_options))) {
834 *height = 0;
835 return ERROR;
836 } else if ((image_info->padding_options & PAD_TOP) &&
837 (start_row < padding_top)) {
838 int blank_rows = MIN(num_rows, (padding_top - start_row));
839 int bytesToBlank = (blank_rows * bytes_per_row);
840 nbytes += bytesToBlank;
841 num_rows -= blank_rows;
842 *height += blank_rows;
843 memset(rgb_pixels, 0xff, bytesToBlank);
844 rgb_pixels += bytesToBlank;
845 start_row += blank_rows;
846 } else if ((image_info->padding_options & PAD_BOTTOM) &&
847 (start_row >= _get_height(image_info, image_info->padding_options & PAD_TOP))) {
848 // handle image padding on bottom
849 int blank_rows = MIN(num_rows,
850 _get_height(image_info, image_info->padding_options) - start_row);
851 int bytesToBlank = (blank_rows * bytes_per_row);
852 nbytes += bytesToBlank;
853 num_rows -= blank_rows;
854 *height += blank_rows;
855 memset(rgb_pixels, 0xff, bytesToBlank);
856 rgb_pixels += bytesToBlank;
857 start_row += blank_rows;
858 }
859
860 if (num_rows <= 0) {
861 return nbytes;
862 }
863
864 unsigned char *pad_rgb_pixels = rgb_pixels;
865 int unpadded_start_row = start_row;
866 // adjust start row to fit within image bounds
867 if (image_info->padding_options & PAD_TOP) {
868 unpadded_start_row -= padding_top;
869 }
870
871 // check if we need to scaling
872 if (image_info->scaling_needed) {
873 // scaling required
874 uint32 scaled_start_row = unpadded_start_row;
875 if (image_info->scaled_height > image_info->printable_height) {
876 scaled_start_row += ((image_info->scaled_height - image_info->printable_height) / 2);
877 }
878 uint32 stripe_height, mixed;
879 uint16 unscaled_row_start, unscaled_row_end;
880 uint16 generated_rows, row_offset;
881 uint32 predecoded_rows;
882
883 int scaled_num_rows = (((scaled_start_row + num_rows) > image_info->scaled_height) ?
884 (image_info->scaled_height - scaled_start_row) : num_rows);
885 while (scaled_num_rows > 0) {
886 stripe_height = MIN(scaled_num_rows, image_info->stripe_height);
887 scaler_calculate_scaling_rows(scaled_start_row,
888 MIN((scaled_start_row + stripe_height - 1),
889 (image_info->scaled_height - 1)), (void *) &image_info->scaler_config,
890 &unscaled_row_start, &unscaled_row_end, &generated_rows, &row_offset, &mixed);
891
892 if (mixed > image_info->mixed_memory_needed) {
893 LOGE("need more memory");
894 return -1;
895 }
896
897 predecoded_rows = 0;
898 if (unscaled_row_start <= image_info->unscaled_end_row) {
899 // shift over any rows we need that were decoded in the previous pass
900 predecoded_rows = (image_info->unscaled_end_row - unscaled_row_start) + 1;
901
902 memmove(image_info->unscaled_rows, image_info->unscaled_rows +
903 BYTES_PER_PIXEL(((unscaled_row_start - image_info->unscaled_start_row) *
904 image_info->output_width)),
905 BYTES_PER_PIXEL((predecoded_rows * image_info->output_width)));
906 }
907
908 image_info->unscaled_start_row = unscaled_row_start;
909 image_info->unscaled_end_row = unscaled_row_end;
910
911 /*
912 * decode the remaining rows we need
913 * don't pad the output since we need to move the data after scaling anyways
914 */
915 int rowsLeftToDecode = ((image_info->unscaled_end_row -
916 (image_info->unscaled_start_row + predecoded_rows)) + 1);
917 if (rowsLeftToDecode > 0) {
918 int dbytes = _decode_stripe(image_info,
919 image_info->unscaled_start_row + predecoded_rows, rowsLeftToDecode,
920 PAD_NONE, (image_info->unscaled_rows + BYTES_PER_PIXEL(predecoded_rows *
921 image_info->output_width)));
922 if (dbytes <= 0) {
923 if (dbytes < 0) {
924 LOGE("couldn't decode rows");
925 }
926 return dbytes;
927 }
928 } else if (predecoded_rows <= 0) {
929 return 0;
930 }
931
932 // scale the data to it's final size
933 scaler_scale_image_data(image_info->unscaled_rows, (void *) &image_info->scaler_config,
934 rgb_pixels, image_info->mixed_memory);
935 // do we have to move the data around??
936 if ((row_offset != 0) ||
937 (image_info->scaled_width > image_info->printable_width) ||
938 (padding_left > 0) ||
939 (padding_right > 0)) {
940 int delta = 0;
941 int pixelsToMove = BYTES_PER_PIXEL(MIN(image_info->scaled_width,
942 image_info->printable_width));
943
944 int memMoveRow = ((bytes_per_row < image_info->scaler_config.iOutBufWidth) ? 0 : (
945 stripe_height - 1));
946 int memMoveIncrement = ((bytes_per_row < image_info->scaler_config.iOutBufWidth)
947 ? 1 : -1);
948
949 // if scaled width is greater than the printable area drop pixels on either size
950 if (image_info->scaled_width > image_info->printable_width) {
951 delta = BYTES_PER_PIXEL(
952 ((image_info->scaled_width - image_info->printable_width) / 2));
953 }
954
955 // move the data into the correct location in the output buffer
956 for (generated_rows = 0; generated_rows < stripe_height; generated_rows++,
957 memMoveRow += memMoveIncrement) {
958 memmove(rgb_pixels + (memMoveRow * bytes_per_row) + padding_left,
959 rgb_pixels + ((memMoveRow + row_offset) *
960 image_info->scaler_config.iOutBufWidth) + delta, pixelsToMove);
961 }
962 }
963
964 num_rows -= stripe_height;
965 scaled_num_rows -= stripe_height;
966 scaled_start_row += stripe_height;
967 nbytes += (bytes_per_row * stripe_height);
968 rgb_pixels += (bytes_per_row * stripe_height);
969 *height += stripe_height;
970 start_row += stripe_height;
971 }
972 } else {
973 // no scaling needed
974
975 // decode the request
976 int dbytes = _decode_stripe(image_info, unpadded_start_row,
977 (((unpadded_start_row + num_rows) >
978 _get_height(image_info, PAD_NONE)) ?
979 (_get_height(image_info, PAD_NONE) - unpadded_start_row)
980 : num_rows),
981 image_info->padding_options, rgb_pixels);
982 if (dbytes <= 0) {
983 if (dbytes < 0) {
984 LOGE("couldn't decode rows");
985 }
986 return dbytes;
987 }
988
989 int rows = (dbytes / bytes_per_row);
990 *height += rows;
991 num_rows -= rows;
992 start_row += rows;
993 unpadded_start_row += rows;
994 rgb_pixels += dbytes;
995 nbytes += dbytes;
996 }
997
998 // white pad the left and right edges
999 if ((pad_rgb_pixels != rgb_pixels) &&
1000 (image_info->padding_options & (PAD_LEFT | PAD_RIGHT)) &&
1001 ((padding_left != 0) || (padding_right != 0))) {
1002 while (pad_rgb_pixels != rgb_pixels) {
1003 if (padding_left != 0) {
1004 memset(pad_rgb_pixels, 0xff, padding_left);
1005 }
1006 if (padding_right != 0) {
1007 memset(pad_rgb_pixels + (bytes_per_row - padding_right), 0xff, padding_right);
1008 }
1009 pad_rgb_pixels += bytes_per_row;
1010 }
1011 }
1012
1013 if ((image_info->padding_options & PAD_BOTTOM) && (num_rows > 0) &&
1014 (start_row >= _get_height(image_info, image_info->padding_options & PAD_TOP))) {
1015 int blank_rows = MIN(num_rows,
1016 _get_height(image_info, image_info->padding_options) - start_row);
1017 int bytesToBlank = (blank_rows * bytes_per_row);
1018 nbytes += bytesToBlank;
1019 num_rows -= blank_rows;
1020 *height += blank_rows;
1021 memset(rgb_pixels, 0xff, bytesToBlank);
1022 rgb_pixels += bytesToBlank;
1023 }
1024
1025 return nbytes;
1026 }
1027
wprint_image_compute_rows_to_cache(wprint_image_info_t * image_info)1028 int wprint_image_compute_rows_to_cache(wprint_image_info_t *image_info) {
1029 int i;
1030 int row_width, max_rows;
1031 unsigned char output_mem;
1032 int available_mem = MAX_DECODE_MEM;
1033 int width, height;
1034
1035 width = image_info->sampled_width;
1036 height = image_info->sampled_height;
1037
1038 switch (image_info->rotation) {
1039 case ROT_90:
1040 case ROT_270:
1041 output_mem = 1;
1042 row_width = height;
1043 break;
1044 case ROT_0:
1045 case ROT_180:
1046 default:
1047 output_mem = 0;
1048 row_width = width;
1049 break;
1050 }
1051
1052 available_mem -= (wprint_image_get_output_buff_size(image_info) *
1053 image_info->concurrent_stripes);
1054 if (image_info->unscaled_rows != NULL) {
1055 // remove any memory allocated for scaling from our pool
1056 available_mem -= BYTES_PER_PIXEL(
1057 image_info->unscaled_rows_needed * image_info->output_width);
1058 available_mem -= image_info->mixed_memory_needed;
1059 }
1060
1061 // make sure we have a valid amount of memory to work with
1062 available_mem = MAX(available_mem, MIN_DECODE_MEM);
1063
1064 LOGD("wprint_image_compute_rows_to_cache(): %d bytes available for row caching", available_mem);
1065
1066 row_width = BYTES_PER_PIXEL(row_width);
1067 max_rows = (available_mem / row_width);
1068
1069 if (max_rows > 0xf) {
1070 max_rows &= ~0xf;
1071 }
1072
1073 LOGD("wprint_image_compute_rows_to_cache(): based on row width %d (%d), %d rows can be cached",
1074 row_width, output_mem, max_rows);
1075
1076 if (output_mem) {
1077 if (max_rows > (MAX(width, height))) {
1078 max_rows = MAX(width, height);
1079 }
1080
1081 image_info->output_cache = (unsigned char **) malloc(sizeof(unsigned char *) * max_rows);
1082 for (i = 0; i < max_rows; i++) {
1083 image_info->output_cache[i] = (unsigned char *) malloc(row_width);
1084 }
1085 } else {
1086 max_rows = MIN(max_rows, height);
1087 }
1088
1089 image_info->rows_cached = max_rows;
1090 LOGD("wprint_image_compute_rows_to_cache(): %d rows being cached", max_rows);
1091
1092 return wprint_image_input_rows_cached(image_info);
1093 }
1094
wprint_image_input_rows_cached(wprint_image_info_t * image_info)1095 int wprint_image_input_rows_cached(wprint_image_info_t *image_info) {
1096 return ((image_info->output_cache != NULL) ? 1 : image_info->rows_cached);
1097 }
1098
wprint_image_cleanup(wprint_image_info_t * image_info)1099 void wprint_image_cleanup(wprint_image_info_t *image_info) {
1100 int i;
1101 const image_decode_ifc_t *decode_ifc = image_info->decode_ifc;
1102
1103 if ((decode_ifc != NULL) && (decode_ifc->cleanup != NULL)) {
1104 decode_ifc->cleanup(image_info);
1105 }
1106
1107 // free memory allocated for saving unscaled rows
1108 if (image_info->unscaled_rows != NULL) {
1109 free(image_info->unscaled_rows);
1110 image_info->unscaled_rows = NULL;
1111 }
1112
1113 // free memory allocated needed for mixed scaling
1114 if (image_info->mixed_memory != NULL) {
1115 free(image_info->mixed_memory);
1116 image_info->mixed_memory = NULL;
1117 }
1118
1119 if (image_info->output_cache != NULL) {
1120 for (i = 0; i < image_info->rows_cached; i++) {
1121 free(image_info->output_cache[i]);
1122 }
1123 free(image_info->output_cache);
1124 image_info->output_cache = NULL;
1125 }
1126 }