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(PHYSDEV dev
, 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(dev
, (1 << info
->bmiHeader
.biBitCount
) - 1);
57 PSDRV_WriteRGBQUAD(dev
, info
->bmiColors
, 1 << info
->bmiHeader
.biBitCount
);
58 PSDRV_WriteIndexColorSpaceEnd(dev
);
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(dev
, &pscol
);
81 PSDRV_WriteImage(dev
, 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(PHYSDEV dev
, const BITMAPINFO
*info
, INT xDst
,
100 INT yDst
, INT widthDst
, INT heightDst
,
101 INT widthSrc
, INT heightSrc
)
103 PSCOLOR bkgnd
, foregnd
;
104 PSDRV_PDEVICE
*physDev
= get_psdrv_dev( dev
);
106 assert(info
->bmiHeader
.biBitCount
== 1);
108 /* We'll write the mask with -ve polarity so that
109 the foregnd color corresponds to a bit equal to
112 if (!info
->bmiHeader
.biClrUsed
)
114 PSDRV_CreateColor( dev
, &foregnd
, GetTextColor( dev
->hdc
) );
115 bkgnd
= physDev
->bkColor
;
119 PSDRV_CreateColor( dev
, &foregnd
, RGB(info
->bmiColors
[0].rgbRed
,
120 info
->bmiColors
[0].rgbGreen
,
121 info
->bmiColors
[0].rgbBlue
) );
122 PSDRV_CreateColor( dev
, &bkgnd
, RGB(info
->bmiColors
[1].rgbRed
,
123 info
->bmiColors
[1].rgbGreen
,
124 info
->bmiColors
[1].rgbBlue
) );
127 PSDRV_WriteGSave(dev
);
128 PSDRV_WriteNewPath(dev
);
129 PSDRV_WriteRectangle(dev
, xDst
, yDst
, widthDst
, heightDst
);
130 PSDRV_WriteSetColor(dev
, &bkgnd
);
131 PSDRV_WriteFill(dev
);
132 PSDRV_WriteGRestore(dev
);
134 PSDRV_WriteSetColor(dev
, &foregnd
);
135 PSDRV_WriteImage(dev
, 1, FALSE
, xDst
, yDst
, widthDst
, heightDst
,
136 widthSrc
, heightSrc
, TRUE
, info
->bmiHeader
.biHeight
< 0);
141 static inline DWORD
max_rle_size(DWORD size
)
143 return size
+ (size
+ 127) / 128 + 1;
146 static inline DWORD
max_ascii85_size(DWORD size
)
148 return (size
+ 3) / 4 * 5;
151 static void free_heap_bits( struct gdi_image_bits
*bits
)
153 HeapFree( GetProcessHeap(), 0, bits
->ptr
);
156 /***************************************************************************
157 * PSDRV_WriteImageBits
159 static void PSDRV_WriteImageBits( PHYSDEV dev
, const BITMAPINFO
*info
, BOOL grayscale
, INT xDst
, INT yDst
,
160 INT widthDst
, INT heightDst
, INT widthSrc
, INT heightSrc
,
161 void *bits
, DWORD size
)
164 DWORD rle_len
, ascii85_len
;
166 if (info
->bmiHeader
.biBitCount
== 1)
167 /* Use imagemask rather than image */
168 PSDRV_WriteImageMaskHeader(dev
, info
, xDst
, yDst
, widthDst
, heightDst
,
169 widthSrc
, heightSrc
);
171 PSDRV_WriteImageHeader(dev
, info
, grayscale
, xDst
, yDst
, widthDst
, heightDst
,
172 widthSrc
, heightSrc
);
174 rle
= HeapAlloc(GetProcessHeap(), 0, max_rle_size(size
));
175 rle_len
= RLE_encode(bits
, size
, rle
);
176 ascii85
= HeapAlloc(GetProcessHeap(), 0, max_ascii85_size(rle_len
));
177 ascii85_len
= ASCII85_encode(rle
, rle_len
, ascii85
);
178 HeapFree(GetProcessHeap(), 0, rle
);
179 PSDRV_WriteData(dev
, ascii85
, ascii85_len
);
180 PSDRV_WriteSpool(dev
, "~>\n", 3);
181 HeapFree(GetProcessHeap(), 0, ascii85
);
184 /***********************************************************************
187 DWORD
PSDRV_PutImage( PHYSDEV dev
, HRGN clip
, BITMAPINFO
*info
,
188 const struct gdi_image_bits
*bits
, struct bitblt_coords
*src
,
189 struct bitblt_coords
*dst
, DWORD rop
)
191 int src_stride
, dst_stride
, size
, x
, y
, width
, height
, bit_offset
;
192 int dst_x
, dst_y
, dst_width
, dst_height
;
193 unsigned char *src_ptr
, *dst_ptr
;
194 struct gdi_image_bits dst_bits
;
195 PSDRV_PDEVICE
*physDev
= get_psdrv_dev( dev
);
196 BOOL grayscale
= info
->bmiHeader
.biBitCount
== 24 && physDev
->pi
->ppd
->ColorDevice
== CD_False
;
198 if (info
->bmiHeader
.biPlanes
!= 1) goto update_format
;
199 if (info
->bmiHeader
.biCompression
!= BI_RGB
) goto update_format
;
200 if (info
->bmiHeader
.biBitCount
== 16 || info
->bmiHeader
.biBitCount
== 32) goto update_format
;
201 if (!bits
) return ERROR_SUCCESS
; /* just querying the format */
203 TRACE( "bpp %u %s -> %s\n", info
->bmiHeader
.biBitCount
, wine_dbgstr_rect(&src
->visrect
),
204 wine_dbgstr_rect(&dst
->visrect
) );
206 width
= src
->visrect
.right
- src
->visrect
.left
;
207 height
= src
->visrect
.bottom
- src
->visrect
.top
;
208 src_stride
= get_dib_width_bytes( info
->bmiHeader
.biWidth
, info
->bmiHeader
.biBitCount
);
209 if (grayscale
) dst_stride
= width
;
210 else dst_stride
= (width
* info
->bmiHeader
.biBitCount
+ 7) / 8;
213 if (info
->bmiHeader
.biHeight
> 0)
214 src_ptr
+= (info
->bmiHeader
.biHeight
- src
->visrect
.bottom
) * src_stride
;
216 src_ptr
+= src
->visrect
.top
* src_stride
;
217 bit_offset
= src
->visrect
.left
* info
->bmiHeader
.biBitCount
;
218 src_ptr
+= bit_offset
/ 8;
220 if (bit_offset
) FIXME( "pos %s not supported\n", wine_dbgstr_rect(&src
->visrect
) );
221 size
= height
* dst_stride
;
223 if (src_stride
!= dst_stride
|| (info
->bmiHeader
.biBitCount
== 24 && !bits
->is_copy
))
225 if (!(dst_bits
.ptr
= HeapAlloc( GetProcessHeap(), 0, size
))) return ERROR_OUTOFMEMORY
;
226 dst_bits
.is_copy
= TRUE
;
227 dst_bits
.free
= free_heap_bits
;
231 dst_bits
.ptr
= src_ptr
;
232 dst_bits
.is_copy
= bits
->is_copy
;
233 dst_bits
.free
= NULL
;
235 dst_ptr
= dst_bits
.ptr
;
237 switch (info
->bmiHeader
.biBitCount
)
242 if (src_stride
!= dst_stride
)
243 for (y
= 0; y
< height
; y
++, src_ptr
+= src_stride
, dst_ptr
+= dst_stride
)
244 memcpy( dst_ptr
, src_ptr
, dst_stride
);
249 PSRGB scale
= rgb_to_grayscale_scale();
250 for (y
= 0; y
< height
; y
++, src_ptr
+= src_stride
, dst_ptr
+= dst_stride
)
251 for (x
= 0; x
< width
; x
++)
252 dst_ptr
[x
] = src_ptr
[x
* 3 + 2] * scale
.r
+ src_ptr
[x
* 3 + 1] * scale
.g
+ src_ptr
[x
* 3] * scale
.b
;
254 else if (dst_ptr
!= src_ptr
)
255 for (y
= 0; y
< height
; y
++, src_ptr
+= src_stride
, dst_ptr
+= dst_stride
)
256 for (x
= 0; x
< width
; x
++)
258 dst_ptr
[x
* 3] = src_ptr
[x
* 3 + 2];
259 dst_ptr
[x
* 3 + 1] = src_ptr
[x
* 3 + 1];
260 dst_ptr
[x
* 3 + 2] = src_ptr
[x
* 3];
262 else /* swap R and B in place */
263 for (y
= 0; y
< height
; y
++, src_ptr
+= src_stride
, dst_ptr
+= dst_stride
)
264 for (x
= 0; x
< width
; x
++)
266 unsigned char tmp
= dst_ptr
[x
* 3];
267 dst_ptr
[x
* 3] = dst_ptr
[x
* 3 + 2];
268 dst_ptr
[x
* 3 + 2] = tmp
;
273 dst_x
= dst
->visrect
.left
;
274 dst_y
= dst
->visrect
.top
,
275 dst_width
= dst
->visrect
.right
- dst
->visrect
.left
;
276 dst_height
= dst
->visrect
.bottom
- dst
->visrect
.top
;
277 if (src
->width
* dst
->width
< 0)
280 dst_width
= -dst_width
;
282 if (src
->height
* dst
->height
< 0)
285 dst_height
= -dst_height
;
289 PSDRV_WriteGSave(dev
);
290 if (clip
) PSDRV_AddClip( dev
, clip
);
291 PSDRV_WriteImageBits( dev
, info
, grayscale
, dst_x
, dst_y
, dst_width
, dst_height
,
292 width
, height
, dst_bits
.ptr
, size
);
293 PSDRV_WriteGRestore(dev
);
294 PSDRV_ResetClip(dev
);
295 if (dst_bits
.free
) dst_bits
.free( &dst_bits
);
296 return ERROR_SUCCESS
;
299 info
->bmiHeader
.biPlanes
= 1;
300 if (info
->bmiHeader
.biBitCount
> 8) info
->bmiHeader
.biBitCount
= 24;
301 info
->bmiHeader
.biCompression
= BI_RGB
;
302 return ERROR_BAD_FORMAT
;