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