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
;
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 PSDRV_CreateColor(dev
, &foregnd
, RGB(info
->bmiColors
[0].rgbRed
,
112 info
->bmiColors
[0].rgbGreen
,
113 info
->bmiColors
[0].rgbBlue
) );
114 PSDRV_CreateColor(dev
, &bkgnd
, RGB(info
->bmiColors
[1].rgbRed
,
115 info
->bmiColors
[1].rgbGreen
,
116 info
->bmiColors
[1].rgbBlue
) );
118 PSDRV_WriteGSave(dev
);
119 PSDRV_WriteNewPath(dev
);
120 PSDRV_WriteRectangle(dev
, xDst
, yDst
, widthDst
, heightDst
);
121 PSDRV_WriteSetColor(dev
, &bkgnd
);
122 PSDRV_WriteFill(dev
);
123 PSDRV_WriteGRestore(dev
);
125 PSDRV_WriteSetColor(dev
, &foregnd
);
126 PSDRV_WriteImage(dev
, 1, FALSE
, xDst
, yDst
, widthDst
, heightDst
,
127 widthSrc
, heightSrc
, TRUE
, info
->bmiHeader
.biHeight
< 0);
132 static inline DWORD
max_rle_size(DWORD size
)
134 return size
+ (size
+ 127) / 128 + 1;
137 static inline DWORD
max_ascii85_size(DWORD size
)
139 return (size
+ 3) / 4 * 5;
142 static void free_heap_bits( struct gdi_image_bits
*bits
)
144 HeapFree( GetProcessHeap(), 0, bits
->ptr
);
147 /***************************************************************************
148 * PSDRV_WriteImageBits
150 static void PSDRV_WriteImageBits( PHYSDEV dev
, const BITMAPINFO
*info
, BOOL grayscale
, INT xDst
, INT yDst
,
151 INT widthDst
, INT heightDst
, INT widthSrc
, INT heightSrc
,
152 void *bits
, DWORD size
)
155 DWORD rle_len
, ascii85_len
;
157 if (info
->bmiHeader
.biBitCount
== 1)
158 /* Use imagemask rather than image */
159 PSDRV_WriteImageMaskHeader(dev
, info
, xDst
, yDst
, widthDst
, heightDst
,
160 widthSrc
, heightSrc
);
162 PSDRV_WriteImageHeader(dev
, info
, grayscale
, xDst
, yDst
, widthDst
, heightDst
,
163 widthSrc
, heightSrc
);
165 rle
= HeapAlloc(GetProcessHeap(), 0, max_rle_size(size
));
166 rle_len
= RLE_encode(bits
, size
, rle
);
167 ascii85
= HeapAlloc(GetProcessHeap(), 0, max_ascii85_size(rle_len
));
168 ascii85_len
= ASCII85_encode(rle
, rle_len
, ascii85
);
169 HeapFree(GetProcessHeap(), 0, rle
);
170 PSDRV_WriteData(dev
, ascii85
, ascii85_len
);
171 PSDRV_WriteSpool(dev
, "~>\n", 3);
172 HeapFree(GetProcessHeap(), 0, ascii85
);
175 /***********************************************************************
178 DWORD
PSDRV_PutImage( PHYSDEV dev
, HRGN clip
, BITMAPINFO
*info
,
179 const struct gdi_image_bits
*bits
, struct bitblt_coords
*src
,
180 struct bitblt_coords
*dst
, DWORD rop
)
182 int src_stride
, dst_stride
, size
, x
, y
, width
, height
, bit_offset
;
183 int dst_x
, dst_y
, dst_width
, dst_height
;
184 unsigned char *src_ptr
, *dst_ptr
;
185 struct gdi_image_bits dst_bits
;
186 PSDRV_PDEVICE
*physDev
= get_psdrv_dev( dev
);
187 BOOL grayscale
= info
->bmiHeader
.biBitCount
== 24 && physDev
->pi
->ppd
->ColorDevice
== CD_False
;
189 if (info
->bmiHeader
.biPlanes
!= 1) goto update_format
;
190 if (info
->bmiHeader
.biCompression
!= BI_RGB
) goto update_format
;
191 if (info
->bmiHeader
.biBitCount
== 16 || info
->bmiHeader
.biBitCount
== 32) goto update_format
;
192 if (!bits
) return ERROR_SUCCESS
; /* just querying the format */
194 TRACE( "bpp %u %s -> %s\n", info
->bmiHeader
.biBitCount
, wine_dbgstr_rect(&src
->visrect
),
195 wine_dbgstr_rect(&dst
->visrect
) );
197 width
= src
->visrect
.right
- src
->visrect
.left
;
198 height
= src
->visrect
.bottom
- src
->visrect
.top
;
199 src_stride
= get_dib_width_bytes( info
->bmiHeader
.biWidth
, info
->bmiHeader
.biBitCount
);
200 if (grayscale
) dst_stride
= width
;
201 else dst_stride
= (width
* info
->bmiHeader
.biBitCount
+ 7) / 8;
204 if (info
->bmiHeader
.biHeight
> 0)
205 src_ptr
+= (info
->bmiHeader
.biHeight
- src
->visrect
.bottom
) * src_stride
;
207 src_ptr
+= src
->visrect
.top
* src_stride
;
208 bit_offset
= src
->visrect
.left
* info
->bmiHeader
.biBitCount
;
209 src_ptr
+= bit_offset
/ 8;
211 if (bit_offset
) FIXME( "pos %s not supported\n", wine_dbgstr_rect(&src
->visrect
) );
212 size
= height
* dst_stride
;
214 if (src_stride
!= dst_stride
|| (info
->bmiHeader
.biBitCount
== 24 && !bits
->is_copy
))
216 if (!(dst_bits
.ptr
= HeapAlloc( GetProcessHeap(), 0, size
))) return ERROR_OUTOFMEMORY
;
217 dst_bits
.is_copy
= TRUE
;
218 dst_bits
.free
= free_heap_bits
;
222 dst_bits
.ptr
= src_ptr
;
223 dst_bits
.is_copy
= bits
->is_copy
;
224 dst_bits
.free
= NULL
;
226 dst_ptr
= dst_bits
.ptr
;
228 switch (info
->bmiHeader
.biBitCount
)
233 if (src_stride
!= dst_stride
)
234 for (y
= 0; y
< height
; y
++, src_ptr
+= src_stride
, dst_ptr
+= dst_stride
)
235 memcpy( dst_ptr
, src_ptr
, dst_stride
);
240 PSRGB scale
= rgb_to_grayscale_scale();
241 for (y
= 0; y
< height
; y
++, src_ptr
+= src_stride
, dst_ptr
+= dst_stride
)
242 for (x
= 0; x
< width
; x
++)
243 dst_ptr
[x
] = src_ptr
[x
* 3 + 2] * scale
.r
+ src_ptr
[x
* 3 + 1] * scale
.g
+ src_ptr
[x
* 3] * scale
.b
;
245 else if (dst_ptr
!= src_ptr
)
246 for (y
= 0; y
< height
; y
++, src_ptr
+= src_stride
, dst_ptr
+= dst_stride
)
247 for (x
= 0; x
< width
; x
++)
249 dst_ptr
[x
* 3] = src_ptr
[x
* 3 + 2];
250 dst_ptr
[x
* 3 + 1] = src_ptr
[x
* 3 + 1];
251 dst_ptr
[x
* 3 + 2] = src_ptr
[x
* 3];
253 else /* swap R and B in place */
254 for (y
= 0; y
< height
; y
++, src_ptr
+= src_stride
, dst_ptr
+= dst_stride
)
255 for (x
= 0; x
< width
; x
++)
257 unsigned char tmp
= dst_ptr
[x
* 3];
258 dst_ptr
[x
* 3] = dst_ptr
[x
* 3 + 2];
259 dst_ptr
[x
* 3 + 2] = tmp
;
264 dst_x
= dst
->visrect
.left
;
265 dst_y
= dst
->visrect
.top
,
266 dst_width
= dst
->visrect
.right
- dst
->visrect
.left
;
267 dst_height
= dst
->visrect
.bottom
- dst
->visrect
.top
;
268 if (src
->width
* dst
->width
< 0)
271 dst_width
= -dst_width
;
273 if (src
->height
* dst
->height
< 0)
276 dst_height
= -dst_height
;
280 PSDRV_WriteGSave(dev
);
281 if (clip
) PSDRV_AddClip( dev
, clip
);
282 PSDRV_WriteImageBits( dev
, info
, grayscale
, dst_x
, dst_y
, dst_width
, dst_height
,
283 width
, height
, dst_bits
.ptr
, size
);
284 PSDRV_WriteGRestore(dev
);
285 PSDRV_ResetClip(dev
);
286 if (dst_bits
.free
) dst_bits
.free( &dst_bits
);
287 return ERROR_SUCCESS
;
290 info
->bmiHeader
.biPlanes
= 1;
291 if (info
->bmiHeader
.biBitCount
> 8) info
->bmiHeader
.biBitCount
= 24;
292 info
->bmiHeader
.biCompression
= BI_RGB
;
293 return ERROR_BAD_FORMAT
;