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
, 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
);
66 pscol
.type
= PSCOLOR_RGB
;
67 pscol
.value
.rgb
.r
= pscol
.value
.rgb
.g
= pscol
.value
.rgb
.b
= 0.0;
68 PSDRV_WriteSetColor(dev
, &pscol
);
73 PSDRV_WriteImage(dev
, info
->bmiHeader
.biBitCount
, xDst
, yDst
,
74 widthDst
, heightDst
, widthSrc
, heightSrc
, FALSE
, info
->bmiHeader
.biHeight
< 0);
79 /***************************************************************************
80 * PSDRV_WriteImageMaskHeader
82 * Helper for PSDRV_PutImage
84 * We use the imagemask operator for 1bpp bitmaps since the output
85 * takes much less time for the printer to render.
88 * Uses level 2 PostScript
91 static BOOL
PSDRV_WriteImageMaskHeader(PHYSDEV dev
, const BITMAPINFO
*info
, INT xDst
,
92 INT yDst
, INT widthDst
, INT heightDst
,
93 INT widthSrc
, INT heightSrc
)
95 PSCOLOR bkgnd
, foregnd
;
97 assert(info
->bmiHeader
.biBitCount
== 1);
99 /* We'll write the mask with -ve polarity so that
100 the foregnd color corresponds to a bit equal to
103 PSDRV_CreateColor(dev
, &foregnd
, RGB(info
->bmiColors
[0].rgbRed
,
104 info
->bmiColors
[0].rgbGreen
,
105 info
->bmiColors
[0].rgbBlue
) );
106 PSDRV_CreateColor(dev
, &bkgnd
, RGB(info
->bmiColors
[1].rgbRed
,
107 info
->bmiColors
[1].rgbGreen
,
108 info
->bmiColors
[1].rgbBlue
) );
110 PSDRV_WriteGSave(dev
);
111 PSDRV_WriteNewPath(dev
);
112 PSDRV_WriteRectangle(dev
, xDst
, yDst
, widthDst
, heightDst
);
113 PSDRV_WriteSetColor(dev
, &bkgnd
);
114 PSDRV_WriteFill(dev
);
115 PSDRV_WriteGRestore(dev
);
117 PSDRV_WriteSetColor(dev
, &foregnd
);
118 PSDRV_WriteImage(dev
, 1, xDst
, yDst
, widthDst
, heightDst
,
119 widthSrc
, heightSrc
, TRUE
, info
->bmiHeader
.biHeight
< 0);
124 static inline DWORD
max_rle_size(DWORD size
)
126 return size
+ (size
+ 127) / 128 + 1;
129 static inline DWORD
max_ascii85_size(DWORD size
)
131 return (size
+ 3) / 4 * 5;
134 static void free_heap_bits( struct gdi_image_bits
*bits
)
136 HeapFree( GetProcessHeap(), 0, bits
->ptr
);
139 /***************************************************************************
140 * PSDRV_WriteImageBits
142 static void PSDRV_WriteImageBits( PHYSDEV dev
, const BITMAPINFO
*info
, INT xDst
, INT yDst
,
143 INT widthDst
, INT heightDst
, INT widthSrc
, INT heightSrc
,
144 void *bits
, DWORD size
)
147 DWORD rle_len
, ascii85_len
;
149 if (info
->bmiHeader
.biBitCount
== 1)
150 /* Use imagemask rather than image */
151 PSDRV_WriteImageMaskHeader(dev
, info
, xDst
, yDst
, widthDst
, heightDst
,
152 widthSrc
, heightSrc
);
154 PSDRV_WriteImageHeader(dev
, info
, xDst
, yDst
, widthDst
, heightDst
,
155 widthSrc
, heightSrc
);
157 rle
= HeapAlloc(GetProcessHeap(), 0, max_rle_size(size
));
158 rle_len
= RLE_encode(bits
, size
, rle
);
159 ascii85
= HeapAlloc(GetProcessHeap(), 0, max_ascii85_size(rle_len
));
160 ascii85_len
= ASCII85_encode(rle
, rle_len
, ascii85
);
161 HeapFree(GetProcessHeap(), 0, rle
);
162 PSDRV_WriteData(dev
, ascii85
, ascii85_len
);
163 PSDRV_WriteSpool(dev
, "~>\n", 3);
164 HeapFree(GetProcessHeap(), 0, ascii85
);
167 /***********************************************************************
170 DWORD
PSDRV_PutImage( PHYSDEV dev
, HRGN clip
, BITMAPINFO
*info
,
171 const struct gdi_image_bits
*bits
, struct bitblt_coords
*src
,
172 struct bitblt_coords
*dst
, DWORD rop
)
174 int src_stride
, dst_stride
, size
, x
, y
, width
, height
, bit_offset
;
175 int dst_x
, dst_y
, dst_width
, dst_height
;
176 unsigned char *src_ptr
, *dst_ptr
;
177 struct gdi_image_bits dst_bits
;
179 if (info
->bmiHeader
.biPlanes
!= 1) goto update_format
;
180 if (info
->bmiHeader
.biCompression
!= BI_RGB
) goto update_format
;
181 if (info
->bmiHeader
.biBitCount
== 16 || info
->bmiHeader
.biBitCount
== 32) goto update_format
;
182 if (!bits
) return ERROR_SUCCESS
; /* just querying the format */
184 TRACE( "bpp %u %s -> %s\n", info
->bmiHeader
.biBitCount
, wine_dbgstr_rect(&src
->visrect
),
185 wine_dbgstr_rect(&dst
->visrect
) );
187 width
= src
->visrect
.right
- src
->visrect
.left
;
188 height
= src
->visrect
.bottom
- src
->visrect
.top
;
189 src_stride
= get_dib_width_bytes( info
->bmiHeader
.biWidth
, info
->bmiHeader
.biBitCount
);
190 dst_stride
= (width
* info
->bmiHeader
.biBitCount
+ 7) / 8;
193 if (info
->bmiHeader
.biHeight
> 0)
194 src_ptr
+= (info
->bmiHeader
.biHeight
- src
->visrect
.bottom
) * src_stride
;
196 src_ptr
+= src
->visrect
.top
* src_stride
;
197 bit_offset
= src
->visrect
.left
* info
->bmiHeader
.biBitCount
;
198 src_ptr
+= bit_offset
/ 8;
200 if (bit_offset
) FIXME( "pos %s not supported\n", wine_dbgstr_rect(&src
->visrect
) );
201 size
= height
* dst_stride
;
203 if (src_stride
!= dst_stride
|| (info
->bmiHeader
.biBitCount
== 24 && !bits
->is_copy
))
205 if (!(dst_bits
.ptr
= HeapAlloc( GetProcessHeap(), 0, size
))) return ERROR_OUTOFMEMORY
;
206 dst_bits
.is_copy
= TRUE
;
207 dst_bits
.free
= free_heap_bits
;
211 dst_bits
.ptr
= src_ptr
;
212 dst_bits
.is_copy
= bits
->is_copy
;
213 dst_bits
.free
= NULL
;
215 dst_ptr
= dst_bits
.ptr
;
217 switch (info
->bmiHeader
.biBitCount
)
222 if (src_stride
!= dst_stride
)
223 for (y
= 0; y
< height
; y
++, src_ptr
+= src_stride
, dst_ptr
+= dst_stride
)
224 memcpy( dst_ptr
, src_ptr
, dst_stride
);
227 if (dst_ptr
!= src_ptr
)
228 for (y
= 0; y
< height
; y
++, src_ptr
+= src_stride
, dst_ptr
+= dst_stride
)
229 for (x
= 0; x
< width
; x
++)
231 dst_ptr
[x
* 3] = src_ptr
[x
* 3 + 2];
232 dst_ptr
[x
* 3 + 1] = src_ptr
[x
* 3 + 1];
233 dst_ptr
[x
* 3 + 2] = src_ptr
[x
* 3];
235 else /* swap R and B in place */
236 for (y
= 0; y
< height
; y
++, src_ptr
+= src_stride
, dst_ptr
+= dst_stride
)
237 for (x
= 0; x
< width
; x
++)
239 unsigned char tmp
= dst_ptr
[x
* 3];
240 dst_ptr
[x
* 3] = dst_ptr
[x
* 3 + 2];
241 dst_ptr
[x
* 3 + 2] = tmp
;
246 dst_x
= dst
->visrect
.left
;
247 dst_y
= dst
->visrect
.top
,
248 dst_width
= dst
->visrect
.right
- dst
->visrect
.left
;
249 dst_height
= dst
->visrect
.bottom
- dst
->visrect
.top
;
250 if (src
->width
* dst
->width
< 0)
253 dst_width
= -dst_width
;
255 if (src
->height
* dst
->height
< 0)
258 dst_height
= -dst_height
;
262 PSDRV_WriteGSave(dev
);
263 if (clip
) PSDRV_AddClip( dev
, clip
);
264 PSDRV_WriteImageBits( dev
, info
, dst_x
, dst_y
, dst_width
, dst_height
,
265 width
, height
, dst_bits
.ptr
, size
);
266 PSDRV_WriteGRestore(dev
);
267 PSDRV_ResetClip(dev
);
268 if (dst_bits
.free
) dst_bits
.free( &dst_bits
);
269 return ERROR_SUCCESS
;
272 info
->bmiHeader
.biPlanes
= 1;
273 if (info
->bmiHeader
.biBitCount
> 8) info
->bmiHeader
.biBitCount
= 24;
274 info
->bmiHeader
.biCompression
= BI_RGB
;
275 return ERROR_BAD_FORMAT
;