ddraw/tests: Add another invalid arguments test for surface QI.
[wine.git] / dlls / wineps.drv / bitmap.c
blobc4d0a965ae83999f6e6d1c0ba323fc889309523f
1 /*
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
21 #include <assert.h>
22 #include <stdlib.h>
24 #include "psdrv.h"
25 #include "winbase.h"
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
43 * BUGS
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)
53 case 1:
54 case 4:
55 case 8:
56 PSDRV_WriteIndexColorSpaceBegin(dev, (1 << info->bmiHeader.biBitCount) - 1);
57 PSDRV_WriteRGBQUAD(dev, info->bmiColors, 1 << info->bmiHeader.biBitCount);
58 PSDRV_WriteIndexColorSpaceEnd(dev);
59 break;
61 case 16:
62 case 24:
63 case 32:
65 PSCOLOR pscol;
66 if (grayscale)
68 pscol.type = PSCOLOR_GRAY;
69 pscol.value.gray.i = 0;
71 else
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);
77 break;
81 PSDRV_WriteImage(dev, info->bmiHeader.biBitCount, grayscale, xDst, yDst,
82 widthDst, heightDst, widthSrc, heightSrc, FALSE, info->bmiHeader.biHeight < 0);
83 return TRUE;
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.
95 * BUGS
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
110 0 in the bitmap.
112 if (!info->bmiHeader.biClrUsed)
114 PSDRV_CreateColor( dev, &foregnd, GetTextColor( dev->hdc ) );
115 bkgnd = physDev->bkColor;
117 else
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);
138 return TRUE;
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 )
163 BYTE *rle, *ascii85;
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);
170 else
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 /***********************************************************************
185 * PSDRV_PutImage
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;
212 src_ptr = bits->ptr;
213 if (info->bmiHeader.biHeight > 0)
214 src_ptr += (info->bmiHeader.biHeight - src->visrect.bottom) * src_stride;
215 else
216 src_ptr += src->visrect.top * src_stride;
217 bit_offset = src->visrect.left * info->bmiHeader.biBitCount;
218 src_ptr += bit_offset / 8;
219 bit_offset &= 7;
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;
229 else
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)
239 case 1:
240 case 4:
241 case 8:
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 );
245 break;
246 case 24:
247 if (grayscale)
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;
270 break;
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)
279 dst_x += dst_width;
280 dst_width = -dst_width;
282 if (src->height * dst->height < 0)
284 dst_y += dst_height;
285 dst_height = -dst_height;
288 PSDRV_SetClip(dev);
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;
298 update_format:
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;