1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
|
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved
//
// File Name:
//
// rasinterface.cpp
//
// Abstract:
//
// Class to wrap rasterization-related calculations, interactions with
// the Xps Rasterization Service, Xps Rasterization Service Callback,
// and eventual raster output (i.e. TIFF encoding)
//
#include "precomp.h"
#include "WppTrace.h"
#include "Exception.h"
#include "filtertypes.h"
#include "UnknownBase.h"
#include "xpsrasfilter.h"
#include "OMConvertor.h"
#include "rasinterface.h"
#include "BitmapHandler.h"
#include "rasinterface.tmh"
namespace xpsrasfilter
{
//
//Routine Name:
//
// RasterizationInterface::CreateRasterizationInterface
//
//Routine Description:
//
// Static factory method that creates an instance of
// RasterizationInterface.
//
//Arguments:
//
// pPropertyBag - Property Bag
// pStream - Filter output stream (IPrintWriteStream)
//
//Return Value:
//
// RasterizationInterface_t (smart ptr)
// The new RasterizationInterface.
//
RasterizationInterface_t
RasterizationInterface::CreateRasterizationInterface(
const IPrintPipelinePropertyBag_t &pPropertyBag,
const IPrintWriteStream_t &pStream
)
{
Variant_t varRasFactory;
IXpsRasterizationFactory_t pXPSRasFactory;
//
// Get the Xps Rasterization Service factory. Since XpsRasterService.dll
// is specified as an OptionalFilterServiceProvider in the filter pipeline
// configuration file, the factory may not be available in the property bag
// (e.g. when running on Windows Vista, Windows XP, etc). In this case,
// this call will fail and the filter could fail, as we do here, or could
// default to some other behavior.
//
THROW_ON_FAILED_HRESULT(
pPropertyBag->GetProperty(
L"MS_IXpsRasterizationFactory",
&varRasFactory
)
);
IUnknown_t pUnk(varRasFactory.punkVal);
THROW_ON_FAILED_HRESULT(
pUnk.QueryInterface(&pXPSRasFactory)
);
//
// Prepare the rasterization/encode/stream interface
//
TiffStreamBitmapHandler_t pBitmapHandler(
TiffStreamBitmapHandler::CreateTiffStreamBitmapHandler(pStream)
);
RasterizationInterface_t pReturnInterface(
new RasterizationInterface(
pXPSRasFactory,
pBitmapHandler
)
);
return pReturnInterface;
}
//
//Routine Name:
//
// RasterizationInterface::RasterizationInterface
//
//Routine Description:
//
// Construct the Rasterization Interface with the
// IXpsRasterizationFactory interface and bitmap
// handler.
//
//Arguments:
//
// pRasFactory - Xps Rasterization Service object factory
// pBitmapHandler - Class to handle band bitmaps
//
RasterizationInterface::RasterizationInterface(
const IXpsRasterizationFactory_t &pRasFactory,
TiffStreamBitmapHandler_t pBitmapHandler
) : m_pXPSRasFactory(pRasFactory),
m_pBitmapHandler(pBitmapHandler)
{
}
//
//Routine Name:
//
// RasterizationInterface::FinishRasterization
//
//Routine Description:
//
// Tell the Rasterization Interface that the last
// page has been rasterized.
//
//Arguments:
//
// None
//
void
RasterizationInterface::FinishRasterization()
{
m_pBitmapHandler->WriteFooter();
}
//
//Routine Name:
//
// RasterizationInterface::RasterizeAndStreamPage
//
//Routine Description:
//
// Given an IXpsOMPage and a set of Print Ticket
// parameters, this method invokes the Xps Rasterization
// Service for each band of the page, and outputs the
// resultant raster data.
//
//Arguments:
//
// pPage - page to rasterize
// printTicketparams - raw parameters from the print ticket(s)
//
void
RasterizationInterface::RasterizePage(
const IXpsOMPage_t &pPage,
const ParametersFromPrintTicket &printTicketParams,
const FilterLiveness_t &pLiveness
)
{
//
// Calculate rasterization parameters
//
ParametersFromFixedPage fixedPageParams;
THROW_ON_FAILED_HRESULT(
pPage->GetPageDimensions(&fixedPageParams.fixedPageSize)
);
THROW_ON_FAILED_HRESULT(
pPage->GetBleedBox(&fixedPageParams.bleedBoxRect)
);
THROW_ON_FAILED_HRESULT(
pPage->GetContentBox(&fixedPageParams.contentBoxRect)
);
RasterizationParameters rastParams(
printTicketParams,
fixedPageParams
);
//
// Create the Rasterizer
//
IXpsRasterizer_t rasterizer;
THROW_ON_FAILED_HRESULT(
m_pXPSRasFactory->CreateRasterizer(
pPage,
rastParams.rasterizationDPI,
XPSRAS_RENDERING_MODE_ANTIALIASED,
XPSRAS_RENDERING_MODE_ANTIALIASED,
&rasterizer
)
);
//
// Set the minimal line width to 1 pixel
//
THROW_ON_FAILED_HRESULT(
rasterizer->SetMinimalLineWidth(1)
);
//
// Loop over bands
//
INT bandOriginY = 0;
while (pLiveness->IsAlive() &&
bandOriginY < rastParams.rasterHeight)
{
DoTraceMessage(XPSRASFILTER_TRACE_VERBOSE, L"Rasterizing Band");
IWICBitmap_t bitmap;
//
// Calculate the height of this band
//
INT bandHeight = rastParams.bandHeight;
if (bandOriginY + rastParams.bandHeight >= rastParams.rasterHeight)
{
bandHeight = rastParams.rasterHeight - bandOriginY;
}
//
// Rasterize this band
//
{
HRESULT hr = rasterizer->RasterizeRect(
rastParams.originX,
bandOriginY + rastParams.originY,
rastParams.rasterWidth,
bandHeight,
static_cast<IXpsRasterizerNotificationCallback *>(pLiveness),
&bitmap
);
//
// Do not throw if we have cancelled rasterization
//
if (hr == HRESULT_FROM_WIN32(ERROR_PRINT_CANCELLED))
{
DoTraceMessage(XPSRASFILTER_TRACE_VERBOSE, L"Rasterization Cancelled");
return;
}
THROW_ON_FAILED_HRESULT(hr);
}
bandOriginY += bandHeight;
//
// The resolution of the bitmap defaults to the
// rasterization DPI, which includes the scaling factor.
// We want the output bitmap to reflect the destination DPI.
//
THROW_ON_FAILED_HRESULT(
bitmap->SetResolution(
printTicketParams.destDPI,
printTicketParams.destDPI
)
);
//
// Encode the raster data as TIFF and stream out
//
m_pBitmapHandler->ProcessBitmap(bitmap);
}
}
//
//Routine Name:
//
// RasterizationParameters::RasterizationParameters
//
//Routine Description:
//
// Given a set of fixed page parameters and a set of Print Ticket
// parameters, this constructor calculates the parameters necessary to
// invoke the Xps Rasterization Service.
//
//Arguments:
//
// printTicketparams - raw parameters from the print ticket(s)
// fixedPageParams - raw parameters from the fixed page
//
RasterizationParameters::RasterizationParameters(
const ParametersFromPrintTicket &printTicketParams,
const ParametersFromFixedPage &fixedPageParams
)
{
//
// Rasterize the entire physical page at the desired resolution. The fixed page
// is scaled and traslated to place it correctly witin the physical page.
//
rasterHeight = static_cast<INT>(
printTicketParams.physicalPageSize.height
* (printTicketParams.destDPI / xpsDPI)
+ 0.5
);
rasterWidth = static_cast<INT>(
printTicketParams.physicalPageSize.width
* (printTicketParams.destDPI / xpsDPI)
+ 0.5
);
//
// Determine the source rectangle for the scale operation
//
XPS_RECT srcRect = {0,0,0,0};
switch(printTicketParams.scaling)
{
case SCALE_BLEEDTOIMAGEABLE:
srcRect = fixedPageParams.bleedBoxRect;
break;
default:
DoTraceMessage(XPSRASFILTER_TRACE_ERROR, L"Unknown scaling type");
THROW_ON_FAILED_HRESULT(E_UNEXPECTED);
break;
}
//
// Determine the destination rectangle for the scale operation
//
XPS_RECT destRect = {0,0,0,0};
switch(printTicketParams.scaling)
{
case SCALE_BLEEDTOIMAGEABLE:
destRect = printTicketParams.imageableArea;
break;
default:
DoTraceMessage(XPSRASFILTER_TRACE_ERROR, L"Unknown scaling type");
THROW_ON_FAILED_HRESULT(E_UNEXPECTED);
break;
}
//
// Because we want to fit the fixed page into a physical page of
// potentially different aspect ratio, it is necessary to calculate
// the scaling factor assuming either the height or width constrains
// the operation; the rasterization dpi is then the smaller of the two.
//
//
// The basic calculation for scaling factor is:
//
// Scaling Factor = (Destination Dimension / Source Dimension)
//
// Multiplying by desired Destination DPI we get the DPI at which to
// rasterize the source content in order to get the desired size
//
// Rasterization DPI = Scaling Factor * Desired Destination DPI
//
{
FLOAT heightScalingFactor = destRect.height / srcRect.height;
FLOAT widthScalingFactor = destRect.width / srcRect.width;
FLOAT heightRastDPI = heightScalingFactor * printTicketParams.destDPI;
FLOAT widthRastDPI = widthScalingFactor * printTicketParams.destDPI;
rasterizationDPI = min(heightRastDPI, widthRastDPI);
}
//
// To determine the rasterization origin, subtract the translation
// due to the destination rectangle (e.g. imageable area) from the
// translation due to the choice of scale (e.g. bleed box origin)
//
{
FLOAT srcOffsetX = srcRect.x * rasterizationDPI / xpsDPI;
FLOAT srcOffsetY = srcRect.y * rasterizationDPI / xpsDPI;
FLOAT destOffsetX = destRect.x * printTicketParams.destDPI / xpsDPI;
FLOAT destOffsetY = destRect.y * printTicketParams.destDPI / xpsDPI;
originX = static_cast<INT>(srcOffsetX - destOffsetX - 0.5);
originY = static_cast<INT>(srcOffsetY - destOffsetY - 0.5);
}
//
// The height of each band is determined by the maximum band size (in bytes)
// divided by 4 bytes per pixel to get the total pixels, and then divided by
// the width of the raster data. This results in a band bitmap that is close
// to the target band size.
//
bandHeight = (RasterizationInterface::ms_targetBandSize / 4) / rasterWidth;
if (bandHeight == 0)
{
//
// The physical page is too wide to rasterize at this
// maximum band size and dpi. Throw.
//
THROW_ON_FAILED_HRESULT(
E_OUTOFMEMORY
);
}
}
} // namespace xpsrasfilter
|