wine/dlls/sane.ds/ds_image.c
Alexandre Julliard 1fe2a12bfb sane.ds: Build with msvcrt.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
2021-10-28 12:50:22 +02:00

450 lines
15 KiB
C

/*
* Copyright 2000 Corel Corporation
* Copyright 2006 CodeWeavers, Aric Stewart
*
* 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
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
#include "sane_i.h"
#include "wingdi.h"
#include "winuser.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(twain);
/* DG_IMAGE/DAT_IMAGEINFO/MSG_GET */
TW_UINT16 SANE_ImageInfoGet (pTW_IDENTITY pOrigin,
TW_MEMREF pData)
{
TW_UINT16 twRC = TWRC_SUCCESS;
pTW_IMAGEINFO pImageInfo = (pTW_IMAGEINFO) pData;
int resolution;
TRACE("DG_IMAGE/DAT_IMAGEINFO/MSG_GET\n");
if (activeDS.currentState != 6 && activeDS.currentState != 7)
{
twRC = TWRC_FAILURE;
activeDS.twCC = TWCC_SEQERROR;
}
else
{
if (activeDS.currentState == 6)
{
/* return general image description information about the image about to be transferred */
TRACE("Getting parameters\n");
if (SANE_CALL( get_params, &activeDS.frame_params ))
{
WARN("sane_get_parameters failed\n");
SANE_CALL( cancel_device, NULL );
activeDS.twCC = TWCC_OPERATIONERROR;
return TWRC_FAILURE;
}
}
if (sane_option_get_int("resolution", &resolution) == TWCC_SUCCESS)
pImageInfo->XResolution.Whole = pImageInfo->YResolution.Whole = resolution;
else
pImageInfo->XResolution.Whole = pImageInfo->YResolution.Whole = -1;
pImageInfo->XResolution.Frac = 0;
pImageInfo->YResolution.Frac = 0;
pImageInfo->ImageWidth = activeDS.frame_params.pixels_per_line;
pImageInfo->ImageLength = activeDS.frame_params.lines;
TRACE("Bits per Sample %i\n",activeDS.frame_params.depth);
TRACE("Frame Format %i\n",activeDS.frame_params.format);
switch (activeDS.frame_params.format)
{
case FMT_RGB:
pImageInfo->BitsPerPixel = activeDS.frame_params.depth * 3;
pImageInfo->Compression = TWCP_NONE;
pImageInfo->Planar = TRUE;
pImageInfo->SamplesPerPixel = 3;
pImageInfo->BitsPerSample[0] = activeDS.frame_params.depth;
pImageInfo->BitsPerSample[1] = activeDS.frame_params.depth;
pImageInfo->BitsPerSample[2] = activeDS.frame_params.depth;
pImageInfo->PixelType = TWPT_RGB;
break;
case FMT_GRAY:
pImageInfo->BitsPerPixel = activeDS.frame_params.depth;
pImageInfo->Compression = TWCP_NONE;
pImageInfo->Planar = TRUE;
pImageInfo->SamplesPerPixel = 1;
pImageInfo->BitsPerSample[0] = activeDS.frame_params.depth;
if (activeDS.frame_params.depth == 1)
pImageInfo->PixelType = TWPT_BW;
else
pImageInfo->PixelType = TWPT_GRAY;
break;
case FMT_OTHER:
twRC = TWRC_FAILURE;
activeDS.twCC = TWCC_SEQERROR;
break;
}
}
return twRC;
}
/* DG_IMAGE/DAT_IMAGELAYOUT/MSG_GET */
TW_UINT16 SANE_ImageLayoutGet (pTW_IDENTITY pOrigin,
TW_MEMREF pData)
{
TW_IMAGELAYOUT *img = (TW_IMAGELAYOUT *) pData;
int tlx, tly, brx, bry;
TW_UINT16 rc;
TRACE("DG_IMAGE/DAT_IMAGELAYOUT/MSG_GET\n");
rc = sane_option_get_scan_area( &tlx, &tly, &brx, &bry );
if (rc != TWCC_SUCCESS)
{
activeDS.twCC = rc;
return TWRC_FAILURE;
}
img->Frame.Left = convert_sane_res_to_twain( tlx );
img->Frame.Top = convert_sane_res_to_twain( tly );
img->Frame.Right = convert_sane_res_to_twain( brx );
img->Frame.Bottom = convert_sane_res_to_twain( bry );
img->DocumentNumber = 1;
img->PageNumber = 1;
img->FrameNumber = 1;
activeDS.twCC = TWCC_SUCCESS;
return TWRC_SUCCESS;
}
/* DG_IMAGE/DAT_IMAGELAYOUT/MSG_GETDEFAULT */
TW_UINT16 SANE_ImageLayoutGetDefault (pTW_IDENTITY pOrigin,
TW_MEMREF pData)
{
FIXME ("stub!\n");
return TWRC_FAILURE;
}
/* DG_IMAGE/DAT_IMAGELAYOUT/MSG_RESET */
TW_UINT16 SANE_ImageLayoutReset (pTW_IDENTITY pOrigin,
TW_MEMREF pData)
{
FIXME ("stub!\n");
return TWRC_FAILURE;
}
/* DG_IMAGE/DAT_IMAGELAYOUT/MSG_SET */
TW_UINT16 SANE_ImageLayoutSet (pTW_IDENTITY pOrigin,
TW_MEMREF pData)
{
TW_IMAGELAYOUT *img = (TW_IMAGELAYOUT *) pData;
BOOL changed = FALSE;
TW_UINT16 twrc;
int tlx, tly, brx, bry;
TRACE("DG_IMAGE/DAT_IMAGELAYOUT/MSG_SET\n");
TRACE("Frame: [Left %x.%x|Top %x.%x|Right %x.%x|Bottom %x.%x]\n",
img->Frame.Left.Whole, img->Frame.Left.Frac,
img->Frame.Top.Whole, img->Frame.Top.Frac,
img->Frame.Right.Whole, img->Frame.Right.Frac,
img->Frame.Bottom.Whole, img->Frame.Bottom.Frac);
tlx = img->Frame.Left.Whole * 65536 + img->Frame.Left.Frac;
tly = img->Frame.Top.Whole * 65536 + img->Frame.Top.Frac;
brx = img->Frame.Right.Whole * 65536 + img->Frame.Right.Frac;
bry = img->Frame.Bottom.Whole * 65536 + img->Frame.Bottom.Frac;
twrc = sane_option_set_scan_area( tlx, tly, brx, bry, &changed );
if (twrc != TWRC_SUCCESS)
return (twrc);
activeDS.twCC = TWCC_SUCCESS;
return changed ? TWRC_CHECKSTATUS : TWRC_SUCCESS;
}
/* DG_IMAGE/DAT_IMAGEMEMXFER/MSG_GET */
TW_UINT16 SANE_ImageMemXferGet (pTW_IDENTITY pOrigin,
TW_MEMREF pData)
{
TW_UINT16 twRC = TWRC_SUCCESS;
pTW_IMAGEMEMXFER pImageMemXfer = (pTW_IMAGEMEMXFER) pData;
TRACE ("DG_IMAGE/DAT_IMAGEMEMXFER/MSG_GET\n");
if (activeDS.currentState < 6 || activeDS.currentState > 7)
{
twRC = TWRC_FAILURE;
activeDS.twCC = TWCC_SEQERROR;
}
else
{
struct read_data_params params;
LPBYTE buffer;
int retlen;
int rows;
/* Transfer an image from the source to the application */
if (activeDS.currentState == 6)
{
/* trigger scanning dialog */
activeDS.progressWnd = ScanningDialogBox(NULL,0);
ScanningDialogBox(activeDS.progressWnd,0);
if (SANE_CALL( start_device, NULL ))
{
activeDS.twCC = TWCC_OPERATIONERROR;
return TWRC_FAILURE;
}
if (get_sane_params( &activeDS.frame_params ))
{
WARN("sane_get_parameters failed\n");
SANE_CALL( cancel_device, NULL );
activeDS.twCC = TWCC_OPERATIONERROR;
return TWRC_FAILURE;
}
TRACE("Acquiring image %dx%dx%d bits (format=%d last=%d) from sane...\n"
, activeDS.frame_params.pixels_per_line, activeDS.frame_params.lines,
activeDS.frame_params.depth, activeDS.frame_params.format,
activeDS.frame_params.last_frame);
activeDS.currentState = 7;
}
/* access memory buffer */
if (pImageMemXfer->Memory.Length < activeDS.frame_params.bytes_per_line)
{
SANE_CALL( cancel_device, NULL );
activeDS.twCC = TWCC_BADVALUE;
return TWRC_FAILURE;
}
if (pImageMemXfer->Memory.Flags & TWMF_HANDLE)
{
FIXME("Memory Handle, may not be locked correctly\n");
buffer = LocalLock(pImageMemXfer->Memory.TheMem);
}
else
buffer = pImageMemXfer->Memory.TheMem;
memset(buffer,0,pImageMemXfer->Memory.Length);
/* must fill full lines */
rows = pImageMemXfer->Memory.Length / activeDS.frame_params.bytes_per_line;
params.buffer = buffer;
params.len = activeDS.frame_params.bytes_per_line * rows;
params.retlen = &retlen;
twRC = SANE_CALL( read_data, &params );
if (twRC == TWCC_SUCCESS)
{
pImageMemXfer->Compression = TWCP_NONE;
pImageMemXfer->BytesPerRow = activeDS.frame_params.bytes_per_line;
pImageMemXfer->Columns = activeDS.frame_params.pixels_per_line;
pImageMemXfer->Rows = rows;
pImageMemXfer->XOffset = 0;
pImageMemXfer->YOffset = 0;
pImageMemXfer->BytesWritten = retlen;
ScanningDialogBox(activeDS.progressWnd, retlen);
if (retlen < activeDS.frame_params.bytes_per_line * rows)
{
ScanningDialogBox(activeDS.progressWnd, -1);
TRACE("sane_read: %u / %u\n", retlen, activeDS.frame_params.bytes_per_line * rows);
SANE_CALL( cancel_device, NULL );
twRC = TWRC_XFERDONE;
}
activeDS.twCC = TWRC_SUCCESS;
}
else
{
ScanningDialogBox(activeDS.progressWnd, -1);
WARN("sane_read: %u\n", twRC);
SANE_CALL( cancel_device, NULL );
activeDS.twCC = TWCC_OPERATIONERROR;
twRC = TWRC_FAILURE;
}
}
if (pImageMemXfer->Memory.Flags & TWMF_HANDLE)
LocalUnlock(pImageMemXfer->Memory.TheMem);
return twRC;
}
/* DG_IMAGE/DAT_IMAGENATIVEXFER/MSG_GET */
TW_UINT16 SANE_ImageNativeXferGet (pTW_IDENTITY pOrigin,
TW_MEMREF pData)
{
TW_UINT16 twRC = TWRC_SUCCESS;
pTW_UINT32 pHandle = (pTW_UINT32) pData;
HANDLE hDIB;
BITMAPINFOHEADER *header = NULL;
int dib_bytes;
int dib_bytes_per_line;
BYTE *line;
RGBQUAD *colors;
int color_size = 0;
int i;
BYTE *p;
TRACE("DG_IMAGE/DAT_IMAGENATIVEXFER/MSG_GET\n");
if (activeDS.currentState != 6)
{
twRC = TWRC_FAILURE;
activeDS.twCC = TWCC_SEQERROR;
}
else
{
/* Transfer an image from the source to the application */
if (SANE_CALL( start_device, NULL ))
{
activeDS.twCC = TWCC_OPERATIONERROR;
return TWRC_FAILURE;
}
if (SANE_CALL( get_params, &activeDS.frame_params ))
{
WARN("sane_get_parameters failed\n");
SANE_CALL( cancel_device, NULL );
activeDS.twCC = TWCC_OPERATIONERROR;
return TWRC_FAILURE;
}
switch (activeDS.frame_params.format)
{
case FMT_GRAY:
if (activeDS.frame_params.depth == 8)
color_size = (1 << 8) * sizeof(*colors);
else if (activeDS.frame_params.depth == 1)
;
else
{
FIXME("For NATIVE, we support only 1 bit monochrome and 8 bit Grayscale, not %d\n", activeDS.frame_params.depth);
SANE_CALL( cancel_device, NULL );
activeDS.twCC = TWCC_OPERATIONERROR;
return TWRC_FAILURE;
}
break;
case FMT_RGB:
break;
case FMT_OTHER:
FIXME("For NATIVE, we support only GRAY and RGB\n");
SANE_CALL( cancel_device, NULL );
activeDS.twCC = TWCC_OPERATIONERROR;
return TWRC_FAILURE;
}
TRACE("Acquiring image %dx%dx%d bits (format=%d last=%d bpl=%d) from sane...\n"
, activeDS.frame_params.pixels_per_line, activeDS.frame_params.lines,
activeDS.frame_params.depth, activeDS.frame_params.format,
activeDS.frame_params.last_frame, activeDS.frame_params.bytes_per_line);
dib_bytes_per_line = ((activeDS.frame_params.bytes_per_line + 3) / 4) * 4;
dib_bytes = activeDS.frame_params.lines * dib_bytes_per_line;
hDIB = GlobalAlloc(GMEM_ZEROINIT, dib_bytes + sizeof(*header) + color_size);
if (hDIB)
header = GlobalLock(hDIB);
if (!header)
{
SANE_CALL( cancel_device, NULL );
activeDS.twCC = TWCC_LOWMEMORY;
if (hDIB)
GlobalFree(hDIB);
return TWRC_FAILURE;
}
header->biSize = sizeof (*header);
header->biWidth = activeDS.frame_params.pixels_per_line;
header->biHeight = activeDS.frame_params.lines;
header->biPlanes = 1;
header->biCompression = BI_RGB;
switch (activeDS.frame_params.format)
{
case FMT_RGB:
header->biBitCount = activeDS.frame_params.depth * 3;
break;
case FMT_GRAY:
header->biBitCount = activeDS.frame_params.depth;
break;
case FMT_OTHER:
break;
}
header->biSizeImage = dib_bytes;
header->biXPelsPerMeter = 0;
header->biYPelsPerMeter = 0;
header->biClrUsed = 0;
header->biClrImportant = 0;
p = (BYTE *)(header + 1);
if (color_size > 0)
{
colors = (RGBQUAD *) p;
p += color_size;
for (i = 0; i < (color_size / sizeof(*colors)); i++)
colors[i].rgbBlue = colors[i].rgbRed = colors[i].rgbGreen = i;
}
/* 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--)
{
int retlen;
struct read_data_params params = { line, activeDS.frame_params.bytes_per_line, &retlen };
activeDS.progressWnd = ScanningDialogBox(activeDS.progressWnd,
((activeDS.frame_params.lines - 1 - i) * 100)
/
(activeDS.frame_params.lines - 1));
twRC = SANE_CALL( read_data, &params );
if (twRC != TWCC_SUCCESS) break;
if (retlen < activeDS.frame_params.bytes_per_line) break;
line -= dib_bytes_per_line;
}
activeDS.progressWnd = ScanningDialogBox(activeDS.progressWnd, -1);
GlobalUnlock(hDIB);
if (twRC != TWCC_SUCCESS)
{
WARN("sane_read: %u, reading line %d\n", twRC, i);
SANE_CALL( cancel_device, NULL );
activeDS.twCC = TWCC_OPERATIONERROR;
GlobalFree(hDIB);
return TWRC_FAILURE;
}
SANE_CALL( cancel_device, NULL );
*pHandle = (UINT_PTR)hDIB;
twRC = TWRC_XFERDONE;
activeDS.twCC = TWCC_SUCCESS;
activeDS.currentState = 7;
}
return twRC;
}