Before starting with MODI.dll, I have to explain what OCR is. Converting images into text is called OCR (Optical Character Recognition). For example pdf files those are screenshots of a plain text page, can be converted into Microsoft Word files and this process requires OCR and this can be done in many ways.
There are lots of solutions which offers OCR in similar ways, some of them can be multilangual and some others can be better at recognizing only some set of fonts. Some of them can be open source and some others can require some licences.
If you need to use open source library, then I suggest you to start with Google's Tesseract. You can find some different C# wrappers like TessNet2, but it currently uses Tesseract2 and I suggest you to wait for a Tessseract3 wrapper.
I dig into Tesseract and at some point I was training my own font to improve results but then I decided to try other options since training is a little bit tricky and I will share it later. Then I found MODI and it actually does almost perfect OCR except that it requires Microsoft Office licence (I guess).
MODI was actually built in OCR dll which existed in Microsoft Office 2003 and 2007 but not in 2010 directly. They have moved MODI into OneNote 2010 but it is a different world.
If you have 2003 or 2007 Office then you just have to include Microsoft Office Document Imaging in your Office configuration. (Software -> Edit Microsoft Office Installation -> Add/Remove Components -> Office- Tools -> Microsoft Office Document Imaging has to be installed.)
If you do not have Office 2003 or 2007 like me, then you just have to get it from Microsoft website. Most simple way is to download this, and when you launch the setup click custom install, disable all components and under Office-Tools, enable just Microsoft Office Document Imaging. Then complete the install, and you should be able to add MODI as reference in your Visual Studio Solution. Other then that, in Start menu you can find an api for MODI under Microsoft Office Tools and try how good it is.
At this point, you have all you need to start OCR with MODI. For best results, I suggest you to save your images in TIF format, and then run OCR with MODI. Let me share my sample code, then you can develop your own methods.
I usually save images to a location and then use OCR so you can do that by web request.
byte[] imageBytes;
HttpWebRequest imageRequest = (HttpWebRequest)WebRequest.Create(imageUrl);
WebResponse imageResponse = imageRequest.GetResponse();
Stream responseStream = imageResponse.GetResponseStream();
using (BinaryReader br = new BinaryReader(responseStream))
{
imageBytes = br.ReadBytes(1500000);
br.Close();
}
responseStream.Close();
imageResponse.Close();
FileStream fs = new FileStream(saveLocation, FileMode.Create);
BinaryWriter bw = new BinaryWriter(fs);
try
{
bw.Write(imageBytes);
}
finally
{
fs.Close();
bw.Close();
}
You can directly save downloaded image as tif or png but most ocr libraries requires TIF with no compression method so that we have to manipulate saved image with following code.
First we get saved image into a Bitmap. Then you should do the manipulations those are necessary. For example, I needed to extend image size by 4, and then I choose interpolation mode, smoothing mode and compositing quality to achieve better image quality for OCR.
Then you should pass encoder info as TIFF and in encoder parameters you should select it as last frame and compression none. Actually in a single tiff file you can add several images, so if you select last frame as multi frames then you can add more images into it. I should write about it as well in another day.
Bitmap bmp = new Bitmap("savedImage.png");
Bitmap dst = new Bitmap((int)(bmp.Width * 4), (int)(bmp.Height * 4));
using (Graphics g = Graphics.FromImage(dst))
{
Rectangle srcRect = new Rectangle(0, 0, bmp.Width, bmp.Height);
Rectangle dstRect = new Rectangle(0, 0, dst.Width, dst.Height);
g.InterpolationMode = InterpolationMode.HighQualityBilinear;
g.SmoothingMode = SmoothingMode.AntiAlias;
g.CompositingQuality = CompositingQuality.GammaCorrected;
g.DrawImage(bmp, dstRect, srcRect, GraphicsUnit.Pixel);
}
ImageCodecInfo encoderInfo = ImageCodecInfo.GetImageEncoders().First(i => i.MimeType == "image/tiff");
EncoderParameters encoderParams = new EncoderParameters(2);
EncoderParameter parameter = new EncoderParameter(System.Drawing.Imaging.Encoder.Compression, (long)EncoderValue.CompressionNone);
encoderParams.Param[0] = parameter;
parameter = new EncoderParameter(System.Drawing.Imaging.Encoder.SaveFlag, (long)EncoderValue.LastFrame);
encoderParams.Param[1] = parameter;
Image tif = (Image)dst;
tif.Save("fileName.tif", encoderInfo, encoderParams);
At the end we save our image file with the extension .tif. Here comes the best part where we do OCR. You should initialize MODI and then set our tif file's path and we will be good to go.
MODI.Document doc = new MODI.Document();
doc.Create("savedImage.tif");
doc.OCR(MODI.MiLANGUAGES.miLANG_ENGLISH, true, true);
MODI.Image img = (MODI.Image)doc.Images[0];
MODI.Layout layout = img.Layout;
string text = layout.Text;
Now text variable contains our image content and you can use it as you wish.
Have a nice day.
Mehmet.
Sunday, September 16, 2012
Wednesday, July 11, 2012
How to Add Attribute ID to Telerik MVC Window When Creating in Javascript
In my previous post I mostly explained how to open a Telerik window in javascript.
I use this function in generic format from all over the application, I simply set url, title and id to pass as arguments and rest is the same. Using ViewInPopup for function name also.
You may need an id for this popup window since you open it via javascript and in some cases manually closing may be needed. For these cases we will just add .attr('id','id-to-give'); to our window element and the last version of our function will be like,
function ViewInPopup(url, id, title) {
$.ajax({
type: 'POST',
url: url,
data: { Id: id },
dataType: 'html',
success: function (htmlData) {
var windowElement = $.telerik.window.create({
title: title,
html: htmlData,
contentUrl: "",
actions: ["Maximize", "Close"],
modal: true,
width: 500,
height: 500,
resizable: false,
draggable: true,
scrollable: true,
onClose: function () { }
});
windowElement.attr('id', 'popupWindow');
var win = $(windowElement).data('tWindow');
win.center().open();
}
})
}
Now you can access this window by id. One more thing to mention, you can close window but you may also need to destroy it.
function closeWindow(id) {
$("#" + id).data('tWindow').close();
$("#" + id).data('tWindow').destroy();
}
If there are any mistakes, let me know.
Regards,
Mehmet.
You may need an id for this popup window since you open it via javascript and in some cases manually closing may be needed. For these cases we will just add .attr('id','id-to-give'); to our window element and the last version of our function will be like,
function ViewInPopup(url, id, title) {
$.ajax({
type: 'POST',
url: url,
data: { Id: id },
dataType: 'html',
success: function (htmlData) {
var windowElement = $.telerik.window.create({
title: title,
html: htmlData,
contentUrl: "",
actions: ["Maximize", "Close"],
modal: true,
width: 500,
height: 500,
resizable: false,
draggable: true,
scrollable: true,
onClose: function () { }
});
windowElement.attr('id', 'popupWindow');
var win = $(windowElement).data('tWindow');
win.center().open();
}
})
}
Now you can access this window by id. One more thing to mention, you can close window but you may also need to destroy it.
function closeWindow(id) {
$("#" + id).data('tWindow').close();
$("#" + id).data('tWindow').destroy();
}
If there are any mistakes, let me know.
Regards,
Mehmet.
Tuesday, July 10, 2012
Telerik MVC Treeview, How to Add CRUD (Edit Create Delete) Buttons, With Popup Window
Telerik MVC users may have known this issue but Treeview absolutely needs some modifications to look like rest of the telerik components. So we have decided to add Edit and Delete button like Grid control on each line. Then we will add Create button on the toolbar. And both Create and Edit will work in popup window.
EDIT: Treeview does not include window.js so we need to register it manually.
<%: Html.Telerik().ScriptRegistrar().jQuery(false).DefaultGroup(group => group.Add("telerik.window.min.js").Add("telerik.draganddrop.min.js"))%>
Adding Edit and Delete buttons on each row is a javascript trick, written by Umut Yıldırım. We simply get each item and append button html before or after text div. Normal Treeview item has following <li> structure,
<li class="t-item">
<div class="t-mid">
<span class="t-in">Item Text</span>
<input class="t-input" name="itemValue" type="hidden" value="7" />
</div>
</li>
What we need to do is adding <a> tags before input or before span. If we add before span then icons will appear at the beginning of ItemText, if we add before input then icons will appear at the end each line.
We first add an onLoad event to Treeview,
events.OnLoad("TreeView_OnLoad");
Then the javascript function which adds our html-to-add before span so it will be at the beginning of item.
function TreeView_OnLoad(e) {
var allNodes = $("li", getTreeView().element);
allNodes.each(function (index) {
var item = allNodes[index];
var text = getTreeView().getItemText(item);
var value = getTreeView().getItemValue(item);
$(this).find("span:first").before("html-to-add");
});
}
If we add before input then it will be at the end, and javascript is as follows,
function TreeView_OnLoad(e) {
var allNodes = $("li", getTreeView().element);
allNodes.each(function (index) {
var item = allNodes[index];
var text = getTreeView().getItemText(item);
var value = getTreeView().getItemValue(item);
$(this).find("input:first").before("html-to-add");
});
}
Then our html-to-add will be as follows, (I changed the classes wrt Gridview button classes so buttons will be same as gridview buttons.)
<a href="href-address" class="t-button"><span class="t-icon t-edit"></span></a>
<a href='#' class="t-button" onclick="..."><span class="t-icon t-delete"></span></a>
As you can see the <a> elements are similar but spans make the difference. If span has class t-edit then it will be edit icon, if it has t-delete then it will be delete icon.
You can modify href or onclick attributes as you desired. If we are going to open a window then we need to put href as "javascript:functionName(arguments)". But for delete button just onClick function is also enough.
For Delete, you can use following javascript function, just a simple function that posts to urlm with given Id. You can change Id and add more parameters, of course method in urlm has to have same parameters and return JsonResult with here Message value. In success part, we remove node with javascript so you will not need to post page again.
function Delete(argument) {
var con = confirm("...");
if (con == true) {
$.ajax({
type: "POST",
url: urlm,
data: { Id: argument },
success: function (response) {
var treeView = getTreeView();
var node = treeView.findByValue( argument );
treeView.remove(node);
alert(response.Message);
},
error: function (xhr, status, error) {
alert(error);
}
});
}
}
For Edit, we need a little more complicated process since we need to open a popup first then load Partial View with given model.
Followint ViewInPopup function opens a telerik window and then post to the given url with given parameters. Then we will load partial view in the given url. Given arguments can be changed but the names have to match with target url's arguments.
function ViewInPopup(url, id, title) {
$.ajax({
type: 'POST',
url: url,
data: { Id: id },
dataType: 'html',
success: function (htmlData) {
var windowElement = $.telerik.window.create({
title: title,
html: htmlData,
contentUrl: "",
actions: ["Maximize", "Close"],
modal: true,
width: 500,
height: 500,
resizable: false,
draggable: true,
scrollable: true,
onClose: function () { }
});
var win = $(windowElement).data('tWindow');
win.center().open();
}
})
}
For edit, we can give url like /Controller/OpenEditPopup to ViewInPopup function and it posts to OpenEditPopup action which is as follows. As you may noticed naming convention of Id is same. We can get model with Id and we will pass to PartialView which expects that type of model.
public ActionResult OpenEditPopup(int Id)
{
...Get model here and pass to Partialview
return PartialView("PartialViewName", model);
}
Above code snippet will load PartialView in our window element.Then you can modify your partial view as you like.
Then we will add Grid-like toolbar and Create button. To achieve this you can inspect Gridview element, and the html tags are as follows. We put this just above Html.Telerik().TreeView().
<div class="t-widget t-grid" id="GridBox">
<div class="t-toolbar t-grid-toolbar t-grid-top">
<a class="t-button t-button-icontext t-grid-add" href="#" onclick="AddNew();">
<span class="t-icon t-add" style="margin-left: 0"></span>Add New</a>
</div>
Then we close the open div right after treeview by </div>.
Here in toolbar we just added Add New button which will look just the same as normal telerik create button. The <a> element and its inner elements are for creating button. The rest is just for toolbar.
In create, the structure will be like Edit and you can give any function as you wish to onclick event. If you want to open in new window, you can use ViewInPopup and direct it to your OpenCreatePopup function which will load your partial view.
So, I have just explained how to put CRUD operations to Telerik MVC Treeview and how to open Create and Edit in popup with partial view.
If there is any typing errors or any mistakes let me know.
Regards,
Mehmet.
EDIT: Treeview does not include window.js so we need to register it manually.
<%: Html.Telerik().ScriptRegistrar().jQuery(false).DefaultGroup(group => group.Add("telerik.window.min.js").Add("telerik.draganddrop.min.js"))%>
Adding Edit and Delete buttons on each row is a javascript trick, written by Umut Yıldırım. We simply get each item and append button html before or after text div. Normal Treeview item has following <li> structure,
<li class="t-item">
<div class="t-mid">
<span class="t-in">Item Text</span>
<input class="t-input" name="itemValue" type="hidden" value="7" />
</div>
</li>
What we need to do is adding <a> tags before input or before span. If we add before span then icons will appear at the beginning of ItemText, if we add before input then icons will appear at the end each line.
We first add an onLoad event to Treeview,
events.OnLoad("TreeView_OnLoad");
Then the javascript function which adds our html-to-add before span so it will be at the beginning of item.
function TreeView_OnLoad(e) {
var allNodes = $("li", getTreeView().element);
allNodes.each(function (index) {
var item = allNodes[index];
var text = getTreeView().getItemText(item);
var value = getTreeView().getItemValue(item);
$(this).find("span:first").before("html-to-add");
});
}
If we add before input then it will be at the end, and javascript is as follows,
function TreeView_OnLoad(e) {
var allNodes = $("li", getTreeView().element);
allNodes.each(function (index) {
var item = allNodes[index];
var text = getTreeView().getItemText(item);
var value = getTreeView().getItemValue(item);
$(this).find("input:first").before("html-to-add");
});
}
Then our html-to-add will be as follows, (I changed the classes wrt Gridview button classes so buttons will be same as gridview buttons.)
<a href="href-address" class="t-button"><span class="t-icon t-edit"></span></a>
<a href='#' class="t-button" onclick="..."><span class="t-icon t-delete"></span></a>
As you can see the <a> elements are similar but spans make the difference. If span has class t-edit then it will be edit icon, if it has t-delete then it will be delete icon.
You can modify href or onclick attributes as you desired. If we are going to open a window then we need to put href as "javascript:functionName(arguments)". But for delete button just onClick function is also enough.
For Delete, you can use following javascript function, just a simple function that posts to urlm with given Id. You can change Id and add more parameters, of course method in urlm has to have same parameters and return JsonResult with here Message value. In success part, we remove node with javascript so you will not need to post page again.
function Delete(argument) {
var con = confirm("...");
if (con == true) {
$.ajax({
type: "POST",
url: urlm,
data: { Id: argument },
success: function (response) {
var treeView = getTreeView();
var node = treeView.findByValue( argument );
treeView.remove(node);
alert(response.Message);
},
error: function (xhr, status, error) {
alert(error);
}
});
}
}
For Edit, we need a little more complicated process since we need to open a popup first then load Partial View with given model.
Followint ViewInPopup function opens a telerik window and then post to the given url with given parameters. Then we will load partial view in the given url. Given arguments can be changed but the names have to match with target url's arguments.
function ViewInPopup(url, id, title) {
$.ajax({
type: 'POST',
url: url,
data: { Id: id },
dataType: 'html',
success: function (htmlData) {
var windowElement = $.telerik.window.create({
title: title,
html: htmlData,
contentUrl: "",
actions: ["Maximize", "Close"],
modal: true,
width: 500,
height: 500,
resizable: false,
draggable: true,
scrollable: true,
onClose: function () { }
});
var win = $(windowElement).data('tWindow');
win.center().open();
}
})
}
For edit, we can give url like /Controller/OpenEditPopup to ViewInPopup function and it posts to OpenEditPopup action which is as follows. As you may noticed naming convention of Id is same. We can get model with Id and we will pass to PartialView which expects that type of model.
public ActionResult OpenEditPopup(int Id)
{
...Get model here and pass to Partialview
return PartialView("PartialViewName", model);
}
Above code snippet will load PartialView in our window element.Then you can modify your partial view as you like.
Then we will add Grid-like toolbar and Create button. To achieve this you can inspect Gridview element, and the html tags are as follows. We put this just above Html.Telerik().TreeView().
<div class="t-widget t-grid" id="GridBox">
<div class="t-toolbar t-grid-toolbar t-grid-top">
<a class="t-button t-button-icontext t-grid-add" href="#" onclick="AddNew();">
<span class="t-icon t-add" style="margin-left: 0"></span>Add New</a>
</div>
Then we close the open div right after treeview by </div>.
Here in toolbar we just added Add New button which will look just the same as normal telerik create button. The <a> element and its inner elements are for creating button. The rest is just for toolbar.
In create, the structure will be like Edit and you can give any function as you wish to onclick event. If you want to open in new window, you can use ViewInPopup and direct it to your OpenCreatePopup function which will load your partial view.
So, I have just explained how to put CRUD operations to Telerik MVC Treeview and how to open Create and Edit in popup with partial view.
If there is any typing errors or any mistakes let me know.
Regards,
Mehmet.
ExecuteNonQuery requires the command to have a transaction when the connection assigned to the command is in a pending local transaction. The Transaction property of the command has not been initialized.
In a transactional connection you might get the error mentioned above. It has a simple solution but we encountered it when switching from Oracle connection to Sql connection.
Oracle Data Access component (ODP Dot Net) actually runs very well without setting command transaction. The following code will work fine with an oracle database (just demonstration, syntax may change)
using(OracleCommand = oracleConnection.CreateCommand())
{
oracleConnection.Open();
OracleTransaction = oracleConnection .BeginTransaction();
OracleCommand.CommandText = "Procedure Name";
OracleCommand.CommandType = CommandType.StoredProcedure;
OracleCommand.Parameters.Clear();
OracleCommand.Parameters.Add(...Add Parameters...);
OracleCommand.ExecuteNonQuery();
}
But in sql connection, we get "ExecuteNonQuery requires the command to have a transaction when the connection assigned to the command is in a pending local transaction. The Transaction property of the command has not been initialized." error, since we actually did not set the transaction property.
OdpDotNet actually handles this but SqlConnection and SqlCommand can not. So we change our Sql code block with transaction version. Which is as follows,
using (SqlConnection conn = new SqlConnection(connectionAddress))
{
SqlTransaction trans = null;
try
{
conn.Open();
trans = conn.BeginTransaction();
using (SqlCommand comm = conn.CreateCommand())
{
comm.CommandText = item.Sql;
comm.Transaction = trans;
comm.CommandType = CommandType.StoredProcedure;
comm.Parameters.Clear();
comm.Parameters.AddWithValue(parametreItem.Key, parametreItem.Value);
comm.ExecuteNonQuery();
}
trans.Commit();
}
catch (Exception ex)
{
trans.Rollback();
throw ex;
}
finally
{
trans.Dispose();
conn.Close();
}
}
If there is any mistakes let me know, so I can fix :)
Regards,
Mehmet.
Oracle Data Access component (ODP Dot Net) actually runs very well without setting command transaction. The following code will work fine with an oracle database (just demonstration, syntax may change)
using(OracleCommand = oracleConnection.CreateCommand())
{
oracleConnection.Open();
OracleTransaction = oracleConnection .BeginTransaction();
OracleCommand.CommandText = "Procedure Name";
OracleCommand.CommandType = CommandType.StoredProcedure;
OracleCommand.Parameters.Clear();
OracleCommand.Parameters.Add(...Add Parameters...);
OracleCommand.ExecuteNonQuery();
}
But in sql connection, we get "ExecuteNonQuery requires the command to have a transaction when the connection assigned to the command is in a pending local transaction. The Transaction property of the command has not been initialized." error, since we actually did not set the transaction property.
OdpDotNet actually handles this but SqlConnection and SqlCommand can not. So we change our Sql code block with transaction version. Which is as follows,
using (SqlConnection conn = new SqlConnection(connectionAddress))
{
SqlTransaction trans = null;
try
{
conn.Open();
trans = conn.BeginTransaction();
using (SqlCommand comm = conn.CreateCommand())
{
comm.CommandText = item.Sql;
comm.Transaction = trans;
comm.CommandType = CommandType.StoredProcedure;
comm.Parameters.Clear();
comm.Parameters.AddWithValue(parametreItem.Key, parametreItem.Value);
comm.ExecuteNonQuery();
}
trans.Commit();
}
catch (Exception ex)
{
trans.Rollback();
throw ex;
}
finally
{
trans.Dispose();
conn.Close();
}
}
If there is any mistakes let me know, so I can fix :)
Regards,
Mehmet.
Tuesday, June 19, 2012
Grid Row Html Attributes & Row Color in Telerik MVC Grid
There are two ways of get this done in Telerik MVC Grid component.
If you are using server side binding, I think it is a little handy in several cases. You can add this in your aspx page to Grid component:
.RowAction(row =>
{
if (row.DataItem.GridKey == 2012)
{
row.HtmlAttributes["style"] = "background:red;";
}
})
You can custumize as you wish the string assigned to HtmlAttributes["style"] element. It will work the style element in a html tag.
If you are using Ajax binding that means you have to do the style thing in OnRowDataBound event. It has to be in javascript and sometimes you may not able to access your control attributes. Here is the code:
.ClientEvents(events => events.OnRowDataBound("Grid_OnRowDataBound"))
<script type="text/javascript">
function Grid_OnRowDataBound(e) {
if (e.dataItem.GridKey == 2012) {
e.row.style.backgroundColor = "red";
}
}
</script>
Regards,
Mehmet.
If you are using server side binding, I think it is a little handy in several cases. You can add this in your aspx page to Grid component:
.RowAction(row =>
{
if (row.DataItem.GridKey == 2012)
{
row.HtmlAttributes["style"] = "background:red;";
}
})
You can custumize as you wish the string assigned to HtmlAttributes["style"] element. It will work the style element in a html tag.
If you are using Ajax binding that means you have to do the style thing in OnRowDataBound event. It has to be in javascript and sometimes you may not able to access your control attributes. Here is the code:
.ClientEvents(events => events.OnRowDataBound("Grid_OnRowDataBound"))
<script type="text/javascript">
function Grid_OnRowDataBound(e) {
if (e.dataItem.GridKey == 2012) {
e.row.style.backgroundColor = "red";
}
}
</script>
We have added the style attribute for each row seperately at OnRowDataBound event. You can add anything like font-size, bold or not, italic, etc.
If there is any mistakes let me know, so I can fix :)
Regards,
Mehmet.
Subscribe to:
Posts (Atom)