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 */
_get_pclm_media_size_name(pcl_job_info_t * job_info,media_size_t media_size,char * media_name)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 */
_get_pclm_media_size(pcl_job_info_t * job_info,media_size_t media_size,PCLmPageSetup * myPageInfo)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
_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)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
_start_page(pcl_job_info_t * job_info,int pixel_width,int pixel_height)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
_print_swath(pcl_job_info_t * job_info,char * rgb_pixels,int start_row,int num_rows,int bytes_per_row)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
_end_page(pcl_job_info_t * job_info,int page_number)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
_end_job(pcl_job_info_t * job_info)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
_canCancelMidPage(void)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
pclm_connect(void)309 ifc_pcl_t *pclm_connect(void) {
310 return ((ifc_pcl_t *) &_pcl_ifc);
311 }