bitmap.c 12.2 KB
Newer Older
1 2 3 4 5
/*
 *	PostScript driver bitmap functions
 *
 * Copyright 1998  Huw D M Davies
 *
6 7 8 9 10 11 12 13 14 15 16 17
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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
19 20
 */

21
#include <assert.h>
22
#include <stdlib.h>
23

24
#include "psdrv.h"
25
#include "winbase.h"
26
#include "wine/debug.h"
27

28
WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
29

30

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 )
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
{
    int words;

    switch(depth)
    {
    case 1:  words = (width + 31) / 32; break;
    case 4:  words = (width + 7) / 8; break;
    case 8:  words = (width + 3) / 4; break;
    case 15:
    case 16: words = (width + 1) / 2; break;
    case 24: words = (width * 3 + 3)/4; break;
    default:
        WARN("(%d): Unsupported depth\n", depth );
        /* fall through */
    case 32: words = width; break;
    }
    return 4 * words;
}

/* get the bitmap info from either an INFOHEADER or COREHEADER bitmap */
static BOOL get_bitmap_info( const void *ptr, LONG *width, LONG *height, WORD *bpp, WORD *compr )
{
    const BITMAPINFOHEADER *header = ptr;

    switch(header->biSize)
    {
    case sizeof(BITMAPCOREHEADER):
        {
61
            const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)header;
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
            *width  = core->bcWidth;
            *height = core->bcHeight;
            *bpp    = core->bcBitCount;
            *compr  = 0;
        }
        return TRUE;
    case sizeof(BITMAPINFOHEADER):
    case sizeof(BITMAPV4HEADER):
    case sizeof(BITMAPV5HEADER):
        /* V4 and V5 structures are a superset of the INFOHEADER structure */
        *width  = header->biWidth;
        *height = header->biHeight;
        *bpp    = header->biBitCount;
        *compr  = header->biCompression;
        return TRUE;
    default:
78
        ERR("(%d): unknown/wrong size for header\n", header->biSize );
79 80 81 82 83
        return FALSE;
    }
}


84 85 86 87 88 89 90 91 92
/***************************************************************************
 *                PSDRV_WriteImageHeader
 *
 * Helper for PSDRV_StretchDIBits
 *
 * BUGS
 *  Uses level 2 PostScript
 */

93
static BOOL PSDRV_WriteImageHeader(PSDRV_PDEVICE *physDev, const BITMAPINFO *info, INT xDst,
94 95 96 97 98 99 100 101
				   INT yDst, INT widthDst, INT heightDst,
				   INT widthSrc, INT heightSrc)
{
    COLORREF map[256];
    int i;

    switch(info->bmiHeader.biBitCount) {
    case 8:
102
        PSDRV_WriteIndexColorSpaceBegin(physDev, 255);
103 104 105 106 107
	for(i = 0; i < 256; i++) {
	    map[i] =  info->bmiColors[i].rgbRed |
	      info->bmiColors[i].rgbGreen << 8 |
	      info->bmiColors[i].rgbBlue << 16;
	}
108 109
	PSDRV_WriteRGB(physDev, map, 256);
	PSDRV_WriteIndexColorSpaceEnd(physDev);
110 111 112
	break;

    case 4:
113
        PSDRV_WriteIndexColorSpaceBegin(physDev, 15);
114 115 116 117 118
	for(i = 0; i < 16; i++) {
	    map[i] =  info->bmiColors[i].rgbRed |
	      info->bmiColors[i].rgbGreen << 8 |
	      info->bmiColors[i].rgbBlue << 16;
	}
119 120
	PSDRV_WriteRGB(physDev, map, 16);
	PSDRV_WriteIndexColorSpaceEnd(physDev);
121 122 123
	break;

    case 1:
124
        PSDRV_WriteIndexColorSpaceBegin(physDev, 1);
125 126 127 128 129
	for(i = 0; i < 2; i++) {
	    map[i] =  info->bmiColors[i].rgbRed |
	      info->bmiColors[i].rgbGreen << 8 |
	      info->bmiColors[i].rgbBlue << 16;
	}
130 131
	PSDRV_WriteRGB(physDev, map, 2);
	PSDRV_WriteIndexColorSpaceEnd(physDev);
132 133 134 135 136 137 138 139 140 141
	break;

    case 15:
    case 16:
    case 24:
    case 32:
      {
	PSCOLOR pscol;
	pscol.type = PSCOLOR_RGB;
	pscol.value.rgb.r = pscol.value.rgb.g = pscol.value.rgb.b = 0.0;
142
        PSDRV_WriteSetColor(physDev, &pscol);
143 144 145 146
        break;
      }

    default:
147
        FIXME("Not implemented yet\n");
148 149 150
	return FALSE;
    }

151 152
    PSDRV_WriteImage(physDev, info->bmiHeader.biBitCount, xDst, yDst,
		     widthDst, heightDst, widthSrc, heightSrc, FALSE);
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
    return TRUE;
}


