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