1126 lines
49 KiB
C
Executable File
1126 lines
49 KiB
C
Executable File
/*
|
|
* Copyright (C) 2016 The Android Open Source Project
|
|
* Copyright (C) 2016 Mopria Alliance, Inc.
|
|
* Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#include "wprint_image.h"
|
|
#include "lib_wprint.h"
|
|
|
|
#define TAG "wprint_image"
|
|
#define MIN_DECODE_MEM (1 * 1024 * 1024)
|
|
#define MAX_DECODE_MEM (4 * 1024 * 1024)
|
|
|
|
void 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) {
|
|
if (image_info != NULL) {
|
|
LOGD("image_setup");
|
|
memset(image_info, 0, sizeof(wprint_image_info_t));
|
|
image_info->wprint_ifc = wprint_ifc;
|
|
image_info->mime_type = mime_type;
|
|
image_info->print_resolution = output_resolution;
|
|
image_info->pdf_render_resolution = pdf_render_resolution;
|
|
}
|
|
}
|
|
|
|
status_t wprint_image_get_info(FILE *imgfile, wprint_image_info_t *image_info) {
|
|
if (image_info == NULL) return ERROR;
|
|
|
|
image_info->imgfile = imgfile;
|
|
image_info->rotation = ROT_0;
|
|
image_info->swath_start = -1;
|
|
image_info->rows_cached = 0;
|
|
image_info->output_cache = NULL;
|
|
image_info->output_swath_start = -1;
|
|
image_info->scaled_sample_size = 1;
|
|
|
|
image_info->stripe_height = 0;
|
|
image_info->unscaled_rows = NULL;
|
|
image_info->unscaled_rows_needed = 0;
|
|
image_info->mixed_memory = NULL;
|
|
image_info->mixed_memory_needed = 0;
|
|
image_info->scaled_width = -1;
|
|
image_info->scaled_height = -1;
|
|
image_info->unscaled_start_row = -1;
|
|
image_info->unscaled_end_row = -1;
|
|
image_info->scaling_needed = FALSE;
|
|
|
|
image_info->output_padding_top = 0;
|
|
image_info->output_padding_left = 0;
|
|
image_info->output_padding_right = 0;
|
|
image_info->output_padding_bottom = 0;
|
|
|
|
const image_decode_ifc_t *decode_ifc = image_info->decode_ifc;
|
|
|
|
if ((decode_ifc != NULL) && (decode_ifc->get_hdr != NULL)) {
|
|
if (OK == decode_ifc->get_hdr(image_info)) {
|
|
LOGI("wprint_image_get_info(): %s dim = %dx%d", image_info->mime_type,
|
|
image_info->width, image_info->height);
|
|
return OK;
|
|
} else {
|
|
LOGE("ERROR: get_hdr for %s", image_info->mime_type);
|
|
return ERROR;
|
|
}
|
|
}
|
|
LOGE("Unsupported image type: %s", image_info->mime_type);
|
|
return ERROR;
|
|
}
|
|
|
|
status_t 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) {
|
|
// validate rotation
|
|
switch (rotation) {
|
|
default:
|
|
rotation = ROT_0;
|
|
case ROT_0:
|
|
case ROT_90:
|
|
case ROT_180:
|
|
case ROT_270:
|
|
break;
|
|
}
|
|
|
|
// rotate margins
|
|
switch (rotation) {
|
|
case ROT_90:
|
|
case ROT_270: {
|
|
unsigned int temp;
|
|
temp = top_margin;
|
|
top_margin = left_margin;
|
|
left_margin = bottom_margin;
|
|
bottom_margin = right_margin;
|
|
right_margin = temp;
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
unsigned int input_render_flags = render_flags;
|
|
|
|
// store padding options
|
|
image_info->padding_options = (padding_options & PAD_ALL);
|
|
|
|
// store margin adjusted printable area
|
|
image_info->printable_width = printable_width - (left_margin + right_margin);
|
|
image_info->printable_height = printable_height - (top_margin + bottom_margin);
|
|
|
|
// store rendering parameters
|
|
image_info->render_flags = render_flags;
|
|
image_info->output_rows = max_decode_stripe;
|
|
image_info->stripe_height = max_decode_stripe;
|
|
image_info->concurrent_stripes = concurrent_stripes;
|
|
|
|
// free data just in case
|
|
if (image_info->unscaled_rows != NULL) {
|
|
free(image_info->unscaled_rows);
|
|
}
|
|
|
|
// free data just in case
|
|
if (image_info->mixed_memory != NULL) {
|
|
free(image_info->mixed_memory);
|
|
}
|
|
|
|
image_info->row_offset = 0;
|
|
image_info->col_offset = 0;
|
|
image_info->scaled_sample_size = 1;
|
|
image_info->scaled_width = -1;
|
|
image_info->scaled_height = -1;
|
|
image_info->unscaled_start_row = -1;
|
|
image_info->unscaled_end_row = -1;
|
|
image_info->unscaled_rows = NULL;
|
|
image_info->unscaled_rows_needed = 0;
|
|
image_info->mixed_memory = NULL;
|
|
image_info->mixed_memory_needed = 0;
|
|
image_info->rotation = rotation;
|
|
|
|
unsigned int image_output_width;
|
|
unsigned int image_output_height;
|
|
|
|
// save margins
|
|
switch (image_info->rotation) {
|
|
case ROT_180:
|
|
case ROT_270:
|
|
image_info->output_padding_top = bottom_margin;
|
|
image_info->output_padding_left = right_margin;
|
|
image_info->output_padding_right = left_margin;
|
|
image_info->output_padding_bottom = top_margin;
|
|
break;
|
|
case ROT_0:
|
|
case ROT_90:
|
|
default:
|
|
image_info->output_padding_top = top_margin;
|
|
image_info->output_padding_left = left_margin;
|
|
image_info->output_padding_right = right_margin;
|
|
image_info->output_padding_bottom = bottom_margin;
|
|
break;
|
|
}
|
|
|
|
// swap dimensions
|
|
switch (image_info->rotation) {
|
|
case ROT_90:
|
|
case ROT_270:
|
|
image_output_width = image_info->height;
|
|
image_output_height = image_info->width;
|
|
break;
|
|
case ROT_0:
|
|
case ROT_180:
|
|
default:
|
|
image_output_width = image_info->width;
|
|
image_output_height = image_info->height;
|
|
break;
|
|
}
|
|
|
|
int native_units = 0;
|
|
|
|
const image_decode_ifc_t *decode_ifc = image_info->decode_ifc;
|
|
if ((image_info->render_flags & RENDER_FLAG_AUTO_FIT) && (decode_ifc != NULL) &&
|
|
(decode_ifc->native_units != NULL)) {
|
|
native_units = decode_ifc->native_units(image_info);
|
|
}
|
|
|
|
if (native_units <= 0) {
|
|
native_units = image_info->print_resolution;
|
|
}
|
|
|
|
float native_scaling = 1.0f;
|
|
unsigned int native_image_output_width = image_output_width;
|
|
unsigned int native_image_output_height = image_output_height;
|
|
|
|
if ((native_units != image_info->print_resolution)
|
|
&& !((image_info->render_flags & RENDER_FLAG_AUTO_SCALE)
|
|
|| ((image_info->render_flags & RENDER_FLAG_AUTO_FIT)
|
|
&& !(image_info->render_flags & RENDER_FLAG_DOCUMENT_SCALING)))) {
|
|
native_scaling = (image_info->print_resolution * 1.0f) / (native_units * 1.0f);
|
|
native_image_output_width = (int) floorf(image_output_width * native_scaling);
|
|
native_image_output_height = (int) floorf(image_output_height * native_scaling);
|
|
LOGD("need to do native scaling by %f factor to size %dx%d", native_scaling,
|
|
native_image_output_width, native_image_output_height);
|
|
}
|
|
|
|
// if we have to scale determine if we can use subsampling to scale down
|
|
if ((image_info->render_flags & (RENDER_FLAG_AUTO_SCALE | RENDER_FLAG_AUTO_FIT)) &&
|
|
(native_scaling == 1.0f)) {
|
|
LOGD("calculating subsampling");
|
|
|
|
/*
|
|
* Find a subsampling scale factor that produces an image that is still bigger
|
|
* than the printable area and then finish scaling later using the fine-scaler.
|
|
* This produces better quality than subsampling to a smaller size and scaling up.
|
|
*/
|
|
image_info->scaled_sample_size = 1;
|
|
if ((decode_ifc != NULL) && (decode_ifc->supports_subsampling(image_info) == OK)) {
|
|
// subsampling supported
|
|
int next_width, next_height;
|
|
next_width = image_output_width >> 1;
|
|
next_height = image_output_height >> 1;
|
|
while (((image_info->render_flags & RENDER_FLAG_AUTO_SCALE) &&
|
|
(next_width > image_info->printable_width) &&
|
|
(next_height > image_info->printable_height)) ||
|
|
((image_info->render_flags & RENDER_FLAG_AUTO_FIT) &&
|
|
((next_width > image_info->printable_width) ||
|
|
(next_height > image_info->printable_height)))) {
|
|
image_info->scaled_sample_size <<= 1;
|
|
next_width >>= 1;
|
|
next_height >>= 1;
|
|
}
|
|
}
|
|
|
|
LOGD("calculated sample size: %d", image_info->scaled_sample_size);
|
|
|
|
// are we dong any subsampling?
|
|
if (image_info->scaled_sample_size > 1) {
|
|
// force the decoder to close and reopen with the new sample size setting
|
|
decode_ifc->cleanup(image_info);
|
|
decode_ifc->get_hdr(image_info);
|
|
|
|
// update the output size
|
|
image_output_width /= image_info->scaled_sample_size;
|
|
image_output_height /= image_info->scaled_sample_size;
|
|
}
|
|
|
|
/*
|
|
* have we reached our target size with subsampling?
|
|
* if so disable further scaling
|
|
*/
|
|
// check if width matches and height meets criteria
|
|
if ((image_output_width == image_info->printable_width) &&
|
|
(((image_info->render_flags & RENDER_FLAG_AUTO_SCALE) &&
|
|
(image_output_height >= image_info->printable_height)) ||
|
|
((image_info->render_flags & RENDER_FLAG_AUTO_FIT) &&
|
|
(image_output_height < image_info->printable_height)))) {
|
|
LOGD("disabling fine scaling since width matches and height meets criteria");
|
|
image_info->render_flags &= ~(RENDER_FLAG_AUTO_SCALE | RENDER_FLAG_AUTO_FIT);
|
|
} else if ((image_output_height == image_info->printable_height) &&
|
|
(((image_info->render_flags & RENDER_FLAG_AUTO_SCALE) &&
|
|
(image_output_width >= image_info->printable_width)) ||
|
|
((image_info->render_flags & RENDER_FLAG_AUTO_FIT) &&
|
|
(image_output_width < image_info->printable_width)))) {
|
|
// height matches and width meets criteria
|
|
LOGD("disabling fine scaling since height matches and width meets criteria");
|
|
image_info->render_flags &= ~(RENDER_FLAG_AUTO_SCALE | RENDER_FLAG_AUTO_FIT);
|
|
}
|
|
|
|
if ((image_info->render_flags & RENDER_FLAG_DOCUMENT_SCALING)
|
|
&& (image_output_height <= image_info->printable_height)
|
|
&& (image_output_width <= image_info->printable_width)) {
|
|
image_info->render_flags &= ~(RENDER_FLAG_AUTO_SCALE | RENDER_FLAG_AUTO_FIT);
|
|
}
|
|
} else if ((native_scaling != 1.0f) &&
|
|
(image_info->render_flags & RENDER_FLAG_DOCUMENT_SCALING)) {
|
|
LOGD("checking native document scaling factor");
|
|
if ((native_image_output_height <= image_info->printable_height)
|
|
&& (native_image_output_width <= image_output_width
|
|
<= image_info->printable_width)) {
|
|
LOGD("fit in printable area, just scale to native units");
|
|
image_info->render_flags &= ~(RENDER_FLAG_AUTO_SCALE | RENDER_FLAG_AUTO_FIT);
|
|
} else {
|
|
LOGD("we don't fit in printable area, continue with fit-to-page");
|
|
native_scaling = 1.0f;
|
|
}
|
|
}
|
|
|
|
// store the subsampled dimensions
|
|
image_info->sampled_width = (image_info->width / image_info->scaled_sample_size);
|
|
image_info->sampled_height = (image_info->height / image_info->scaled_sample_size);
|
|
|
|
// do we have any additional scaling to do?
|
|
if ((image_info->render_flags & (RENDER_FLAG_AUTO_SCALE | RENDER_FLAG_AUTO_FIT))
|
|
|| (native_scaling != 1.0f)) {
|
|
LOGD("calculating fine-scaling");
|
|
int i;
|
|
float targetHeight, targetWidth;
|
|
float sourceHeight, sourceWidth;
|
|
float rw;
|
|
int useHeight;
|
|
|
|
sourceWidth = image_output_width * 1.0f;
|
|
sourceHeight = image_output_height * 1.0f;
|
|
|
|
if (image_info->render_flags & (RENDER_FLAG_AUTO_SCALE | RENDER_FLAG_AUTO_FIT)) {
|
|
targetHeight = image_info->printable_height * 1.0f;
|
|
targetWidth = image_info->printable_width * 1.0f;
|
|
|
|
// determine what our bounding edge is
|
|
rw = (targetHeight * sourceWidth) / sourceHeight;
|
|
if (image_info->render_flags & RENDER_FLAG_AUTO_SCALE) {
|
|
useHeight = (rw >= targetWidth);
|
|
} else {
|
|
useHeight = (rw < targetWidth);
|
|
}
|
|
|
|
// determine the scaling factor
|
|
if (useHeight) {
|
|
image_info->scaled_width = (int) floorf(rw);
|
|
image_info->scaled_height = (int) floorf(targetHeight);
|
|
} else {
|
|
image_info->scaled_height = (int) floorf(targetWidth * sourceHeight / sourceWidth);
|
|
image_info->scaled_width = (int) floorf(targetWidth);
|
|
}
|
|
} else {
|
|
image_info->scaled_height = native_image_output_height;
|
|
image_info->scaled_width = native_image_output_width;
|
|
}
|
|
image_info->scaling_needed = TRUE;
|
|
|
|
/*
|
|
* setup the fine-scaler
|
|
* we use rotated image_output_width rather than the pre-rotated sampled_width
|
|
*/
|
|
scaler_make_image_scaler_tables(image_output_width, BYTES_PER_PIXEL(image_output_width),
|
|
image_info->scaled_width, BYTES_PER_PIXEL(image_info->scaled_width),
|
|
image_output_height, image_info->scaled_height, &image_info->scaler_config);
|
|
|
|
image_info->unscaled_rows_needed = 0;
|
|
image_info->mixed_memory_needed = 0;
|
|
|
|
// calculate memory requirements
|
|
for (i = 0; i < image_info->printable_height; i += max_decode_stripe) {
|
|
uint16 row;
|
|
uint16 row_start, row_end, gen_rows, row_offset;
|
|
uint32 mixed;
|
|
row = i;
|
|
if (row >= image_info->scaled_height) {
|
|
break;
|
|
}
|
|
scaler_calculate_scaling_rows(row,
|
|
MIN((row + (max_decode_stripe - 1)),
|
|
(image_info->scaled_height - 1)),
|
|
(void *) &image_info->scaler_config,
|
|
&row_start, &row_end, &gen_rows,
|
|
&row_offset, &mixed);
|
|
|
|
image_info->output_rows = MAX(image_info->output_rows, gen_rows);
|
|
image_info->unscaled_rows_needed = MAX(image_info->unscaled_rows_needed,
|
|
((row_end - row_start) + 3));
|
|
image_info->mixed_memory_needed = MAX(image_info->mixed_memory_needed, mixed);
|
|
}
|
|
int unscaled_size = BYTES_PER_PIXEL(
|
|
(MAX(image_output_width, image_output_height) * image_info->unscaled_rows_needed));
|
|
|
|
// allocate memory required for scaling
|
|
image_info->unscaled_rows = malloc(unscaled_size);
|
|
|
|
if (image_info->unscaled_rows != NULL) {
|
|
memset(image_info->unscaled_rows, 0xff, unscaled_size);
|
|
}
|
|
image_info->mixed_memory = (image_info->mixed_memory_needed != 0) ? malloc(
|
|
image_info->mixed_memory_needed) : NULL;
|
|
} else {
|
|
image_info->scaled_height = image_output_height;
|
|
image_info->scaled_width = image_output_width;
|
|
}
|
|
|
|
// final calculations
|
|
if ((image_info->render_flags & (RENDER_FLAG_AUTO_SCALE | RENDER_FLAG_AUTO_FIT)) ||
|
|
image_info->scaling_needed) {
|
|
/* use the full image size since both of the dimensions could be greater than
|
|
* the printable area */
|
|
image_info->output_width = image_output_width;
|
|
image_info->output_height = image_output_height;
|
|
} else {
|
|
// clip the image within the printable area
|
|
image_info->output_width = MIN(image_info->printable_width, image_output_width);
|
|
image_info->output_height = MIN(image_info->printable_height, image_output_height);
|
|
}
|
|
|
|
int delta;
|
|
switch (image_info->rotation) {
|
|
case ROT_90:
|
|
if (image_info->render_flags & RENDER_FLAG_AUTO_SCALE) {
|
|
} else if (image_info->render_flags & RENDER_FLAG_CENTER_HORIZONTAL) {
|
|
if (image_info->scaled_width > image_info->printable_width) {
|
|
image_info->col_offset = (
|
|
(image_info->scaled_width - image_info->printable_width) / 2);
|
|
} else {
|
|
int paddingDelta = (image_info->printable_width - image_info->scaled_width);
|
|
delta = paddingDelta / 2;
|
|
image_info->output_padding_left += delta;
|
|
image_info->output_padding_right += delta + (paddingDelta & 0x1);
|
|
}
|
|
} else if (image_info->scaled_width > image_info->printable_width) {
|
|
image_info->col_offset = (image_info->scaled_width - image_info->printable_width);
|
|
} else if (image_info->scaled_width < image_info->printable_width) {
|
|
image_info->output_padding_right += (image_info->printable_width -
|
|
image_info->scaled_width);
|
|
}
|
|
|
|
if (image_info->render_flags & RENDER_FLAG_AUTO_SCALE) {
|
|
} else if (image_info->render_flags & RENDER_FLAG_CENTER_VERTICAL) {
|
|
if (image_info->scaled_height > image_info->printable_height) {
|
|
image_info->row_offset = (
|
|
(image_info->scaled_height - image_info->printable_height) / 2);
|
|
} else {
|
|
int paddingDelta = (image_info->printable_height - image_info->scaled_height);
|
|
delta = paddingDelta / 2;
|
|
image_info->output_padding_top += delta;
|
|
image_info->output_padding_bottom += delta + (paddingDelta & 0x1);
|
|
}
|
|
} else if (image_info->scaled_height < image_info->printable_height) {
|
|
image_info->output_padding_bottom += (image_info->printable_height -
|
|
image_info->scaled_height);
|
|
}
|
|
break;
|
|
case ROT_180:
|
|
if (image_info->render_flags & RENDER_FLAG_AUTO_SCALE) {
|
|
} else if (image_info->render_flags & RENDER_FLAG_CENTER_HORIZONTAL) {
|
|
if (image_info->scaled_width > image_info->printable_width) {
|
|
image_info->col_offset = (
|
|
(image_info->scaled_width - image_info->printable_width) / 2);
|
|
} else {
|
|
int paddingDelta = (image_info->printable_width - image_info->scaled_width);
|
|
delta = paddingDelta / 2;
|
|
image_info->output_padding_left += delta;
|
|
image_info->output_padding_right += delta + (paddingDelta & 0x1);
|
|
}
|
|
} else if (image_info->scaled_width > image_info->printable_width) {
|
|
image_info->col_offset = (image_info->scaled_width - image_info->printable_width);
|
|
} else if (image_info->scaled_width < image_info->printable_width) {
|
|
image_info->output_padding_left += (image_info->printable_width -
|
|
image_info->scaled_width);
|
|
}
|
|
|
|
if (image_info->render_flags & RENDER_FLAG_AUTO_SCALE) {
|
|
} else if (image_info->render_flags & RENDER_FLAG_CENTER_VERTICAL) {
|
|
if (image_info->scaled_height > image_info->printable_height) {
|
|
image_info->row_offset = (
|
|
(image_info->scaled_height - image_info->printable_height) / 2);
|
|
} else {
|
|
int paddingDelta = (image_info->printable_height - image_info->scaled_height);
|
|
delta = paddingDelta / 2;
|
|
image_info->output_padding_top += delta;
|
|
image_info->output_padding_bottom += delta + (paddingDelta & 0x1);
|
|
}
|
|
} else if (image_info->scaled_height > image_info->printable_height) {
|
|
image_info->row_offset = (image_info->scaled_height - image_info->printable_height);
|
|
} else if (image_info->scaled_height < image_info->printable_height) {
|
|
image_info->output_padding_top += (image_info->printable_height -
|
|
image_info->scaled_height);
|
|
}
|
|
break;
|
|
case ROT_270:
|
|
if (image_info->render_flags & RENDER_FLAG_AUTO_SCALE) {
|
|
} else if (image_info->render_flags & RENDER_FLAG_CENTER_HORIZONTAL) {
|
|
if (image_info->scaled_width > image_info->printable_width) {
|
|
image_info->col_offset = (
|
|
(image_info->scaled_width - image_info->printable_width) / 2);
|
|
} else {
|
|
int paddingDelta = (image_info->printable_width - image_info->scaled_width);
|
|
delta = paddingDelta / 2;
|
|
image_info->output_padding_left += delta;
|
|
image_info->output_padding_right += delta + (paddingDelta & 0x1);
|
|
}
|
|
} else if (image_info->scaled_width > image_info->printable_width) {
|
|
image_info->col_offset = (image_info->scaled_width - image_info->printable_width);
|
|
} else if (image_info->scaled_width < image_info->printable_width) {
|
|
image_info->output_padding_left += (image_info->printable_width -
|
|
image_info->scaled_width);
|
|
}
|
|
|
|
if (image_info->render_flags & RENDER_FLAG_AUTO_SCALE) {
|
|
} else if (image_info->render_flags & RENDER_FLAG_CENTER_VERTICAL) {
|
|
if (image_info->scaled_height > image_info->printable_height) {
|
|
image_info->row_offset = (
|
|
(image_info->scaled_height - image_info->printable_height) / 2);
|
|
} else {
|
|
int paddingDelta = (image_info->printable_height - image_info->scaled_height);
|
|
delta = paddingDelta / 2;
|
|
image_info->output_padding_top += delta;
|
|
image_info->output_padding_bottom += delta + (paddingDelta & 0x1);
|
|
}
|
|
} else if (image_info->scaled_height < image_info->printable_height) {
|
|
image_info->output_padding_top += (image_info->printable_height -
|
|
image_info->scaled_height);
|
|
} else if (image_info->scaled_height > image_info->printable_height) {
|
|
image_info->row_offset = (image_info->scaled_height - image_info->printable_height);
|
|
}
|
|
break;
|
|
case ROT_0:
|
|
default:
|
|
if (image_info->render_flags & RENDER_FLAG_AUTO_SCALE) {
|
|
} else if (image_info->render_flags & RENDER_FLAG_CENTER_HORIZONTAL) {
|
|
if (image_info->scaled_width > image_info->printable_width) {
|
|
image_info->col_offset = (
|
|
(image_info->scaled_width - image_info->printable_width) / 2);
|
|
} else {
|
|
int paddingDelta = (image_info->printable_width - image_info->scaled_width);
|
|
delta = paddingDelta / 2;
|
|
image_info->output_padding_left += delta;
|
|
image_info->output_padding_right += delta + (paddingDelta & 0x1);
|
|
}
|
|
} else if (image_info->scaled_width < image_info->printable_width) {
|
|
image_info->output_padding_right += (image_info->printable_width -
|
|
image_info->scaled_width);
|
|
}
|
|
|
|
if (image_info->render_flags & RENDER_FLAG_AUTO_SCALE) {
|
|
} else if (image_info->render_flags & RENDER_FLAG_CENTER_VERTICAL) {
|
|
if (image_info->scaled_height > image_info->printable_height) {
|
|
image_info->row_offset = (
|
|
(image_info->scaled_height - image_info->printable_height) / 2);
|
|
} else {
|
|
int paddingDelta = (image_info->printable_height - image_info->scaled_height);
|
|
delta = paddingDelta / 2;
|
|
image_info->output_padding_top += delta;
|
|
image_info->output_padding_bottom += delta + (paddingDelta & 0x1);
|
|
}
|
|
} else if (image_info->scaled_height < image_info->printable_height) {
|
|
image_info->output_padding_bottom += (image_info->printable_height -
|
|
image_info->scaled_height);
|
|
}
|
|
break;
|
|
}
|
|
|
|
LOGD("wprint_image_set_output_properties(): input render flags - %d (0x%8.8x)",
|
|
input_render_flags, input_render_flags);
|
|
LOGD("wprint_image_set_output_properties(): printable area - %dx%d",
|
|
printable_width, printable_height);
|
|
LOGD("wprint_image_set_output_properties(): input margins: Top:%d Left:%d Right:%d Bottom:%d",
|
|
top_margin, left_margin, right_margin, bottom_margin);
|
|
LOGD("wprint_image_set_output_properties(): padding options: %d (0x%2.2x)",
|
|
image_info->padding_options, image_info->padding_options);
|
|
LOGD("wprint_image_set_output_properties(): concurrent stripes - %d",
|
|
image_info->concurrent_stripes);
|
|
LOGD("wprint_image_set_output_properties(): stripe height - %d", image_info->stripe_height);
|
|
LOGD("wprint_image_set_output_properties(): image dimensions: %dx%d",
|
|
image_info->width, image_info->height);
|
|
LOGD("wprint_image_set_output_properties(): image rotation: %d", image_info->rotation);
|
|
LOGD("wprint_image_set_output_properties(): final render flags - %d (0x%8.8x)",
|
|
image_info->render_flags, image_info->render_flags);
|
|
LOGD("wprint_image_set_output_properties(): printable area after margins - %dx%d",
|
|
image_info->printable_width, image_info->printable_height);
|
|
LOGD("wprint_image_set_output_properties(): output_padding: Top:%d Left:%d Right:%d Bottom:%d",
|
|
image_info->output_padding_top, image_info->output_padding_left,
|
|
image_info->output_padding_right, image_info->output_padding_bottom);
|
|
LOGD("wprint_image_set_output_properties(): output dimensions: %dx%d", image_info->output_width,
|
|
image_info->output_height);
|
|
LOGD("wprint_image_set_output_properties(): subsampled image dimensions - %dx%d",
|
|
image_info->sampled_width, image_info->sampled_height);
|
|
LOGD("wprint_image_set_output_properties(): scaled image dimensions - %dx%d",
|
|
image_info->scaled_width, image_info->scaled_height);
|
|
LOGD("wprint_image_set_output_properties(): image offsets - row: %d, col: %d",
|
|
image_info->row_offset, image_info->col_offset);
|
|
LOGD("wprint_image_set_output_properties(): margins - top: %d, left: %d, right: %d, bottom: %d",
|
|
image_info->output_padding_top, image_info->output_padding_left,
|
|
image_info->output_padding_right, image_info->output_padding_bottom);
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int _get_width(wprint_image_info_t *image_info, unsigned int padding_options) {
|
|
int width;
|
|
if (image_info->render_flags & RENDER_FLAG_AUTO_SCALE) {
|
|
width = image_info->printable_width;
|
|
} else if ((image_info->render_flags & RENDER_FLAG_AUTO_FIT) || image_info->scaling_needed) {
|
|
width = image_info->scaled_width;
|
|
} else {
|
|
width = image_info->output_width;
|
|
}
|
|
if (padding_options & PAD_LEFT) {
|
|
width += image_info->output_padding_left;
|
|
}
|
|
if (padding_options & PAD_RIGHT) {
|
|
width += image_info->output_padding_right;
|
|
}
|
|
return width;
|
|
}
|
|
|
|
int wprint_image_get_width(wprint_image_info_t *image_info) {
|
|
int width = _get_width(image_info, image_info->padding_options);
|
|
LOGD("wprint_image_get_width(): %d", width);
|
|
return width;
|
|
}
|
|
|
|
int wprint_image_get_output_buff_size(wprint_image_info_t *image_info) {
|
|
int width = MAX(MAX(image_info->scaled_width, image_info->scaled_height),
|
|
_get_width(image_info, image_info->padding_options));
|
|
LOGD("wprint_image_get_output_buff_size(): %dx%d", width, image_info->output_rows);
|
|
return (BYTES_PER_PIXEL(width * image_info->output_rows));
|
|
}
|
|
|
|
static int _get_height(wprint_image_info_t *image_info, unsigned int padding_options) {
|
|
int height;
|
|
if (image_info->render_flags & RENDER_FLAG_AUTO_SCALE) {
|
|
height = image_info->printable_height;
|
|
} else {
|
|
height = MIN(image_info->scaled_height, image_info->printable_height);
|
|
}
|
|
if (padding_options & PAD_TOP) {
|
|
height += image_info->output_padding_top;
|
|
}
|
|
if (padding_options & PAD_BOTTOM) {
|
|
height += image_info->output_padding_bottom;
|
|
}
|
|
return height;
|
|
}
|
|
|
|
int wprint_image_get_height(wprint_image_info_t *image_info) {
|
|
int height = _get_height(image_info, image_info->padding_options);
|
|
LOGD("wprint_image_get_height(): %d", height);
|
|
return height;
|
|
}
|
|
|
|
bool wprint_image_is_landscape(wprint_image_info_t *image_info) {
|
|
return (image_info->width > image_info->height);
|
|
}
|
|
|
|
int _decode_stripe(wprint_image_info_t *image_info, int start_row, int num_rows,
|
|
unsigned int padding_options, unsigned char *rgb_pixels) {
|
|
int image_y, image_x;
|
|
unsigned char *image_data;
|
|
int nbytes = -1;
|
|
int rbytes;
|
|
int col_offset;
|
|
int old_num_rows;
|
|
const image_decode_ifc_t *decode_ifc = image_info->decode_ifc;
|
|
if ((decode_ifc == NULL) || (decode_ifc->decode_row == NULL)) {
|
|
return nbytes;
|
|
}
|
|
|
|
nbytes = 0;
|
|
start_row += image_info->row_offset;
|
|
rbytes = BYTES_PER_PIXEL(image_info->output_width);
|
|
|
|
// get padding values
|
|
int padding_left = ((padding_options & PAD_LEFT) ? BYTES_PER_PIXEL(
|
|
image_info->output_padding_left) : 0);
|
|
int padding_right = ((padding_options & PAD_RIGHT) ? BYTES_PER_PIXEL(
|
|
image_info->output_padding_right) : 0);
|
|
|
|
old_num_rows = ~num_rows;
|
|
switch (image_info->rotation) {
|
|
case ROT_90:
|
|
col_offset = BYTES_PER_PIXEL(image_info->col_offset);
|
|
while (num_rows > 0) {
|
|
if (start_row > image_info->sampled_width) {
|
|
return nbytes;
|
|
}
|
|
if (old_num_rows == num_rows) {
|
|
LOGE("Bad ROT_90 calculations. Exiting to prevent infinite loop");
|
|
return ERROR;
|
|
}
|
|
old_num_rows = num_rows;
|
|
if ((image_info->output_swath_start == -1) ||
|
|
(start_row < image_info->output_swath_start) ||
|
|
(start_row >= (image_info->output_swath_start + image_info->rows_cached))) {
|
|
if (image_info->output_swath_start == -1) {
|
|
if (decode_ifc->decode_row(image_info, 0) == NULL) {
|
|
return ERROR;
|
|
}
|
|
}
|
|
image_info->output_swath_start = ((start_row / image_info->rows_cached) *
|
|
image_info->rows_cached);
|
|
for (image_y = 0; image_y < image_info->sampled_height; image_y++) {
|
|
image_data = decode_ifc->decode_row(image_info, image_y);
|
|
if (image_data == NULL) {
|
|
return ERROR;
|
|
}
|
|
for (image_x = 0; (image_x < image_info->rows_cached &&
|
|
((image_x + image_info->output_swath_start) <
|
|
image_info->sampled_width));
|
|
image_x++) {
|
|
memcpy(image_info->output_cache[image_x] + BYTES_PER_PIXEL(
|
|
(image_info->sampled_height - image_y - 1)),
|
|
image_data + BYTES_PER_PIXEL(
|
|
(image_info->output_swath_start + image_x)),
|
|
BYTES_PER_PIXEL(1));
|
|
}
|
|
}
|
|
}
|
|
|
|
for (image_y = start_row; ((num_rows != 0) &&
|
|
(image_y < image_info->sampled_width) &&
|
|
(image_y < (image_info->output_swath_start + image_info->rows_cached)));
|
|
image_y++, num_rows--, start_row++) {
|
|
memcpy(rgb_pixels + padding_left,
|
|
image_info->output_cache[image_y - image_info->output_swath_start] +
|
|
col_offset, rbytes);
|
|
nbytes += rbytes + padding_left + padding_right;
|
|
rgb_pixels += rbytes + padding_left + padding_right;
|
|
}
|
|
}
|
|
break;
|
|
case ROT_180:
|
|
col_offset = image_info->col_offset;
|
|
for (image_y = start_row;
|
|
((image_y < image_info->sampled_height) && (num_rows != 0));
|
|
image_y++, num_rows--) {
|
|
image_data = decode_ifc->decode_row(image_info,
|
|
(image_info->sampled_height - image_y - 1));
|
|
if (image_data == NULL) {
|
|
return ERROR;
|
|
}
|
|
for (image_x = 0; image_x < image_info->output_width; image_x++) {
|
|
memcpy(rgb_pixels + padding_left + BYTES_PER_PIXEL(image_x),
|
|
image_data + BYTES_PER_PIXEL(image_info->sampled_width -
|
|
image_x - col_offset - 1),
|
|
BYTES_PER_PIXEL(1));
|
|
}
|
|
nbytes += rbytes + padding_left + padding_right;
|
|
rgb_pixels += rbytes + padding_left + padding_right;
|
|
}
|
|
break;
|
|
case ROT_270:
|
|
col_offset = BYTES_PER_PIXEL(image_info->col_offset);
|
|
while (num_rows > 0) {
|
|
if (start_row > image_info->sampled_width) {
|
|
return nbytes;
|
|
}
|
|
if (old_num_rows == num_rows) {
|
|
LOGE("Bad ROT_270 calculations. Erroring out to prevent infinite loop.");
|
|
return ERROR;
|
|
}
|
|
old_num_rows = num_rows;
|
|
if ((image_info->output_swath_start == -1) ||
|
|
(start_row < image_info->output_swath_start) ||
|
|
(start_row >= (image_info->output_swath_start + image_info->rows_cached))) {
|
|
if (image_info->output_swath_start == -1) {
|
|
if (decode_ifc->decode_row(image_info, 0) == NULL) {
|
|
return ERROR;
|
|
}
|
|
}
|
|
image_info->output_swath_start = ((start_row / image_info->rows_cached) *
|
|
image_info->rows_cached);
|
|
for (image_y = 0; image_y < image_info->sampled_height; image_y++) {
|
|
image_data = decode_ifc->decode_row(image_info, image_y);
|
|
if (image_data == NULL) {
|
|
return ERROR;
|
|
}
|
|
for (image_x = 0; ((image_x < image_info->rows_cached) &&
|
|
((image_x + image_info->output_swath_start) <
|
|
image_info->sampled_width));
|
|
image_x++) {
|
|
memcpy(image_info->output_cache[image_x] + BYTES_PER_PIXEL(image_y),
|
|
image_data + BYTES_PER_PIXEL(image_info->sampled_width -
|
|
(image_info->output_swath_start +
|
|
image_x) - 1),
|
|
BYTES_PER_PIXEL(1));
|
|
}
|
|
}
|
|
}
|
|
for (image_y = start_row;
|
|
((num_rows != 0) &&
|
|
(image_y < image_info->sampled_width) &&
|
|
(image_y < (image_info->output_swath_start
|
|
+ image_info->rows_cached)));
|
|
image_y++, num_rows--, start_row++) {
|
|
memcpy(rgb_pixels + padding_left,
|
|
image_info->output_cache[image_y - image_info->output_swath_start] +
|
|
col_offset, rbytes);
|
|
nbytes += rbytes + padding_left + padding_right;
|
|
rgb_pixels += rbytes + padding_left + padding_right;
|
|
}
|
|
}
|
|
break;
|
|
case ROT_0:
|
|
default:
|
|
col_offset = BYTES_PER_PIXEL(image_info->col_offset);
|
|
for (image_y = start_row;
|
|
((image_y < image_info->sampled_height) && (num_rows != 0));
|
|
image_y++, num_rows--) {
|
|
image_data = decode_ifc->decode_row(image_info, image_y);
|
|
if (image_data == NULL) {
|
|
LOGE("ERROR: received no data for row: %d", image_y);
|
|
return ERROR;
|
|
}
|
|
memcpy(rgb_pixels + padding_left, image_data + col_offset, rbytes);
|
|
nbytes += rbytes + padding_left + padding_right;
|
|
rgb_pixels += rbytes + padding_left + padding_right;
|
|
}
|
|
break;
|
|
}
|
|
return nbytes;
|
|
}
|
|
|
|
int wprint_image_decode_stripe(wprint_image_info_t *image_info, int start_row, int *height,
|
|
unsigned char *rgb_pixels) {
|
|
int nbytes = 0;
|
|
int bytes_per_row = BYTES_PER_PIXEL(_get_width(image_info, image_info->padding_options));
|
|
|
|
if (height == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
int num_rows = *height;
|
|
|
|
*height = 0;
|
|
|
|
// get padding values
|
|
int padding_left = ((image_info->padding_options & PAD_LEFT) ? BYTES_PER_PIXEL(
|
|
image_info->output_padding_left) : 0);
|
|
int padding_right = ((image_info->padding_options & PAD_RIGHT) ? BYTES_PER_PIXEL(
|
|
image_info->output_padding_right) : 0);
|
|
int padding_top = ((image_info->padding_options & PAD_TOP) ?
|
|
image_info->output_padding_top : 0);
|
|
// handle invalid requests
|
|
if ((start_row < 0) || (start_row >= _get_height(image_info, image_info->padding_options))) {
|
|
*height = 0;
|
|
return ERROR;
|
|
} else if ((image_info->padding_options & PAD_TOP) &&
|
|
(start_row < padding_top)) {
|
|
int blank_rows = MIN(num_rows, (padding_top - start_row));
|
|
int bytesToBlank = (blank_rows * bytes_per_row);
|
|
nbytes += bytesToBlank;
|
|
num_rows -= blank_rows;
|
|
*height += blank_rows;
|
|
memset(rgb_pixels, 0xff, bytesToBlank);
|
|
rgb_pixels += bytesToBlank;
|
|
start_row += blank_rows;
|
|
} else if ((image_info->padding_options & PAD_BOTTOM) &&
|
|
(start_row >= _get_height(image_info, image_info->padding_options & PAD_TOP))) {
|
|
// handle image padding on bottom
|
|
int blank_rows = MIN(num_rows,
|
|
_get_height(image_info, image_info->padding_options) - start_row);
|
|
int bytesToBlank = (blank_rows * bytes_per_row);
|
|
nbytes += bytesToBlank;
|
|
num_rows -= blank_rows;
|
|
*height += blank_rows;
|
|
memset(rgb_pixels, 0xff, bytesToBlank);
|
|
rgb_pixels += bytesToBlank;
|
|
start_row += blank_rows;
|
|
}
|
|
|
|
if (num_rows <= 0) {
|
|
return nbytes;
|
|
}
|
|
|
|
unsigned char *pad_rgb_pixels = rgb_pixels;
|
|
int unpadded_start_row = start_row;
|
|
// adjust start row to fit within image bounds
|
|
if (image_info->padding_options & PAD_TOP) {
|
|
unpadded_start_row -= padding_top;
|
|
}
|
|
|
|
// check if we need to scaling
|
|
if (image_info->scaling_needed) {
|
|
// scaling required
|
|
uint32 scaled_start_row = unpadded_start_row;
|
|
if (image_info->scaled_height > image_info->printable_height) {
|
|
scaled_start_row += ((image_info->scaled_height - image_info->printable_height) / 2);
|
|
}
|
|
uint32 stripe_height, mixed;
|
|
uint16 unscaled_row_start, unscaled_row_end;
|
|
uint16 generated_rows, row_offset;
|
|
uint32 predecoded_rows;
|
|
|
|
int scaled_num_rows = (((scaled_start_row + num_rows) > image_info->scaled_height) ?
|
|
(image_info->scaled_height - scaled_start_row) : num_rows);
|
|
while (scaled_num_rows > 0) {
|
|
stripe_height = MIN(scaled_num_rows, image_info->stripe_height);
|
|
scaler_calculate_scaling_rows(scaled_start_row,
|
|
MIN((scaled_start_row + stripe_height - 1),
|
|
(image_info->scaled_height - 1)), (void *) &image_info->scaler_config,
|
|
&unscaled_row_start, &unscaled_row_end, &generated_rows, &row_offset, &mixed);
|
|
|
|
if (mixed > image_info->mixed_memory_needed) {
|
|
LOGE("need more memory");
|
|
return -1;
|
|
}
|
|
|
|
predecoded_rows = 0;
|
|
if (unscaled_row_start <= image_info->unscaled_end_row) {
|
|
// shift over any rows we need that were decoded in the previous pass
|
|
predecoded_rows = (image_info->unscaled_end_row - unscaled_row_start) + 1;
|
|
|
|
memmove(image_info->unscaled_rows, image_info->unscaled_rows +
|
|
BYTES_PER_PIXEL(((unscaled_row_start - image_info->unscaled_start_row) *
|
|
image_info->output_width)),
|
|
BYTES_PER_PIXEL((predecoded_rows * image_info->output_width)));
|
|
}
|
|
|
|
image_info->unscaled_start_row = unscaled_row_start;
|
|
image_info->unscaled_end_row = unscaled_row_end;
|
|
|
|
/*
|
|
* decode the remaining rows we need
|
|
* don't pad the output since we need to move the data after scaling anyways
|
|
*/
|
|
int rowsLeftToDecode = ((image_info->unscaled_end_row -
|
|
(image_info->unscaled_start_row + predecoded_rows)) + 1);
|
|
if (rowsLeftToDecode > 0) {
|
|
int dbytes = _decode_stripe(image_info,
|
|
image_info->unscaled_start_row + predecoded_rows, rowsLeftToDecode,
|
|
PAD_NONE, (image_info->unscaled_rows + BYTES_PER_PIXEL(predecoded_rows *
|
|
image_info->output_width)));
|
|
if (dbytes <= 0) {
|
|
if (dbytes < 0) {
|
|
LOGE("couldn't decode rows");
|
|
}
|
|
return dbytes;
|
|
}
|
|
} else if (predecoded_rows <= 0) {
|
|
return 0;
|
|
}
|
|
|
|
// scale the data to it's final size
|
|
scaler_scale_image_data(image_info->unscaled_rows, (void *) &image_info->scaler_config,
|
|
rgb_pixels, image_info->mixed_memory);
|
|
// do we have to move the data around??
|
|
if ((row_offset != 0) ||
|
|
(image_info->scaled_width > image_info->printable_width) ||
|
|
(padding_left > 0) ||
|
|
(padding_right > 0)) {
|
|
int delta = 0;
|
|
int pixelsToMove = BYTES_PER_PIXEL(MIN(image_info->scaled_width,
|
|
image_info->printable_width));
|
|
|
|
int memMoveRow = ((bytes_per_row < image_info->scaler_config.iOutBufWidth) ? 0 : (
|
|
stripe_height - 1));
|
|
int memMoveIncrement = ((bytes_per_row < image_info->scaler_config.iOutBufWidth)
|
|
? 1 : -1);
|
|
|
|
// if scaled width is greater than the printable area drop pixels on either size
|
|
if (image_info->scaled_width > image_info->printable_width) {
|
|
delta = BYTES_PER_PIXEL(
|
|
((image_info->scaled_width - image_info->printable_width) / 2));
|
|
}
|
|
|
|
// move the data into the correct location in the output buffer
|
|
for (generated_rows = 0; generated_rows < stripe_height; generated_rows++,
|
|
memMoveRow += memMoveIncrement) {
|
|
memmove(rgb_pixels + (memMoveRow * bytes_per_row) + padding_left,
|
|
rgb_pixels + ((memMoveRow + row_offset) *
|
|
image_info->scaler_config.iOutBufWidth) + delta, pixelsToMove);
|
|
}
|
|
}
|
|
|
|
num_rows -= stripe_height;
|
|
scaled_num_rows -= stripe_height;
|
|
scaled_start_row += stripe_height;
|
|
nbytes += (bytes_per_row * stripe_height);
|
|
rgb_pixels += (bytes_per_row * stripe_height);
|
|
*height += stripe_height;
|
|
start_row += stripe_height;
|
|
}
|
|
} else {
|
|
// no scaling needed
|
|
|
|
// decode the request
|
|
int dbytes = _decode_stripe(image_info, unpadded_start_row,
|
|
(((unpadded_start_row + num_rows) >
|
|
_get_height(image_info, PAD_NONE)) ?
|
|
(_get_height(image_info, PAD_NONE) - unpadded_start_row)
|
|
: num_rows),
|
|
image_info->padding_options, rgb_pixels);
|
|
if (dbytes <= 0) {
|
|
if (dbytes < 0) {
|
|
LOGE("couldn't decode rows");
|
|
}
|
|
return dbytes;
|
|
}
|
|
|
|
int rows = (dbytes / bytes_per_row);
|
|
*height += rows;
|
|
num_rows -= rows;
|
|
start_row += rows;
|
|
unpadded_start_row += rows;
|
|
rgb_pixels += dbytes;
|
|
nbytes += dbytes;
|
|
}
|
|
|
|
// white pad the left and right edges
|
|
if ((pad_rgb_pixels != rgb_pixels) &&
|
|
(image_info->padding_options & (PAD_LEFT | PAD_RIGHT)) &&
|
|
((padding_left != 0) || (padding_right != 0))) {
|
|
while (pad_rgb_pixels != rgb_pixels) {
|
|
if (padding_left != 0) {
|
|
memset(pad_rgb_pixels, 0xff, padding_left);
|
|
}
|
|
if (padding_right != 0) {
|
|
memset(pad_rgb_pixels + (bytes_per_row - padding_right), 0xff, padding_right);
|
|
}
|
|
pad_rgb_pixels += bytes_per_row;
|
|
}
|
|
}
|
|
|
|
if ((image_info->padding_options & PAD_BOTTOM) && (num_rows > 0) &&
|
|
(start_row >= _get_height(image_info, image_info->padding_options & PAD_TOP))) {
|
|
int blank_rows = MIN(num_rows,
|
|
_get_height(image_info, image_info->padding_options) - start_row);
|
|
int bytesToBlank = (blank_rows * bytes_per_row);
|
|
nbytes += bytesToBlank;
|
|
num_rows -= blank_rows;
|
|
*height += blank_rows;
|
|
memset(rgb_pixels, 0xff, bytesToBlank);
|
|
rgb_pixels += bytesToBlank;
|
|
}
|
|
|
|
return nbytes;
|
|
}
|
|
|
|
int wprint_image_compute_rows_to_cache(wprint_image_info_t *image_info) {
|
|
int i;
|
|
int row_width, max_rows;
|
|
unsigned char output_mem;
|
|
int available_mem = MAX_DECODE_MEM;
|
|
int width, height;
|
|
|
|
width = image_info->sampled_width;
|
|
height = image_info->sampled_height;
|
|
|
|
switch (image_info->rotation) {
|
|
case ROT_90:
|
|
case ROT_270:
|
|
output_mem = 1;
|
|
row_width = height;
|
|
break;
|
|
case ROT_0:
|
|
case ROT_180:
|
|
default:
|
|
output_mem = 0;
|
|
row_width = width;
|
|
break;
|
|
}
|
|
|
|
available_mem -= (wprint_image_get_output_buff_size(image_info) *
|
|
image_info->concurrent_stripes);
|
|
if (image_info->unscaled_rows != NULL) {
|
|
// remove any memory allocated for scaling from our pool
|
|
available_mem -= BYTES_PER_PIXEL(
|
|
image_info->unscaled_rows_needed * image_info->output_width);
|
|
available_mem -= image_info->mixed_memory_needed;
|
|
}
|
|
|
|
// make sure we have a valid amount of memory to work with
|
|
available_mem = MAX(available_mem, MIN_DECODE_MEM);
|
|
|
|
LOGD("wprint_image_compute_rows_to_cache(): %d bytes available for row caching", available_mem);
|
|
|
|
row_width = BYTES_PER_PIXEL(row_width);
|
|
max_rows = (available_mem / row_width);
|
|
|
|
if (max_rows > 0xf) {
|
|
max_rows &= ~0xf;
|
|
}
|
|
|
|
LOGD("wprint_image_compute_rows_to_cache(): based on row width %d (%d), %d rows can be cached",
|
|
row_width, output_mem, max_rows);
|
|
|
|
if (output_mem) {
|
|
if (max_rows > (MAX(width, height))) {
|
|
max_rows = MAX(width, height);
|
|
}
|
|
|
|
image_info->output_cache = (unsigned char **) malloc(sizeof(unsigned char *) * max_rows);
|
|
for (i = 0; i < max_rows; i++) {
|
|
image_info->output_cache[i] = (unsigned char *) malloc(row_width);
|
|
}
|
|
} else {
|
|
max_rows = MIN(max_rows, height);
|
|
}
|
|
|
|
image_info->rows_cached = max_rows;
|
|
LOGD("wprint_image_compute_rows_to_cache(): %d rows being cached", max_rows);
|
|
|
|
return wprint_image_input_rows_cached(image_info);
|
|
}
|
|
|
|
int wprint_image_input_rows_cached(wprint_image_info_t *image_info) {
|
|
return ((image_info->output_cache != NULL) ? 1 : image_info->rows_cached);
|
|
}
|
|
|
|
void wprint_image_cleanup(wprint_image_info_t *image_info) {
|
|
int i;
|
|
const image_decode_ifc_t *decode_ifc = image_info->decode_ifc;
|
|
|
|
if ((decode_ifc != NULL) && (decode_ifc->cleanup != NULL)) {
|
|
decode_ifc->cleanup(image_info);
|
|
}
|
|
|
|
// free memory allocated for saving unscaled rows
|
|
if (image_info->unscaled_rows != NULL) {
|
|
free(image_info->unscaled_rows);
|
|
image_info->unscaled_rows = NULL;
|
|
}
|
|
|
|
// free memory allocated needed for mixed scaling
|
|
if (image_info->mixed_memory != NULL) {
|
|
free(image_info->mixed_memory);
|
|
image_info->mixed_memory = NULL;
|
|
}
|
|
|
|
if (image_info->output_cache != NULL) {
|
|
for (i = 0; i < image_info->rows_cached; i++) {
|
|
free(image_info->output_cache[i]);
|
|
}
|
|
free(image_info->output_cache);
|
|
image_info->output_cache = NULL;
|
|
}
|
|
} |