2 * PostScript driver bitmap functions
4 * Copyright 1998 Huw D M Davies
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "wine/debug.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(psdrv
);
31 /* Return the width of a DIB bitmap in bytes. DIB bitmap data is 32-bit aligned. */
32 static inline int get_dib_width_bytes( int width
, int depth
)
34 return ((width
* depth
+ 31) / 8) & ~3;
38 /***************************************************************************
39 * PSDRV_WriteImageHeader
41 * Helper for PSDRV_PutImage
44 * Uses level 2 PostScript
47 static BOOL
PSDRV_WriteImageHeader(print_ctx
*ctx
, const BITMAPINFO
*info
, BOOL grayscale
, INT xDst
,
48 INT yDst
, INT widthDst
, INT heightDst
,
49 INT widthSrc
, INT heightSrc
)
51 switch(info
->bmiHeader
.biBitCount
)
56 PSDRV_WriteIndexColorSpaceBegin(ctx
, (1 << info
->bmiHeader
.biBitCount
) - 1);
57 PSDRV_WriteRGBQUAD(ctx
, info
->bmiColors
, 1 << info
->bmiHeader
.biBitCount
);
58 PSDRV_WriteIndexColorSpaceEnd(ctx
);
68 pscol
.type
= PSCOLOR_GRAY
;
69 pscol
.value
.gray
.i
= 0;
73 pscol
.type
= PSCOLOR_RGB
;
74 pscol
.value
.rgb
.r
= pscol
.value
.rgb
.g
= pscol
.value
.rgb
.b
= 0.0;
76 PSDRV_WriteSetColor(ctx
, &pscol
);
81 PSDRV_WriteImage(ctx
, info
->bmiHeader
.biBitCount
, grayscale
, xDst
, yDst
,
82 widthDst
, heightDst
, widthSrc
, heightSrc
, FALSE
, info
->bmiHeader
.biHeight
< 0);
87 /***************************************************************************
88 * PSDRV_WriteImageMaskHeader
90 * Helper for PSDRV_PutImage
92 * We use the imagemask operator for 1bpp bitmaps since the output
93 * takes much less time for the printer to render.
96 * Uses level 2 PostScript
99 static BOOL
PSDRV_WriteImageMaskHeader(print_ctx
*ctx
, const BITMAPINFO
*info
, INT xDst
,
100 INT yDst
, INT widthDst
, INT heightDst
,
101 INT widthSrc
, INT heightSrc
)
103 PSCOLOR bkgnd
, foregnd
;
105 assert(info
->bmiHeader
.biBitCount
== 1);
107 /* We'll write the mask with -ve polarity so that
108 the foregnd color corresponds to a bit equal to
111 if (!info
->bmiHeader
.biClrUsed
)
113 PSDRV_CreateColor( ctx
, &foregnd
, GetTextColor( ctx
->hdc
) );
114 bkgnd
= ctx
->bkColor
;
118 PSDRV_CreateColor( ctx
, &foregnd
, RGB(info
->bmiColors
[0].rgbRed
,
119 info
->bmiColors
[0].rgbGreen
,
120 info
->bmiColors
[0].rgbBlue
) );
121 PSDRV_CreateColor( ctx
, &bkgnd
, RGB(info
->bmiColors
[1].rgbRed
,
122 info
->bmiColors
[1].rgbGreen
,
123 info
->bmiColors
[1].rgbBlue
) );
126 PSDRV_WriteGSave(ctx
);
127 PSDRV_WriteNewPath(ctx
);
128 PSDRV_WriteRectangle(ctx
, xDst
, yDst
, widthDst
, heightDst
);
129 PSDRV_WriteSetColor(ctx
, &bkgnd
);
130 PSDRV_WriteFill(ctx
);
131 PSDRV_WriteGRestore(ctx
);
133 PSDRV_WriteSetColor(ctx
, &foregnd
);
134 PSDRV_WriteImage(ctx
, 1, FALSE
, xDst
, yDst
, widthDst
, heightDst
,
135 widthSrc
, heightSrc
, TRUE
, info
->bmiHeader
.biHeight
< 0);
140 static inline DWORD
max_rle_size(DWORD size
)
142 return size
+ (size
+ 127) / 128 + 1;
145 static inline DWORD
max_ascii85_size(DWORD size
)
147 return (size
+ 3) / 4 * 5;
150 static void free_heap_bits( struct ps_image_bits
*bits
)
152 HeapFree( GetProcessHeap(), 0, bits
->ptr
);
155 /***************************************************************************
156 * PSDRV_WriteImageBits
158 static void PSDRV_WriteImageBits( print_ctx
*ctx
, const BITMAPINFO
*info
, BOOL grayscale
, INT xDst
, INT yDst
,
159 INT widthDst
, INT heightDst
, INT widthSrc
, INT heightSrc
,
160 void *bits
, DWORD size
)
163 DWORD rle_len
, ascii85_len
;
165 if (info
->bmiHeader
.biBitCount
== 1)
166 /* Use imagemask rather than image */
167 PSDRV_WriteImageMaskHeader(ctx
, info
, xDst
, yDst
, widthDst
, heightDst
,
168 widthSrc
, heightSrc
);
170 PSDRV_WriteImageHeader(ctx
, info
, grayscale
, xDst
, yDst
, widthDst
, heightDst
,
171 widthSrc
, heightSrc
);
173 rle
= HeapAlloc(GetProcessHeap(), 0, max_rle_size(size
));
174 rle_len
= RLE_encode(bits
, size
, rle
);
175 ascii85
= HeapAlloc(GetProcessHeap(), 0, max_ascii85_size(rle_len
));
176 ascii85_len
= ASCII85_encode(rle
, rle_len
, ascii85
);
177 HeapFree(GetProcessHeap(), 0, rle
);
178 PSDRV_WriteData(ctx
, ascii85
, ascii85_len
);
179 PSDRV_WriteSpool(ctx
, "~>\n", 3);
180 HeapFree(GetProcessHeap(), 0, ascii85
);
183 /***********************************************************************
186 DWORD
PSDRV_PutImage( print_ctx
*ctx
, HRGN clip
, BITMAPINFO
*info
,
187 const struct ps_image_bits
*bits
, struct ps_bitblt_coords
*src
,
188 struct ps_bitblt_coords
*dst
, DWORD rop
)
190 int src_stride
, dst_stride
, size
, x
, y
, width
, height
, bit_offset
;
191 int dst_x
, dst_y
, dst_width
, dst_height
;
192 unsigned char *src_ptr
, *dst_ptr
;
193 struct ps_image_bits dst_bits
;
194 BOOL grayscale
= info
->bmiHeader
.biBitCount
== 24 && ctx
->pi
->ppd
->ColorDevice
== CD_False
;
196 if (info
->bmiHeader
.biPlanes
!= 1) goto update_format
;
197 if (info
->bmiHeader
.biCompression
!= BI_RGB
) goto update_format
;
198 if (info
->bmiHeader
.biBitCount
!= 1 && info
->bmiHeader
.biBitCount
!= 4 &&
199 info
->bmiHeader
.biBitCount
!= 8 && info
->bmiHeader
.biBitCount
!= 24) goto update_format
;
200 if (!bits
) return ERROR_SUCCESS
; /* just querying the format */
202 TRACE( "bpp %u %s -> %s\n", info
->bmiHeader
.biBitCount
, wine_dbgstr_rect(&src
->visrect
),
203 wine_dbgstr_rect(&dst
->visrect
) );
205 width
= src
->visrect
.right
- src
->visrect
.left
;
206 height
= src
->visrect
.bottom
- src
->visrect
.top
;
207 src_stride
= get_dib_width_bytes( info
->bmiHeader
.biWidth
, info
->bmiHeader
.biBitCount
);
208 if (grayscale
) dst_stride
= width
;
209 else dst_stride
= (width
* info
->bmiHeader
.biBitCount
+ 7) / 8;
212 if (info
->bmiHeader
.biHeight
> 0)
213 src_ptr
+= (info
->bmiHeader
.biHeight
- src
->visrect
.bottom
) * src_stride
;
215 src_ptr
+= src
->visrect
.top
* src_stride
;
216 bit_offset
= src
->visrect
.left
* info
->bmiHeader
.biBitCount
;
217 src_ptr
+= bit_offset
/ 8;
219 if (bit_offset
) FIXME( "pos %s not supported\n", wine_dbgstr_rect(&src
->visrect
) );
220 size
= height
* dst_stride
;
222 if (src_stride
!= dst_stride
|| (info
->bmiHeader
.biBitCount
== 24 && !bits
->is_copy
))
224 if (!(dst_bits
.ptr
= HeapAlloc( GetProcessHeap(), 0, size
))) return ERROR_OUTOFMEMORY
;
225 dst_bits
.is_copy
= TRUE
;
226 dst_bits
.free
= free_heap_bits
;
230 dst_bits
.ptr
= src_ptr
;
231 dst_bits
.is_copy
= bits
->is_copy
;
232 dst_bits
.free
= NULL
;
234 dst_ptr
= dst_bits
.ptr
;
236 switch (info
->bmiHeader
.biBitCount
)
241 if (src_stride
!= dst_stride
)
242 for (y
= 0; y
< height
; y
++, src_ptr
+= src_stride
, dst_ptr
+= dst_stride
)
243 memcpy( dst_ptr
, src_ptr
, dst_stride
);
248 PSRGB scale
= rgb_to_grayscale_scale();
249 for (y
= 0; y
< height
; y
++, src_ptr
+= src_stride
, dst_ptr
+= dst_stride
)
250 for (x
= 0; x
< width
; x
++)
251 dst_ptr
[x
] = src_ptr
[x
* 3 + 2] * scale
.r
+ src_ptr
[x
* 3 + 1] * scale
.g
+ src_ptr
[x
* 3] * scale
.b
;
253 else if (dst_ptr
!= src_ptr
)
254 for (y
= 0; y
< height
; y
++, src_ptr
+= src_stride
, dst_ptr
+= dst_stride
)
255 for (x
= 0; x
< width
; x
++)
257 dst_ptr
[x
* 3] = src_ptr
[x
* 3 + 2];
258 dst_ptr
[x
* 3 + 1] = src_ptr
[x
* 3 + 1];
259 dst_ptr
[x
* 3 + 2] = src_ptr
[x
* 3];
261 else /* swap R and B in place */
262 for (y
= 0; y
< height
; y
++, src_ptr
+= src_stride
, dst_ptr
+= dst_stride
)
263 for (x
= 0; x
< width
; x
++)
265 unsigned char tmp
= dst_ptr
[x
* 3];
266 dst_ptr
[x
* 3] = dst_ptr
[x
* 3 + 2];
267 dst_ptr
[x
* 3 + 2] = tmp
;
272 dst_x
= dst
->visrect
.left
;
273 dst_y
= dst
->visrect
.top
;
274 dst_width
= dst
->visrect
.right
- dst
->visrect
.left
;
275 dst_height
= dst
->visrect
.bottom
- dst
->visrect
.top
;
276 if (src
->width
* dst
->width
< 0)
279 dst_width
= -dst_width
;
281 if (src
->height
* dst
->height
< 0)
284 dst_height
= -dst_height
;
288 PSDRV_WriteGSave(ctx
);
289 if (clip
) PSDRV_AddClip( ctx
, clip
);
290 PSDRV_WriteImageBits( ctx
, info
, grayscale
, dst_x
, dst_y
, dst_width
, dst_height
,
291 width
, height
, dst_bits
.ptr
, size
);
292 PSDRV_WriteGRestore(ctx
);
293 PSDRV_ResetClip(ctx
);
294 if (dst_bits
.free
) dst_bits
.free( &dst_bits
);
295 return ERROR_SUCCESS
;
298 info
->bmiHeader
.biPlanes
= 1;
299 if (info
->bmiHeader
.biBitCount
!= 1 && info
->bmiHeader
.biBitCount
!= 4 &&
300 info
->bmiHeader
.biBitCount
!= 8 && info
->bmiHeader
.biBitCount
!= 24)
301 info
->bmiHeader
.biBitCount
= 24;
302 info
->bmiHeader
.biCompression
= BI_RGB
;
303 return ERROR_BAD_FORMAT
;