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