/***************************************************************************
 *                PSDRV_WriteImageMaskHeader
 *
 * Helper for PSDRV_StretchDIBits
 *
 * We use the imagemask operator for 1bpp bitmaps since the output
 * takes much less time for the printer to render.
 *
 * BUGS
 *  Uses level 2 PostScript
 */

static BOOL PSDRV_WriteImageMaskHeader(PSDRV_PDEVICE *physDev, const BITMAPINFO *info, INT xDst,
                                       INT yDst, INT widthDst, INT heightDst,
                                       INT widthSrc, INT heightSrc)
{
    COLORREF map[2];
    PSCOLOR bkgnd, foregnd;
    int i;

    assert(info->bmiHeader.biBitCount == 1);

    for(i = 0; i < 2; i++) {
        map[i] =  info->bmiColors[i].rgbRed |
            info->bmiColors[i].rgbGreen << 8 |
            info->bmiColors[i].rgbBlue << 16;
    }

    /* We'll write the mask with -ve polarity so that 
       the foregnd color corresponds to a bit equal to
       0 in the bitmap.
    */
    PSDRV_CreateColor(physDev, &foregnd, map[0]);
    PSDRV_CreateColor(physDev, &bkgnd, map[1]);

    PSDRV_WriteGSave(physDev);
    PSDRV_WriteNewPath(physDev);
    PSDRV_WriteRectangle(physDev, xDst, yDst, widthDst, heightDst);
    PSDRV_WriteSetColor(physDev, &bkgnd);
    PSDRV_WriteFill(physDev);
    PSDRV_WriteGRestore(physDev);

    PSDRV_WriteSetColor(physDev, &foregnd);
200 201
    PSDRV_WriteImage(physDev, 1, xDst, yDst, widthDst, heightDst,
		     widthSrc, heightSrc, TRUE);
202

203 204
    return TRUE;
}
205

206 207 208 209 210 211 212 213 214
static inline DWORD max_rle_size(DWORD size)
{
    return size + (size + 127) / 128 + 1;
}

static inline DWORD max_ascii85_size(DWORD size)
{
    return (size + 3) / 4 * 5;
}
215 216 217 218

/***************************************************************************
 *
 *	PSDRV_StretchDIBits
219 220
 *
 * BUGS
221 222
 *  Doesn't work correctly if xSrc isn't byte aligned - this affects 1 and 4
 *  bit depths.
223
 *  Compression not implemented.
224
 */
225
INT PSDRV_StretchDIBits( PSDRV_PDEVICE *physDev, INT xDst, INT yDst, INT widthDst,
226 227 228
			 INT heightDst, INT xSrc, INT ySrc,
			 INT widthSrc, INT heightSrc, const void *bits,
			 const BITMAPINFO *info, UINT wUsage, DWORD dwRop )
