Home › Forums › TWAIN Classic › Memory transfer mode: desuming the header
- This topic has 10 replies, 2 voices, and was last updated 14 years, 7 months ago by sdavi.
- AuthorPosts
Hi all, i’m working on buffered memory transfer mode.
I’m able to save on filesystem image data but i dont save into file
header info of the image (the buffered memory transfer mode dont carry out with header information).
So i’ve a question: how can i deducing the header of image? it must be a BITMAPFILEHEADER + BITMAINFOHEADER/BITMAPCOREHEADER? (this implies that i get always a bitmap?)
How can i make the header?
Best regardsAnother question: when i use native mode, the scanner return me a dib handle, so i can desume BITMAPINFOHEADER and BITMAPFILEHEADER structs, save it and then the bitmap bits. it works.
if in my app i want give to end user the choice to save image in another format, i can use any image processing library (imagemagick, freeimage etc.) but only if i save the returned image in bmp format.
So my question: both in memory and native mode (i know that in file mode it is possible), is there any chance to give in other format (jpeg, png, tiff and so on) directly by the device???
In twain spec. is written that in memory mode the device return the image data without header, so the programmer must deduce the headers.
In memory mode, the returned data are always of a bitmap?Now, i can get the image data by a memory transfer, desume the hneeded headers (BITMAPFLILEHEADER and BITMAPINFOHEADER),
and i can save it into the filesystem, but when i open the image with a program (gimp for example) i note that the image is flipped vertically.
Why???
Anyone can say me why the source transfer image data in that way?Post my code in relevants parts:
void doBufferedMemoryTransfer()
{
/*commented code, only explained for semplicity*/
//call DG_CONTROL,DAT_SETUPMEMXFER,MSG_GET so i can setup twMemXFer that is of TW_SETUPMEMXFER type
// call getImageInfo(); and getImageLayout(); that wraps DG_IMAGE,DAT_IMAGEINFO,MSG_GET and DG_IMAGE,DAT_IMAGELAYOUT,MSG_GET respectively
// in a loop i call DG_IMAGE,DAT_IMAGEMEMXFER,MSG_GET until TWRC_XFERDONE is fired by last call to DG_IMAGE,DAT_IMAGEMEMXFER,MSG_GET
/*end commented code*/
...
case TWRC_SUCCESS:
fwrite((void*)buf,1,(UINT)twImageMemXFer.BytesWritten,pFile);
break;
case TWRC_XFERDONE:
//write last buffer into the file
fwrite((void*)buf,1,(UINT)twImageMemXFer.BytesWritten,pFile);
//call fseek to move the file pointer to begin of file in order to write
//image headers that needs to be placed in
fseek ( pFile , 0 , SEEK_SET );
bitmapFileHeader.bfSize = sizeof(BITMAPFILEHEADER) ;
bitmapFileHeader.bfType = 0x4D42;//BM
bitmapFileHeader.bfReserved1 = 0;
bitmapFileHeader.bfReserved2 = 0;
bitmapFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) ;
bitmapInfoHeader.biSize = sizeof(BITMAPINFOHEADER) ;
bitmapInfoHeader.biPlanes = 1;
bitmapInfoHeader.biBitCount = imageInfo->getBitsPerPixel();
bitmapInfoHeader.biCompression = BI_RGB;//imageInfo->getCompression();
bitmapInfoHeader.biSizeImage = ((((imageInfo->getImageWidth() * imageInfo->getBitsPerPixel() + 31) / 32)*4) * abs(imageInfo->getImageLength()));
bitmapInfoHeader.biXPelsPerMeter = 0;
bitmapInfoHeader.biYPelsPerMeter = 0;
bitmapInfoHeader.biClrUsed = 0;
bitmapInfoHeader.biClrImportant = 0;
bitmapInfoHeader.biWidth = imageInfo->getImageWidth();
bitmapInfoHeader.biHeight = imageInfo->getImageLength();
fwrite(&bitmapFileHeader, 1, sizeof(BITMAPFILEHEADER), pFile);
fwrite(&bitmapInfoHeader, 1, sizeof(BITMAPINFOHEADER), pFile);
//other calls to free memory, close file handle and exit from the loop omitted.
break;
}
The imageInfo instance is a instance of a class that wraps TW_IMAGEINFO struct.
best regards
Windows BMP images have the origin (point 0,0) at the bottom-left corner of the image. Most everything else has it at the top-left.
A quick and easy solution is to write a negative length in the header. For example, if the image is 100 pixels long, set the length to -100. Most programs can handle that. Some interpret the length as an unsigned integer so a negative value looks like a very large positive value. Usually, these programs will report that there’s not enough memory to load the image.
The other solution is to flip the pixels vertically so the origin is at the bottom-left.
–
Yes, now its ok, tank you. But theimage (under memory transfer mode)
has some problem: the colors are not interpreted correctly and at certain resolution the image is streched.Aren’t BMP’s a joy to work with? Not only are the rows bottom-up but the color sequence is BGR instead of the usual RGB. Obviously, to fix that you have to swap the red and blue channels for each pixel in the image.
Aspect ratio distortion (i.e. stretching) could be caused by not setting the X and Y resolutions to the same value. Most DS’s do not support independent X and Y resolutions so another possibility is that you found a bug.
–
Tanks for the reply.
Now i get image not stretched and in BGR format.
Thare’s another problem now: for certains resolutions when i apply a little loop in order to convert from BGR to RGB the scanner produce an image with correct colors; with another resolution no.
The routine is very simple: if i got a buffer (under TWRC_SUCCESS, o the last buffer under TWRX_XFERDONE) i do:
for(int i=0; i{
tmp=buf;
buf=buf[i+2];
buf[i+2]=tmp;
}
where buf is buffer memory.
So i make a little test, and set all bytes to BLUE color, for example.
So i wrote:
for(int i=0; i{
buf = 255;//Its in BGR format, for obtain a BLUE pixel
buf[i+1]=0;
buf[i+2]=0;
}
for all pixels in every buffer.
What i expect is the image is all BLUE, unique color, but it’s not:
I read (edited the image with GIMP) a ilne BLUE, another GREEN and the last RED, for all lines in the image.
It’s strange.
Can u help me about this?
Why i change the resolution this strange behavior?
I make a test with my scanner (BROTHER), the kodaki30 in simulation mode.
Best regardsWhen the number of bytes per row is not evenly divisble by 3, you’re loop won’t work. Rewrite it to do one row at a time instead of the entire buffer in one pass.
–
Tank you, now it works!.
Only last litttle problem: when in memory mode i set various values, the resulting image is always 72×72 dpi (openong it from gimp).
Instead in native mode, when i set variuos resolutions, the dpi reflect the resolution i set previously.
Any idea dpenney?
The problem is that i never worked with images….
Best regardsThe resolution is specified in the header. The units are pixels per meter:
const float INCHES_PER_METER = 39.3700787f;
bmInfoHeader.biXPelsPerMeter = (int)((dpi * INCHES_PER_METER) + 0.5f);
bmInfoHeader.biYPelsPerMeter = bmInfoHeader.biXPelsPerMeter;–
Hi depenney, tank you very much for all your support.
Best regards- AuthorPosts