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 <sys/types.h> 20 #include <stdio.h> 21 #include <stdlib.h> 22 #include <math.h> 23 24 #include "lib_pcl.h" 25 #include "wprint_image.h" 26 27 #include "pclm_wrapper_api.h" 28 29 #include "media.h" 30 #include "wprint_debug.h" 31 32 #define TAG "lib_pclm" 33 34 /* 35 * Store a valid media_size name into media_name 36 */ 37 static void _get_pclm_media_size_name(pcl_job_info_t *job_info, media_size_t media_size, 38 char *media_name) { 39 int i = 0; 40 for (i = 0; i < SUPPORTED_MEDIA_SIZE_COUNT; i++) { 41 if (media_size == SupportedMediaSizes[i].media_size) { 42 strncpy(media_name, SupportedMediaSizes[i].PCL6Name, 43 strlen(SupportedMediaSizes[i].PCL6Name)); 44 LOGD("_get_pclm_media_size_name(): match found: %d, %s", media_size, media_name); 45 break; // we found a match, so break out of loop 46 } 47 } 48 49 if (i == SUPPORTED_MEDIA_SIZE_COUNT) { 50 // media size not found, defaulting to letter 51 LOGD("_get_pclm_media_size_name(): media size, %d, NOT FOUND, setting to letter", 52 media_size); 53 _get_pclm_media_size_name(job_info, US_LETTER, media_name); 54 } 55 } 56 57 /* 58 * Write a valid media_size into myPageInfo 59 */ 60 static void _get_pclm_media_size(pcl_job_info_t *job_info, media_size_t media_size, 61 PCLmPageSetup *myPageInfo) { 62 int i = SUPPORTED_MEDIA_SIZE_COUNT; 63 64 if (myPageInfo != NULL) { 65 for (i = 0; i < SUPPORTED_MEDIA_SIZE_COUNT; i++) { 66 if (media_size == SupportedMediaSizes[i].media_size) { 67 strncpy(myPageInfo->mediaSizeName, SupportedMediaSizes[i].PCL6Name, 68 sizeof(myPageInfo->mediaSizeName) - 1); 69 70 myPageInfo->mediaWidth = floorf( 71 _MI_TO_POINTS(SupportedMediaSizes[i].WidthInInches)); 72 myPageInfo->mediaHeight = floorf( 73 _MI_TO_POINTS(SupportedMediaSizes[i].HeightInInches)); 74 75 LOGD("_get_pclm_media_size(): match found: %d, %s, width=%f, height=%f", 76 media_size, SupportedMediaSizes[i].PCL6Name, myPageInfo->mediaWidth, 77 myPageInfo->mediaHeight); 78 break; // we found a match, so break out of loop 79 } 80 } 81 } 82 83 if (i == SUPPORTED_MEDIA_SIZE_COUNT) { 84 // media size not found, defaulting to letter 85 LOGD("_get_pclm_media_size(): media size, %d, NOT FOUND, setting to letter", media_size); 86 _get_pclm_media_size(job_info, US_LETTER, myPageInfo); 87 } 88 } 89 90 static wJob_t _start_job(wJob_t job_handle, pcl_job_info_t *job_info, media_size_t media_size, 91 media_type_t media_type, int resolution, duplex_t duplex, duplex_dry_time_t dry_time, 92 color_space_t color_space, media_tray_t media_tray, float top_margin, 93 float left_margin) { 94 int outBuffSize = 0; 95 96 if (job_info == NULL) { 97 return _WJOBH_NONE; 98 } 99 100 if (job_info->job_handle != _WJOBH_NONE) { 101 if (job_info->wprint_ifc != NULL) { 102 LOGD("_start_job() required cleanup"); 103 } 104 job_info->job_handle = _WJOBH_NONE; 105 } 106 107 if ((job_info->wprint_ifc == NULL) || (job_info->print_ifc == NULL)) { 108 return _WJOBH_NONE; 109 } 110 111 LOGD("_start_job(), media_size %d, media_type %d, dt %d, %s, media_tray %d margins T %f L %f", 112 media_size, media_type, dry_time, 113 (duplex == DUPLEX_MODE_NONE) ? "simplex" : "duplex", 114 media_tray, top_margin, left_margin); 115 116 job_info->job_handle = job_handle; 117 118 _START_JOB(job_info, "pdf"); 119 120 job_info->resolution = resolution; 121 job_info->media_size = media_size; 122 job_info->standard_scale = (float) resolution / (float) STANDARD_SCALE_FOR_PDF; 123 124 // initialize static variables 125 job_info->pclm_output_buffer = NULL; 126 job_info->seed_row = job_info->pcl_buff = NULL; // unused 127 job_info->pixel_width = job_info->pixel_height = job_info->page_number = job_info->num_rows = 0; 128 129 memset((void *) &job_info->pclm_page_info, 0x0, sizeof(PCLmPageSetup)); 130 _get_pclm_media_size_name(job_info, media_size, &job_info->pclm_page_info.mediaSizeName[0]); 131 132 if ((left_margin < 0.0f) || (top_margin < 0.0f)) { 133 job_info->pclm_page_info.mediaWidthOffset = 0.0f; 134 job_info->pclm_page_info.mediaHeightOffset = 0.0f; 135 } else { 136 job_info->pclm_page_info.mediaWidthOffset = (left_margin * (float) STANDARD_SCALE_FOR_PDF); 137 job_info->pclm_page_info.mediaHeightOffset = (top_margin * (float) STANDARD_SCALE_FOR_PDF); 138 } 139 140 LOGI("_start_job(), mediaHeightOffsets W %f H %f", job_info->pclm_page_info.mediaWidthOffset, 141 job_info->pclm_page_info.mediaHeightOffset); 142 143 job_info->pclm_page_info.pageOrigin = top_left; // REVISIT 144 145 job_info->monochrome = (color_space == COLOR_SPACE_MONO); 146 job_info->pclm_page_info.dstColorSpaceSpefication = deviceRGB; 147 if (color_space == COLOR_SPACE_MONO) { 148 job_info->pclm_page_info.dstColorSpaceSpefication = grayScale; 149 } else if (color_space == COLOR_SPACE_COLOR) { 150 job_info->pclm_page_info.dstColorSpaceSpefication = deviceRGB; 151 } else if (color_space == COLOR_SPACE_ADOBE_RGB) { 152 job_info->pclm_page_info.dstColorSpaceSpefication = adobeRGB; 153 } 154 155 job_info->pclm_page_info.stripHeight = job_info->strip_height; 156 job_info->pclm_page_info.destinationResolution = res600; 157 if (resolution == 300) { 158 job_info->pclm_page_info.destinationResolution = res300; 159 } else if (resolution == 600) { 160 job_info->pclm_page_info.destinationResolution = res600; 161 } else if (resolution == 1200) { 162 job_info->pclm_page_info.destinationResolution = res1200; 163 } 164 165 if (duplex == DUPLEX_MODE_BOOK) { 166 job_info->pclm_page_info.duplexDisposition = duplex_longEdge; 167 } else if (duplex == DUPLEX_MODE_TABLET) { 168 job_info->pclm_page_info.duplexDisposition = duplex_shortEdge; 169 } else { 170 job_info->pclm_page_info.duplexDisposition = simplex; 171 } 172 173 job_info->pclm_page_info.mirrorBackside = false; 174 job_info->pclmgen_obj = CreatePCLmGen(); 175 PCLmStartJob(job_info->pclmgen_obj, (void **) &job_info->pclm_output_buffer, &outBuffSize); 176 _WRITE(job_info, (const char *) job_info->pclm_output_buffer, outBuffSize); 177 return job_info->job_handle; 178 } 179 180 static int _start_page(pcl_job_info_t *job_info, int pixel_width, int pixel_height) { 181 PCLmPageSetup *page_info = &job_info->pclm_page_info; 182 ubyte *pclm_output_buff = job_info->pclm_output_buffer; 183 int outBuffSize = 0; 184 185 _START_PAGE(job_info, pixel_width, pixel_height); 186 187 page_info->sourceHeight = (float) pixel_height / job_info->standard_scale; 188 page_info->sourceWidth = (float) pixel_width / job_info->standard_scale; 189 LOGI("_start_page(), strip height=%d, image width=%d, image height=%d, scaled width=%f, " 190 "scaled height=%f", page_info->stripHeight, pixel_width, pixel_height, 191 page_info->sourceWidth, page_info->sourceHeight); 192 193 if (job_info->num_components == 3) { 194 page_info->colorContent = color_content; 195 page_info->srcColorSpaceSpefication = deviceRGB; 196 } else { 197 page_info->colorContent = gray_content; 198 page_info->srcColorSpaceSpefication = grayScale; 199 } 200 201 /* Note: we could possibly get this value dynamically from device via IPP (ePCL) however, 202 * current ink devices report RLE as the default compression type, which compresses much 203 * worse than JPEG or FLATE 204 */ 205 page_info->compTypeRequested = compressDCT; 206 job_info->scan_line_width = pixel_width * job_info->num_components; 207 int res1 = PCLmGetMediaDimensions(job_info->pclmgen_obj, page_info->mediaSizeName, page_info); 208 page_info->SourceWidthPixels = MIN(pixel_width, job_info->pclm_page_info.mediaWidthInPixels); 209 page_info->SourceHeightPixels = pixel_height; 210 job_info->pclm_scan_line_width = 211 job_info->pclm_page_info.mediaWidthInPixels * job_info->num_components; 212 213 LOGD("PCLmGetMediaDimensions(%d), mediaSizeName=%s, mediaWidth=%f, mediaHeight=%f, " 214 "widthPixels=%d, heightPixels=%d", res1, job_info->pclm_page_info.mediaSizeName, 215 job_info->pclm_page_info.mediaWidth, job_info->pclm_page_info.mediaHeight, 216 job_info->pclm_page_info.mediaWidthInPixels, 217 job_info->pclm_page_info.mediaHeightInPixels); 218 219 PCLmStartPage(job_info->pclmgen_obj, page_info, (void **) &pclm_output_buff, &outBuffSize); 220 _WRITE(job_info, (const char *) pclm_output_buff, outBuffSize); 221 222 job_info->page_number++; 223 return job_info->page_number; 224 } 225 226 static int _print_swath(pcl_job_info_t *job_info, char *rgb_pixels, int start_row, int num_rows, 227 int bytes_per_row) { 228 int outBuffSize = 0; 229 _PAGE_DATA(job_info, (const unsigned char *) rgb_pixels, (num_rows * bytes_per_row)); 230 231 if (job_info->monochrome) { 232 unsigned char *buff = (unsigned char *) rgb_pixels; 233 int nbytes = (num_rows * bytes_per_row); 234 int readIndex, writeIndex; 235 for (readIndex = writeIndex = 0; readIndex < nbytes; readIndex += BYTES_PER_PIXEL(1)) { 236 unsigned char gray = SP_GRAY(buff[readIndex + 0], buff[readIndex + 1], 237 buff[readIndex + 2]); 238 buff[writeIndex++] = gray; 239 buff[writeIndex++] = gray; 240 buff[writeIndex++] = gray; 241 } 242 } 243 244 LOGD("_print_swath(): page #%d, buffSize=%d, rows %d - %d (%d rows), bytes per row %d", 245 job_info->page_number, job_info->strip_height * job_info->scan_line_width, start_row, 246 start_row + num_rows - 1, num_rows, bytes_per_row); 247 248 if (job_info->scan_line_width > job_info->pclm_scan_line_width) { 249 int i; 250 char *src_pixels = rgb_pixels + job_info->scan_line_width; 251 char *dest_pixels = rgb_pixels + job_info->pclm_scan_line_width; 252 for (i = 1; i < num_rows; i++, src_pixels += job_info->scan_line_width, 253 dest_pixels += job_info->pclm_scan_line_width) { 254 memmove(dest_pixels, src_pixels, job_info->pclm_scan_line_width); 255 } 256 } 257 258 /* if the inBufferSize is ever used in genPCLm, change the input parameter to pass in 259 * image_info->printable_width*num_components*strip_height 260 * it is currently pixel_width (from _start_page()) * num_components * strip_height 261 */ 262 PCLmEncapsulate(job_info->pclmgen_obj, rgb_pixels, 263 job_info->strip_height * MIN(job_info->scan_line_width, job_info->pclm_scan_line_width), 264 num_rows, (void **) &job_info->pclm_output_buffer, &outBuffSize); 265 _WRITE(job_info, (const char *) job_info->pclm_output_buffer, outBuffSize); 266 267 return OK; 268 } 269 270 static int _end_page(pcl_job_info_t *job_info, int page_number) { 271 int outBuffSize = 0; 272 273 if (page_number == -1) { 274 LOGI("_end_page(): writing blank page"); 275 _start_page(job_info, 0, 0); 276 unsigned char blank_data[1] = {0xFF}; 277 PCLmEncapsulate(job_info->pclmgen_obj, (void *) blank_data, 1, 1, 278 (void **) &job_info->pclm_output_buffer, &outBuffSize); 279 _WRITE(job_info, (const char *) job_info->pclm_output_buffer, outBuffSize); 280 } 281 LOGI("_end_page()"); 282 PCLmEndPage(job_info->pclmgen_obj, (void **) &job_info->pclm_output_buffer, &outBuffSize); 283 _WRITE(job_info, (const char *) job_info->pclm_output_buffer, outBuffSize); 284 _END_PAGE(job_info); 285 286 return OK; 287 } 288 289 static int _end_job(pcl_job_info_t *job_info) { 290 int outBuffSize = 0; 291 292 LOGI("_end_job()"); 293 PCLmEndJob(job_info->pclmgen_obj, (void **) &job_info->pclm_output_buffer, &outBuffSize); 294 _WRITE(job_info, (const char *) job_info->pclm_output_buffer, outBuffSize); 295 PCLmFreeBuffer(job_info->pclmgen_obj, job_info->pclm_output_buffer); 296 DestroyPCLmGen(job_info->pclmgen_obj); 297 _END_JOB(job_info); 298 return OK; 299 } 300 301 static bool _canCancelMidPage(void) { 302 return false; 303 } 304 305 static const ifc_pcl_t _pcl_ifc = { 306 _start_job, _end_job, _start_page, _end_page, _print_swath, _canCancelMidPage 307 }; 308 309 ifc_pcl_t *pclm_connect(void) { 310 return ((ifc_pcl_t *) &_pcl_ifc); 311 }