/* * 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 <sys/types.h> #include <stdio.h> #include <stdlib.h> #include <math.h> #include "lib_pcl.h" #include "wprint_image.h" #include "pclm_wrapper_api.h" #include "media.h" #include "wprint_debug.h" #define TAG "lib_pclm" /* * Store a valid media_size name into media_name */ static void _get_pclm_media_size_name(pcl_job_info_t *job_info, media_size_t media_size, char *media_name) { int i = 0; for (i = 0; i < SUPPORTED_MEDIA_SIZE_COUNT; i++) { if (media_size == SupportedMediaSizes[i].media_size) { strncpy(media_name, SupportedMediaSizes[i].PCL6Name, strlen(SupportedMediaSizes[i].PCL6Name)); LOGD("_get_pclm_media_size_name(): match found: %d, %s", media_size, media_name); break; // we found a match, so break out of loop } } if (i == SUPPORTED_MEDIA_SIZE_COUNT) { // media size not found, defaulting to letter LOGD("_get_pclm_media_size_name(): media size, %d, NOT FOUND, setting to letter", media_size); _get_pclm_media_size_name(job_info, US_LETTER, media_name); } } /* * Write a valid media_size into myPageInfo */ static void _get_pclm_media_size(pcl_job_info_t *job_info, media_size_t media_size, PCLmPageSetup *myPageInfo) { int i = SUPPORTED_MEDIA_SIZE_COUNT; if (myPageInfo != NULL) { for (i = 0; i < SUPPORTED_MEDIA_SIZE_COUNT; i++) { if (media_size == SupportedMediaSizes[i].media_size) { strncpy(myPageInfo->mediaSizeName, SupportedMediaSizes[i].PCL6Name, sizeof(myPageInfo->mediaSizeName) - 1); myPageInfo->mediaWidth = floorf( _MI_TO_POINTS(SupportedMediaSizes[i].WidthInInches)); myPageInfo->mediaHeight = floorf( _MI_TO_POINTS(SupportedMediaSizes[i].HeightInInches)); LOGD("_get_pclm_media_size(): match found: %d, %s, width=%f, height=%f", media_size, SupportedMediaSizes[i].PCL6Name, myPageInfo->mediaWidth, myPageInfo->mediaHeight); break; // we found a match, so break out of loop } } } if (i == SUPPORTED_MEDIA_SIZE_COUNT) { // media size not found, defaulting to letter LOGD("_get_pclm_media_size(): media size, %d, NOT FOUND, setting to letter", media_size); _get_pclm_media_size(job_info, US_LETTER, myPageInfo); } } static wJob_t _start_job(wJob_t job_handle, pcl_job_info_t *job_info, media_size_t media_size, media_type_t media_type, int resolution, duplex_t duplex, duplex_dry_time_t dry_time, color_space_t color_space, media_tray_t media_tray, float top_margin, float left_margin) { int outBuffSize = 0; if (job_info == NULL) { return _WJOBH_NONE; } if (job_info->job_handle != _WJOBH_NONE) { if (job_info->wprint_ifc != NULL) { LOGD("_start_job() required cleanup"); } job_info->job_handle = _WJOBH_NONE; } if ((job_info->wprint_ifc == NULL) || (job_info->print_ifc == NULL)) { return _WJOBH_NONE; } LOGD("_start_job(), media_size %d, media_type %d, dt %d, %s, media_tray %d margins T %f L %f", media_size, media_type, dry_time, (duplex == DUPLEX_MODE_NONE) ? "simplex" : "duplex", media_tray, top_margin, left_margin); job_info->job_handle = job_handle; _START_JOB(job_info, "pdf"); job_info->resolution = resolution; job_info->media_size = media_size; job_info->standard_scale = (float) resolution / (float) STANDARD_SCALE_FOR_PDF; // initialize static variables job_info->pclm_output_buffer = NULL; job_info->seed_row = job_info->pcl_buff = NULL; // unused job_info->pixel_width = job_info->pixel_height = job_info->page_number = job_info->num_rows = 0; memset((void *) &job_info->pclm_page_info, 0x0, sizeof(PCLmPageSetup)); _get_pclm_media_size_name(job_info, media_size, &job_info->pclm_page_info.mediaSizeName[0]); if ((left_margin < 0.0f) || (top_margin < 0.0f)) { job_info->pclm_page_info.mediaWidthOffset = 0.0f; job_info->pclm_page_info.mediaHeightOffset = 0.0f; } else { job_info->pclm_page_info.mediaWidthOffset = (left_margin * (float) STANDARD_SCALE_FOR_PDF); job_info->pclm_page_info.mediaHeightOffset = (top_margin * (float) STANDARD_SCALE_FOR_PDF); } LOGI("_start_job(), mediaHeightOffsets W %f H %f", job_info->pclm_page_info.mediaWidthOffset, job_info->pclm_page_info.mediaHeightOffset); job_info->pclm_page_info.pageOrigin = top_left; // REVISIT job_info->monochrome = (color_space == COLOR_SPACE_MONO); job_info->pclm_page_info.dstColorSpaceSpefication = deviceRGB; if (color_space == COLOR_SPACE_MONO) { job_info->pclm_page_info.dstColorSpaceSpefication = grayScale; } else if (color_space == COLOR_SPACE_COLOR) { job_info->pclm_page_info.dstColorSpaceSpefication = deviceRGB; } else if (color_space == COLOR_SPACE_ADOBE_RGB) { job_info->pclm_page_info.dstColorSpaceSpefication = adobeRGB; } job_info->pclm_page_info.stripHeight = job_info->strip_height; job_info->pclm_page_info.destinationResolution = res600; if (resolution == 300) { job_info->pclm_page_info.destinationResolution = res300; } else if (resolution == 600) { job_info->pclm_page_info.destinationResolution = res600; } else if (resolution == 1200) { job_info->pclm_page_info.destinationResolution = res1200; } if (duplex == DUPLEX_MODE_BOOK) { job_info->pclm_page_info.duplexDisposition = duplex_longEdge; } else if (duplex == DUPLEX_MODE_TABLET) { job_info->pclm_page_info.duplexDisposition = duplex_shortEdge; } else { job_info->pclm_page_info.duplexDisposition = simplex; } job_info->pclm_page_info.mirrorBackside = false; job_info->pclmgen_obj = CreatePCLmGen(); PCLmStartJob(job_info->pclmgen_obj, (void **) &job_info->pclm_output_buffer, &outBuffSize); _WRITE(job_info, (const char *) job_info->pclm_output_buffer, outBuffSize); return job_info->job_handle; } static int _start_page(pcl_job_info_t *job_info, int pixel_width, int pixel_height) { PCLmPageSetup *page_info = &job_info->pclm_page_info; ubyte *pclm_output_buff = job_info->pclm_output_buffer; int outBuffSize = 0; _START_PAGE(job_info, pixel_width, pixel_height); page_info->sourceHeight = (float) pixel_height / job_info->standard_scale; page_info->sourceWidth = (float) pixel_width / job_info->standard_scale; LOGI("_start_page(), strip height=%d, image width=%d, image height=%d, scaled width=%f, " "scaled height=%f", page_info->stripHeight, pixel_width, pixel_height, page_info->sourceWidth, page_info->sourceHeight); if (job_info->num_components == 3) { page_info->colorContent = color_content; page_info->srcColorSpaceSpefication = deviceRGB; } else { page_info->colorContent = gray_content; page_info->srcColorSpaceSpefication = grayScale; } /* Note: we could possibly get this value dynamically from device via IPP (ePCL) however, * current ink devices report RLE as the default compression type, which compresses much * worse than JPEG or FLATE */ page_info->compTypeRequested = compressDCT; job_info->scan_line_width = pixel_width * job_info->num_components; int res1 = PCLmGetMediaDimensions(job_info->pclmgen_obj, page_info->mediaSizeName, page_info); page_info->SourceWidthPixels = MIN(pixel_width, job_info->pclm_page_info.mediaWidthInPixels); page_info->SourceHeightPixels = pixel_height; job_info->pclm_scan_line_width = job_info->pclm_page_info.mediaWidthInPixels * job_info->num_components; LOGD("PCLmGetMediaDimensions(%d), mediaSizeName=%s, mediaWidth=%f, mediaHeight=%f, " "widthPixels=%d, heightPixels=%d", res1, job_info->pclm_page_info.mediaSizeName, job_info->pclm_page_info.mediaWidth, job_info->pclm_page_info.mediaHeight, job_info->pclm_page_info.mediaWidthInPixels, job_info->pclm_page_info.mediaHeightInPixels); PCLmStartPage(job_info->pclmgen_obj, page_info, (void **) &pclm_output_buff, &outBuffSize); _WRITE(job_info, (const char *) pclm_output_buff, outBuffSize); job_info->page_number++; return job_info->page_number; } static int _print_swath(pcl_job_info_t *job_info, char *rgb_pixels, int start_row, int num_rows, int bytes_per_row) { int outBuffSize = 0; _PAGE_DATA(job_info, (const unsigned char *) rgb_pixels, (num_rows * bytes_per_row)); if (job_info->monochrome) { unsigned char *buff = (unsigned char *) rgb_pixels; int nbytes = (num_rows * bytes_per_row); int readIndex, writeIndex; for (readIndex = writeIndex = 0; readIndex < nbytes; readIndex += BYTES_PER_PIXEL(1)) { unsigned char gray = SP_GRAY(buff[readIndex + 0], buff[readIndex + 1], buff[readIndex + 2]); buff[writeIndex++] = gray; buff[writeIndex++] = gray; buff[writeIndex++] = gray; } } LOGD("_print_swath(): page #%d, buffSize=%d, rows %d - %d (%d rows), bytes per row %d", job_info->page_number, job_info->strip_height * job_info->scan_line_width, start_row, start_row + num_rows - 1, num_rows, bytes_per_row); if (job_info->scan_line_width > job_info->pclm_scan_line_width) { int i; char *src_pixels = rgb_pixels + job_info->scan_line_width; char *dest_pixels = rgb_pixels + job_info->pclm_scan_line_width; for (i = 1; i < num_rows; i++, src_pixels += job_info->scan_line_width, dest_pixels += job_info->pclm_scan_line_width) { memmove(dest_pixels, src_pixels, job_info->pclm_scan_line_width); } } /* if the inBufferSize is ever used in genPCLm, change the input parameter to pass in * image_info->printable_width*num_components*strip_height * it is currently pixel_width (from _start_page()) * num_components * strip_height */ PCLmEncapsulate(job_info->pclmgen_obj, rgb_pixels, job_info->strip_height * MIN(job_info->scan_line_width, job_info->pclm_scan_line_width), num_rows, (void **) &job_info->pclm_output_buffer, &outBuffSize); _WRITE(job_info, (const char *) job_info->pclm_output_buffer, outBuffSize); return OK; } static int _end_page(pcl_job_info_t *job_info, int page_number) { int outBuffSize = 0; if (page_number == -1) { LOGI("_end_page(): writing blank page"); _start_page(job_info, 0, 0); unsigned char blank_data[1] = {0xFF}; PCLmEncapsulate(job_info->pclmgen_obj, (void *) blank_data, 1, 1, (void **) &job_info->pclm_output_buffer, &outBuffSize); _WRITE(job_info, (const char *) job_info->pclm_output_buffer, outBuffSize); } LOGI("_end_page()"); PCLmEndPage(job_info->pclmgen_obj, (void **) &job_info->pclm_output_buffer, &outBuffSize); _WRITE(job_info, (const char *) job_info->pclm_output_buffer, outBuffSize); _END_PAGE(job_info); return OK; } static int _end_job(pcl_job_info_t *job_info) { int outBuffSize = 0; LOGI("_end_job()"); PCLmEndJob(job_info->pclmgen_obj, (void **) &job_info->pclm_output_buffer, &outBuffSize); _WRITE(job_info, (const char *) job_info->pclm_output_buffer, outBuffSize); PCLmFreeBuffer(job_info->pclmgen_obj, job_info->pclm_output_buffer); DestroyPCLmGen(job_info->pclmgen_obj); _END_JOB(job_info); return OK; } static bool _canCancelMidPage(void) { return false; } static const ifc_pcl_t _pcl_ifc = { _start_job, _end_job, _start_page, _end_page, _print_swath, _canCancelMidPage }; ifc_pcl_t *pclm_connect(void) { return ((ifc_pcl_t *) &_pcl_ifc); }