Ignore:
Timestamp:
Feb 27, 2004, 7:56:12 PM (21 years ago)
Author:
sandervl
Message:

SetDIBitsToDevice & StretchDIBits fixes + cleanup

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/gdi32/blit.cpp

    r10373 r10486  
    1 /* $Id: blit.cpp,v 1.46 2004-01-11 11:42:08 sandervl Exp $ */
     1/* $Id: blit.cpp,v 1.47 2004-02-27 18:56:12 sandervl Exp $ */
    22
    33/*
     
    110110                               const BITMAPINFO *info, UINT coloruse)
    111111{
    112     INT result, imgsize, palsize, height, width;
     112    INT result, imgsize, palsize;
    113113    char *ptr;
    114114    ULONG compression = 0, bmpsize;
     
    118118    dprintf(("GDI32: SetDIBitsToDevice hdc:%X xDest:%d yDest:%d, cx:%d, cy:%d, xSrc:%d, ySrc:%d, startscan:%d, lines:%d \nGDI32: bits 0x%X, info 0x%X, coloruse %d",
    119119              hdc, xDest, yDest, cx, cy, xSrc, ySrc, startscan, lines, (LPVOID) bits, (PBITMAPINFO)info, coloruse));
    120 
    121     SetLastError(ERROR_SUCCESS);
    122     if(info == NULL) {
    123         goto invalid_parameter;
    124     }
    125     height = info->bmiHeader.biHeight;
    126     width  = info->bmiHeader.biWidth;
    127 
    128     if (height < 0) height = -height;
    129     if (!lines || (startscan >= height)) {
    130         goto invalid_parameter;
    131     }
    132     if (startscan + lines > height) lines = height - startscan;
    133 
    134     if (ySrc < startscan) ySrc = startscan;
    135     else if (ySrc >= startscan + lines) goto invalid_parameter;
    136 
    137     if (xSrc >= width) goto invalid_parameter;
    138 
    139     if (ySrc + cy >= startscan + lines) cy = startscan + lines - ySrc;
    140 
    141     if (xSrc + cx >= width) cx = width - xSrc;
    142 
    143     if (!cx || !cy) goto invalid_parameter;
    144120
    145121    //SvL: RP7's bitmap size is not correct; fix it here or else
     
    219195    ((BITMAPINFO *)info)->bmiHeader.biSizeImage = bmpsize;
    220196    return result;
    221 
    222 invalid_parameter:
    223     SetLastError(ERROR_INVALID_PARAMETER);
    224     return 0;
    225197}
    226198//******************************************************************************
     
    232204{
    233205    static BOOL fMatrox32BppBug = FALSE;
    234     INT rc = 0;
     206    INT   height, width;
     207    INT   rc = 0;
    235208    char *newBits = NULL;
    236209
     
    239212    }
    240213
     214    SetLastError(ERROR_SUCCESS);
     215    if(info == NULL) {
     216        goto invalid_parameter;
     217    }
     218    height = info->bmiHeader.biHeight;
     219    width  = info->bmiHeader.biWidth;
     220
     221    if (height < 0) height = -height;
     222    if (!lines || (startscan >= height)) {
     223        goto invalid_parameter;
     224    }
     225    if (startscan + lines > height) lines = height - startscan;
     226
     227    if (ySrc < startscan) ySrc = startscan;
     228    else if (ySrc >= startscan + lines) goto invalid_parameter;
     229
     230    if (xSrc >= width) goto invalid_parameter;
     231
     232    if (ySrc + cy >= startscan + lines) cy = startscan + lines - ySrc;
     233
     234    if (xSrc + cx >= width) cx = width - xSrc;
     235
     236    if (!cx || !cy) goto invalid_parameter;
     237
    241238    //If upside down, reverse scanlines and call SetDIBitsToDevice again
    242 //    if(info->bmiHeader.biHeight < 0 && info->bmiHeader.biBitCount != 8 && info->bmiHeader.biCompression == 0) {
    243239    if(info->bmiHeader.biHeight < 0 && (info->bmiHeader.biCompression == BI_RGB ||
    244240       info->bmiHeader.biCompression == BI_BITFIELDS))
     
    246242        // upside down
    247243        INT rc = -1;
    248         long lLineByte = DIB_GetDIBWidthBytes(info->bmiHeader.biWidth, info->bmiHeader.biBitCount);
    249         long lHeight   = -info->bmiHeader.biHeight;
     244
     245        UINT lLineByte = DIB_GetDIBWidthBytes(info->bmiHeader.biWidth, info->bmiHeader.biBitCount);
     246        UINT lLineCopy, xOffset;
     247        UINT lHeight   = -info->bmiHeader.biHeight;
     248
     249        xOffset   = (xSrc*info->bmiHeader.biBitCount)/8;
     250        xSrc      = (xSrc*info->bmiHeader.biBitCount)%8;
     251        ySrc     -= startscan;
     252
     253        // Calculate destination line width
     254        lLineCopy = cx;
     255        if(xSrc + cx > info->bmiHeader.biWidth)
     256            lLineCopy = info->bmiHeader.biWidth - xSrc;
     257
     258        // Plus xSrc in case rounding makes us start at a smaller x coordinate
     259        lLineCopy = DIB_GetDIBWidthBytes(lLineCopy+xSrc, info->bmiHeader.biBitCount);
    250260
    251261        //TODO: doesn't work if memory is readonly!!
     
    254264        char *newBits = (char *)malloc( lLineByte * lHeight );
    255265        if(newBits) {
    256             unsigned char *pbSrc = (unsigned char *)bits + xSrc + lLineByte * (ySrc + lHeight - 1);
    257             unsigned char *pbDst = (unsigned char *)newBits;
    258             for(int y = 0; y < lHeight; y++) {
    259                 memcpy( pbDst, pbSrc, lLineByte );
    260                 pbDst += lLineByte;
    261                 pbSrc -= lLineByte;
     266            unsigned char *pbSrc = (unsigned char *)bits + xOffset + lLineByte * ySrc;
     267            unsigned char *pbDst = (unsigned char *)newBits + lLineByte * (lHeight - 1);
     268            for(int y = 0; y < min(cy, min(lHeight, lines)); y++) {
     269                memcpy( pbDst, pbSrc, lLineCopy);
     270                pbSrc += lLineByte;
     271                pbDst -= lLineByte;
    262272            }
    263273            //We only convert the necessary data so xSrc & ySrc are now 0
    264             rc = SetDIBitsToDevice( hdc, xDest, yDest, cx, cy, 0, 0, startscan, lines, (void *)newBits, info, coloruse );
     274            //xSrc can be non-zero for < 8bpp bitmap where it starts at the wrong boundary
     275            rc = SetDIBitsToDevice( hdc, xDest, yDest, cx, cy, xSrc, 0, startscan, lines, (void *)newBits, info, coloruse );
    265276            free( newBits );
    266277        }
     
    272283        return rc;
    273284    }
    274 
    275     //We must convert 32 bpp bitmap data to 24 bpp on systems with the Matrox
    276     //display driver. (GpiDrawBits for 32 bpp fails with insufficient memory error)
    277     if(info->bmiHeader.biBitCount == 32 && fMatrox32BppBug)
    278     {
    279         BITMAPINFO newInfo;
    280         newInfo.bmiHeader = info->bmiHeader;
    281 
    282         long lLineWidth;
    283         long lHeight    = (newInfo.bmiHeader.biHeight > 0) ? newInfo.bmiHeader.biHeight : -newInfo.bmiHeader.biHeight;
    284         long lWidth     = newInfo.bmiHeader.biWidth;
    285 
    286         newInfo.bmiHeader.biBitCount  = 24;
    287         newInfo.bmiHeader.biSizeImage = CalcBitmapSize(24, newInfo.bmiHeader.biWidth,
    288                                                        newInfo.bmiHeader.biHeight);
    289 
    290         lLineWidth = newInfo.bmiHeader.biSizeImage / lHeight;
    291 
    292         //convert 32 bits bitmap data to 24 bits
    293         newBits = (char *)malloc(newInfo.bmiHeader.biSizeImage+16); //extra room needed for copying (too much)
    294         if(!newBits) {
    295             DebugInt3();
    296             return -1;
    297         }
    298         unsigned char *pbSrc = (unsigned char *)bits;
    299         unsigned char *pbDst = (unsigned char *)newBits;
    300         //not very efficient
    301         for(int i = 0; i < lHeight; i++) {
    302             for(int j=0;j<lWidth;j++) {
    303                 *(DWORD *)pbDst = *(DWORD *)pbSrc;
    304                 pbSrc += 4;
    305                 pbDst += 3;
    306             }
    307             //24 bpp scanline must be aligned at 4 byte boundary
    308             pbDst += (lLineWidth - 3*lWidth);
    309         }
    310         rc = SetDIBitsToDevice_( hdc, xDest, yDest, cx, cy, xSrc, ySrc, startscan, lines, newBits, &newInfo, coloruse );
    311         free(newBits);
    312         return rc;
    313     }
    314285    rc = SetDIBitsToDevice_( hdc, xDest, yDest, cx, cy, xSrc, ySrc, startscan, lines, bits, info, coloruse );
    315286
    316     if(rc == -1 && info->bmiHeader.biBitCount == 32 && !fMatrox32BppBug)
    317     {
    318         //The Matrox driver seems to have some difficulty blitting 32bpp
    319         //data. (out of memory error) The same operation works fine with SDD.
    320         fMatrox32BppBug = TRUE;
    321         return SetDIBitsToDevice(hdc, xDest, yDest, cx,
    322                                  cy, xSrc, ySrc,
    323                                  startscan, lines, bits,
    324                                  info, coloruse);
    325     }
    326287    return rc;
     288
     289invalid_parameter:
     290    SetLastError(ERROR_INVALID_PARAMETER);
     291    return 0;
    327292}
    328293//******************************************************************************
     
    389354        dprintf(("WARNING: StretchDIBits does NOT work correctly for 1 bpp bitmaps!!"));
    390355    }
    391 
     356#if 0
     357    // SvL: I'm not sure what this was supposed to fix, but it breaks one
     358    //      application here
     359    //      SetDIBitsToDevice works with palette indexes, so this should not
     360    //      be necessary (anymore)
    392361    if(wUsage == DIB_PAL_COLORS && info->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
    393362    {
     
    396365
    397366        int i;
     367        UINT biClrUsed;
    398368        USHORT *pColorIndex = (USHORT *)info->bmiColors;
    399         RGBQUAD *pColors = (RGBQUAD *) alloca(info->bmiHeader.biClrUsed *
    400                          sizeof(RGBQUAD));
    401         BITMAPINFO *infoLoc = (BITMAPINFO *) alloca(sizeof(BITMAPINFO) +
    402                              info->bmiHeader.biClrUsed * sizeof(RGBQUAD));
     369        RGBQUAD *pColors;
     370        BITMAPINFO *infoLoc;
     371
     372        biClrUsed = (info->bmiHeader.biClrUsed) ? info->bmiHeader.biClrUsed : (1<<info->bmiHeader.biBitCount);
     373
     374        pColors = (RGBQUAD *) alloca(biClrUsed * sizeof(RGBQUAD));
     375        infoLoc = (BITMAPINFO *) alloca(sizeof(BITMAPINFO) + biClrUsed * sizeof(RGBQUAD));
    403376
    404377        memcpy(infoLoc, info, sizeof(BITMAPINFO));
    405378
    406         if(GetDIBColorTable(hdc, 0, info->bmiHeader.biClrUsed, pColors) == 0) {
    407                     dprintf(("ERROR: StretchDIBits: GetDIBColorTable failed!!"));
    408                 return FALSE;
    409         }
    410         for(i=0;i<info->bmiHeader.biClrUsed;i++, pColorIndex++)
     379        if(GetDIBColorTable(hdc, 0, biClrUsed, pColors) == 0)
     380        {
     381            dprintf(("ERROR: StretchDIBits: GetDIBColorTable failed!!"));
     382            return FALSE;
     383        }
     384        for(i=0;i<biClrUsed;i++, pColorIndex++)
    411385        {
    412                 infoLoc->bmiColors[i] = pColors[*pColorIndex];
     386            infoLoc->bmiColors[i] = pColors[*pColorIndex];
    413387        }
    414388
     
    429403        return rc;
    430404    }
    431 
     405#endif
    432406    switch(info->bmiHeader.biBitCount) {
    433407    case 15:
Note: See TracChangeset for help on using the changeset viewer.