229
{
230 231
    LONG fullSrcWidth, fullSrcHeight;
    INT widthbytes;
232 233
    WORD bpp, compression;
    INT line;
234
    POINT pt[2];
235 236 237
    const BYTE *src_ptr;
    BYTE *dst_ptr, *bitmap, *rle, *ascii85;
    DWORD rle_len, ascii85_len, bitmap_size;
238

239
    TRACE("%p (%d,%d %dx%d) -> (%d,%d %dx%d)\n", physDev->hdc,
240 241
	  xSrc, ySrc, widthSrc, heightSrc, xDst, yDst, widthDst, heightDst);

242
    if (!get_bitmap_info( info, &fullSrcWidth, &fullSrcHeight, &bpp, &compression )) return FALSE;
243

244
    widthbytes = get_dib_width_bytes(fullSrcWidth, bpp);
245

246
    TRACE("full size=%dx%d bpp=%d compression=%d rop=%08x\n", fullSrcWidth,
247
	  fullSrcHeight, bpp, compression, dwRop);
248 249


250
    if(compression != BI_RGB) {
251
        FIXME("Compression not supported\n");
252 253 254
	return FALSE;
    }

255 256 257 258 259 260 261 262 263
    pt[0].x = xDst;
    pt[0].y = yDst;
    pt[1].x = xDst + widthDst;
    pt[1].y = yDst + heightDst;
    LPtoDP( physDev->hdc, pt, 2 );
    xDst = pt[0].x;
    yDst = pt[0].y;
    widthDst = pt[1].x - pt[0].x;
    heightDst = pt[1].y - pt[0].y;
264 265 266 267

    switch(bpp) {

    case 1:
268
        PSDRV_SetClip(physDev);
269
	PSDRV_WriteGSave(physDev);
270 271 272 273

        /* Use imagemask rather than image */
	PSDRV_WriteImageMaskHeader(physDev, info, xDst, yDst, widthDst, heightDst,
                                   widthSrc, heightSrc);
274 275
	src_ptr = bits;
	src_ptr += (ySrc * widthbytes);
276
	if(xSrc & 7)
277
	    FIXME("This won't work...\n");
278 279 280 281
        bitmap_size = heightSrc * ((widthSrc + 7) / 8);
        dst_ptr = bitmap = HeapAlloc(GetProcessHeap(), 0, bitmap_size);
        for(line = 0; line < heightSrc; line++, src_ptr += widthbytes, dst_ptr += ((widthSrc + 7) / 8))
            memcpy(dst_ptr, src_ptr + xSrc / 8, (widthSrc + 7) / 8);
282 283 284
	break;

    case 4:
285
        PSDRV_SetClip(physDev);
286 287
	PSDRV_WriteGSave(physDev);
	PSDRV_WriteImageHeader(physDev, info, xDst, yDst, widthDst, heightDst,
288
			       widthSrc, heightSrc);
289 290
	src_ptr = bits;
	src_ptr += (ySrc * widthbytes);
291
	if(xSrc & 1)
292
	    FIXME("This won't work...\n");
293 294 295 296
        bitmap_size = heightSrc * ((widthSrc + 1) / 2);
        dst_ptr = bitmap = HeapAlloc(GetProcessHeap(), 0, bitmap_size);
        for(line = 0; line < heightSrc; line++, src_ptr += widthbytes, dst_ptr += ((widthSrc + 1) / 2))
	    memcpy(dst_ptr, src_ptr + xSrc/2, (widthSrc+1)/2);
297 298 299
	break;

    case 8:
300
        PSDRV_SetClip(physDev);
301 302
	PSDRV_WriteGSave(physDev);
	PSDRV_WriteImageHeader(physDev, info, xDst, yDst, widthDst, heightDst,
303
			       widthSrc, heightSrc);
304 305 306 307 308 309
	src_ptr = bits;
	src_ptr += (ySrc * widthbytes);
        bitmap_size = heightSrc * widthSrc;
        dst_ptr = bitmap = HeapAlloc(GetProcessHeap(), 0, bitmap_size);
        for(line = 0; line < heightSrc; line++, src_ptr += widthbytes, dst_ptr += widthSrc)
	    memcpy(dst_ptr, src_ptr + xSrc, widthSrc);
310 311 312 313
	break;

    case 15:
    case 16:
314
        PSDRV_SetClip(physDev);
315 316
	PSDRV_WriteGSave(physDev);
	PSDRV_WriteImageHeader(physDev, info, xDst, yDst, widthDst, heightDst,
317 318
			       widthSrc, heightSrc);

319 320 321

        src_ptr = bits;
        src_ptr += (ySrc * widthbytes);
322
        bitmap_size = heightSrc * widthSrc * 3;
323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
        dst_ptr = bitmap = HeapAlloc(GetProcessHeap(), 0, bitmap_size);
        
        for(line = 0; line < heightSrc; line++, src_ptr += widthbytes) {
            const WORD *words = (const WORD *)src_ptr + xSrc;
            int i;
            for(i = 0; i < widthSrc; i++) {
                BYTE r, g, b;

                /* We want 0x0 -- 0x1f to map to 0x0 -- 0xff */
                r = words[i] >> 10 & 0x1f;
                r = r << 3 | r >> 2;
                g = words[i] >> 5 & 0x1f;
                g = g << 3 | g >> 2;
                b = words[i] & 0x1f;
                b = b << 3 | b >> 2;
                dst_ptr[0] = r;
                dst_ptr[1] = g;
                dst_ptr[2] = b;
                dst_ptr += 3;
            }
        }
344 345 346
	break;

    case 24:
347
        PSDRV_SetClip(physDev);
348 349
	PSDRV_WriteGSave(physDev);
	PSDRV_WriteImageHeader(physDev, info, xDst, yDst, widthDst, heightDst,
350 351
			       widthSrc, heightSrc);

352 353 354 355 356 357 358 359 360 361 362 363 364 365
        src_ptr = bits;
        src_ptr += (ySrc * widthbytes);
        bitmap_size = heightSrc * widthSrc * 3;
        dst_ptr = bitmap = HeapAlloc(GetProcessHeap(), 0, bitmap_size);
        for(line = 0; line < heightSrc; line++, src_ptr += widthbytes) {
            const BYTE *byte = src_ptr + xSrc * 3;
            int i;
            for(i = 0; i < widthSrc; i++) {
                dst_ptr[0] = byte[i * 3 + 2];
                dst_ptr[1] = byte[i * 3 + 1];
                dst_ptr[2] = byte[i * 3];
                dst_ptr += 3;
            }
        }
366 367 368
	break;

    case 32:
369
        PSDRV_SetClip(physDev);
370 371
	PSDRV_WriteGSave(physDev);
	PSDRV_WriteImageHeader(physDev, info, xDst, yDst, widthDst, heightDst,
372 373
			       widthSrc, heightSrc);

374 375 376 377 378 379 380 381 382 383 384 385 386 387
        src_ptr = bits;
        src_ptr += (ySrc * widthbytes);
        bitmap_size = heightSrc * widthSrc * 3;
        dst_ptr = bitmap = HeapAlloc(GetProcessHeap(), 0, bitmap_size);
        for(line = 0; line < heightSrc; line++, src_ptr += widthbytes) {
            const BYTE *byte = src_ptr + xSrc * 4;
            int i;
            for(i = 0; i < widthSrc; i++) {
                dst_ptr[0] = byte[i * 4 + 2];
                dst_ptr[1] = byte[i * 4 + 1];
                dst_ptr[2] = byte[i * 4];
                dst_ptr += 3;
            }
        }
388 389 390
	break;

    default:
391
        FIXME("Unsupported depth\n");
392 393 394
	return FALSE;

    }
395 396 397 398 399 400 401 402 403 404

    rle = HeapAlloc(GetProcessHeap(), 0, max_rle_size(bitmap_size));
    rle_len = RLE_encode(bitmap, bitmap_size, rle);
    HeapFree(GetProcessHeap(), 0, bitmap);
    ascii85 = HeapAlloc(GetProcessHeap(), 0, max_ascii85_size(rle_len));
    ascii85_len = ASCII85_encode(rle, rle_len, ascii85);
    HeapFree(GetProcessHeap(), 0, rle);
    PSDRV_WriteData(physDev, ascii85, ascii85_len);
    HeapFree(GetProcessHeap(), 0, ascii85);
    PSDRV_WriteSpool(physDev, "~>\n", 3);
405
    PSDRV_WriteGRestore(physDev);
406
    PSDRV_ResetClip(physDev);
407
    return abs(heightSrc);
408
}