From: Bernd Herd codeberg@herdsoft.com
Makes sure SANE transistions to the next frame on some backends. Extends or shrinks DIB to the number of lines actually transfered by the SANE data source. --- dlls/sane.ds/ds_image.c | 130 +++++++++++++++++++++++++++++++++------- 1 file changed, 107 insertions(+), 23 deletions(-)
diff --git a/dlls/sane.ds/ds_image.c b/dlls/sane.ds/ds_image.c index a1e7d91553b..120c0b52203 100644 --- a/dlls/sane.ds/ds_image.c +++ b/dlls/sane.ds/ds_image.c @@ -348,7 +348,9 @@ TW_UINT16 SANE_ImageNativeXferGet (pTW_IDENTITY pOrigin, RGBTRIPLE *pixels; int color_size = 0; int i, j; + int y=0, eof = 0; BYTE *p; + DWORD tmp, *ptop, *pbot;
TRACE("DG_IMAGE/DAT_IMAGENATIVEXFER/MSG_GET\n");
@@ -394,9 +396,9 @@ TW_UINT16 SANE_ImageNativeXferGet (pTW_IDENTITY pOrigin, }
dib_bytes_per_line = ((activeDS.frame_params.bytes_per_line + 3) / 4) * 4; - dib_bytes = activeDS.frame_params.lines * dib_bytes_per_line; + dib_bytes = (activeDS.frame_params.lines+1) * dib_bytes_per_line;
- hDIB = GlobalAlloc(GMEM_ZEROINIT, dib_bytes + sizeof(*header) + color_size); + hDIB = GlobalAlloc(GMEM_MOVEABLE, dib_bytes + sizeof(*header) + color_size); if (hDIB) header = GlobalLock(hDIB);
@@ -410,9 +412,10 @@ TW_UINT16 SANE_ImageNativeXferGet (pTW_IDENTITY pOrigin, return TWRC_FAILURE; }
+ memset(header, 0, sizeof(BITMAPINFOHEADER)); header->biSize = sizeof (*header); header->biWidth = activeDS.frame_params.pixels_per_line; - header->biHeight = activeDS.frame_params.lines; + header->biHeight = -activeDS.frame_params.lines-1; header->biPlanes = 1; header->biCompression = BI_RGB; switch (activeDS.frame_params.format) @@ -426,7 +429,6 @@ TW_UINT16 SANE_ImageNativeXferGet (pTW_IDENTITY pOrigin, case FMT_OTHER: break; } - header->biSizeImage = dib_bytes; header->biXPelsPerMeter = 0; header->biYPelsPerMeter = 0; header->biClrUsed = 0; @@ -442,53 +444,135 @@ TW_UINT16 SANE_ImageNativeXferGet (pTW_IDENTITY pOrigin, { /* Sane uses 1 to represent minimum intensity (black) and 0 for maximum (white) */ colors[0].rgbBlue = colors[0].rgbRed = colors[0].rgbGreen = 255; + colors[0].rgbReserved = 0; colors[1].rgbBlue = colors[1].rgbRed = colors[1].rgbGreen = 0; + colors[1].rgbReserved = 0; } else for (i = 0; i < (color_size / sizeof(*colors)); i++) + { colors[i].rgbBlue = colors[i].rgbRed = colors[i].rgbGreen = i; + colors[i].rgbReserved = 0; + } }
- - /* Sane returns data in top down order. Acrobat does best with - a bottom up DIB being returned. */ - line = p + (activeDS.frame_params.lines - 1) * dib_bytes_per_line; - for (i = activeDS.frame_params.lines - 1; i >= 0; i--) + do { int retlen; - struct read_data_params params = { line, activeDS.frame_params.bytes_per_line, &retlen }; + struct read_data_params params = { NULL, activeDS.frame_params.bytes_per_line, &retlen }; + + if (y >= -header->biHeight) + { + TRACE("Data source transfers more lines than expected. Extend DIB to %ld lines\n", (-header->biHeight)+1000); + GlobalUnlock(hDIB); + + dib_bytes += 1000 * dib_bytes_per_line; + hDIB = GlobalReAlloc(hDIB, dib_bytes + sizeof(*header) + color_size, GMEM_MOVEABLE); + + if (!hDIB) + { + SANE_Cancel(); + activeDS.twCC = TWCC_LOWMEMORY; + activeDS.currentState = 6; + return TWRC_FAILURE; + } + + header = (BITMAPINFOHEADER *) GlobalLock(hDIB); + header->biHeight -= 1000; + + p = ((BYTE *) header) + header->biSize + color_size; + }
activeDS.progressWnd = ScanningDialogBox(activeDS.progressWnd, - ((activeDS.frame_params.lines - 1 - i) * 100) - / - (activeDS.frame_params.lines - 1)); + MulDiv(y, 100, activeDS.frame_params.lines)); + + params.buffer = + line = p + y * dib_bytes_per_line; + + if (activeDS.frame_params.bytes_per_line & 3) + { + /* Set padding-bytes at the end of the line buffer to 0 */ + memset(line+dib_bytes_per_line-4, 0, 4); + }
twRC = SANE_CALL( read_data, ¶ms ); if (twRC != TWCC_SUCCESS) break; - if (retlen < activeDS.frame_params.bytes_per_line) break; - /* TWAIN: for 24 bit color DIBs, the pixels are stored in BGR order */ - if (activeDS.frame_params.format == FMT_RGB && activeDS.frame_params.depth == 8) + if (retlen < activeDS.frame_params.bytes_per_line) + { /* EOF reached */ + eof = 1; + } + else { - pixels = (RGBTRIPLE *) line; - for (j = 0; j < activeDS.frame_params.pixels_per_line; ++j) + y++; + /* TWAIN: for 24 bit color DIBs, the pixels are stored in BGR order */ + if (activeDS.frame_params.format == FMT_RGB && activeDS.frame_params.depth == 8) { - color_buffer = pixels[j].rgbtRed; - pixels[j].rgbtRed = pixels[j].rgbtBlue; - pixels[j].rgbtBlue = color_buffer; + pixels = (RGBTRIPLE *) line; + for (j = 0; j < activeDS.frame_params.pixels_per_line; ++j) + { + color_buffer = pixels[j].rgbtRed; + pixels[j].rgbtRed = pixels[j].rgbtBlue; + pixels[j].rgbtBlue = color_buffer; + } } } - line -= dib_bytes_per_line; } + while (!eof);
if (twRC != TWCC_SUCCESS) { - WARN("sane_read: %u, reading line %d\n", twRC, i); + WARN("sane_read: %u, reading line %d\n", twRC, y); SANE_Cancel(); activeDS.twCC = TWCC_OPERATIONERROR; GlobalFree(hDIB); return TWRC_FAILURE; }
+ if (y < -header->biHeight && y>0) + { + /* Data source sent less data than allocated. + * This is common when using an ADF. + * Reduce the DIB to the size that has actually been transfered. */ + GlobalUnlock(hDIB); + + dib_bytes += y * dib_bytes_per_line; + hDIB = GlobalReAlloc(hDIB, dib_bytes + sizeof(*header) + color_size, GMEM_MOVEABLE); + + if (!hDIB) + { + SANE_Cancel(); + activeDS.twCC = TWCC_LOWMEMORY; + activeDS.currentState = 6; + return TWRC_FAILURE; + } + + header = (BITMAPINFOHEADER *) GlobalLock(hDIB); + header->biHeight = -y; + + p = ((BYTE *) header) + header->biSize + color_size; + } + + /* Sane returns data in top down order. Acrobat does best with + a bottom up DIB being returned. Flip image */ + header->biHeight *= -1; + header->biSizeImage = dib_bytes; + for (y = 0; y<header->biHeight / 2; y++) + { + ptop = (DWORD *) (p + dib_bytes_per_line * y ); + pbot = (DWORD *) (p + dib_bytes_per_line * (header->biHeight-y-1) ); + + for (i = dib_bytes_per_line/4; --i>=0; ) + { + tmp = *ptop; + *ptop = *pbot; + *pbot = tmp; + ptop++; + pbot++; + } + } + + activeDS.progressWnd = ScanningDialogBox(activeDS.progressWnd, -1); + GlobalUnlock(hDIB);
*pHandle = (TW_HANDLE)hDIB;