I'm trying to use Leadtools Version 20 to automatically cleanup some images (black border removal, line removal, deskew, ...).
Since some of the APIs only work with black and white images, I create a copy of the image in memory and turn it black and white using L_ColorResBitmap
. My plan is to use this black and white image to do the processing and then process the colored image manually. For example I use L_BorderRemoveBitmap
to figure out the region that needs to be wiped out and then wipe the same region on the color image or use L_DeskewBitmap
to figure out the angle that black and white image needs to be turned and then use L_RotateBitmap
to turn the colored image. But when I use L_LineRemoveBitmap
, it returns an empty region. I even tried to use the callback function, but inside the callback function region is always NULL.
I have made sure the image that is being loaded has a vertical line in it and if I save the black and white version the line is removed, but the correct region is not handed back.
Here is a snippet of what I'm doing:
FILEINFO fi;
L_INT PageCount;
L_INT i;
L_UINT uFlags;
BITMAPHANDLE tBmp;
BITMAPHANDLE bwBmp;
BORDERREMOVE br = {sizeof(BORDERREMOVE), BORDER_SINGLE_REGION, BORDER_ALL, 25, 4, 10, NULL, nullptr, sizeof(BITMAPHANDLE)};
RECT r;
LINEREMOVE lr = {sizeof(LINEREMOVE), LINE_SINGLE_REGION, 400, 12, 15, 10, 2, 0, LINEREMOVE_VERTICAL, NULL, nullptr, sizeof(BITMAPHANDLE)};
memset(&fi, 0, sizeof(FILEINFO));
fi.uStructSize = sizeof(FILEINFO);
plo->PageNumber = 0; // plo is a LOADFILEOPTION*
L_FileInfo(FileName, &fi, sizeof(FILEINFO), FILEINFO_TOTALPAGES, plo); // ok
PageCount = fi.TotalPages;
for(i = 0; i < PageCount; i++)
{
memset(&fi, 0, sizeof(FILEINFO));
fi.uStructSize = sizeof(FILEINFO);
plo->PageNumber = i + 1;
memset(&tBmp, 0, sizeof(BITMAPHANDLE));
FileInfo(FileName, &fi, sizeof(FILEINFO), 0, plo); // OK
if(tBmp.Flags.Allocated)
L_FreeBitmap(&tBmp);
L_LoadBitmap(FileName, &tBmp, sizeof(BITMAPHANDLE), fi.BitsPerPixel > 24 ? 24 : fi.BitsPerPixel, ORDER_RGBORGRAY, plo, &fi); // OK
if(tBmp.Flags.Allocated)
{
if (TOP_LEFT != tBmp.ViewPerspective)
L_ChangeBitmapViewPerspective(NULL, &tBmp, sizeof(BITMAPHANDLE), TOP_LEFT);
uFlags = DSKW_PROCESS | DSKW_FILL | DSKW_DOCUMENTANDPICTURE | DSKW_BICUBIC | DSKW_NORMALSPEEDROTATE;
if(1 != fi.BitsPerPixel)
uFlags |= (DSKW_DONT_PERFORM_PREPROCESSING | DSKW_NORMAL_DETECTION);
memset(&BitmapRegion, 0, sizeof(BITMAPHANDLE));
BitmapRegion.uStructSize = sizeof(BITMAPHANDLE);
if(bwBmp.Flags.Allocated)
L_FreeBitmap(&bwBmp);
memset(&bwBmp, 0, sizeof(BITMAPHANDLE));
bwBmp.uStructSize = sizeof(BITMAPHANDLE);
L_CopyBitmap(&bwBmp, &tBmp, bwBmp.uStructSize); // OK
if(1 != tBmp.BitsPerPixel)
L_ColorResBitmap(&bwBmp, &bwBmp, sizeof(BITMAPHANDLE), 1, CRF_FIXEDPALETTE, NULL, NULL, 0, NULL, NULL); // OK
L_BorderRemoveBitmap(&bwBmp, &br, nullptr, nullptr, 0) // OK
if(NULL != br.hRgn)
{
L_SetBitmapRgnHandle(&tBmp, nullptr, br.hRgn, L_RGN_SET); // OK
L_FillBitmap(&tBmp, bkColor); // OK bkColor is White
L_FreeBitmapRgn(&tBmp);
}
L_LineRemoveBitmap(&bwBmp, &lr, lrCB, NULL, 0) // returns OK
if(NULL != lr.hRgn) // not null but empty
{
::GetRgnBox(lr.hRgn, &r); // it is always {0, 0, 0, 0}
L_SetBitmapRgnHandle(&tBmp, nullptr, lr.hRgn, L_RGN_SET);
L_FillBitmap(&tBmp, bkColor); // OK but fills nothing
L_FreeBitmapRgn(&tBmp);
}
// do other stuff and save
}
}
L_INT EXT_CALLBACK lrCB(HRGN hRgn, L_INT iStartRow, L_INT iStartCol, L_INT iLength, L_VOID* pUserData)
{
UNREFERENCED_PARAMETER(pUserData);
if(NULL != hRgn) // always null
{
RECT rcRect;
GetRgnBox(hRgn, &rcRect);
DeleteObject(hRgn);
}
return SUCCESS_REMOVE;
}
Sam,
If you want the Callback to set a Windows region, you need to also set the LINE_CALLBACK_REGION uFlag when defining the LINEREMOVE structure:
LINEREMOVE lr = {
sizeof(LINEREMOVE), // uStructSize
LINE_CALLBACK_REGION| LINE_SINGLE_REGION, // uFlags
400, // Minimum Length
12, // Maximum Width
15, // Wall size
10, // Max percent of line that can be a wall
2, // Maximum Gap
0, // Maximum Line Variance
LINEREMOVE_VERTICAL, // horizontal or vertical
NULL, // hRgn
nullptr, // pBitmapRegion
sizeof(BITMAPHANDLE) // uBitmapStructSize
};
The flag is documented in this page.
After the function finishes processing, you can then take the lines region set in the lr.hRgn property and set it in the original color bitmap using the following code:
L_SetBitmapRgnHandle(&OriginalBitmap, NULL, lr.hRgn, L_RGN_SET);
In addition to the response here, I have sent you a small code snippet in a reply to the email you sent to our support address.