diff --git a/app/fwupgrade/FWUpgrade_resource.qrc b/app/fwupgrade/FWUpgrade_resource.qrc index be103270..145ff74b 100644 --- a/app/fwupgrade/FWUpgrade_resource.qrc +++ b/app/fwupgrade/FWUpgrade_resource.qrc @@ -1,6 +1,7 @@ FWUpgrade_zh_CN.qm + qt_zh_CN.qm image_rsc/logo/auge_logo.ico @@ -10,7 +11,7 @@ image_rsc/logo/HUAGO-LOGO-for UI.jpg image_rsc/logo/HUAGO-LOGO-for UI.png image_rsc/logo/Lanxum_logo.ico - image_rsc/logo/Cumtenn_logo.ico + image_rsc/logo/Cumtenn_logo.ico image_rsc/logo/logo.ico image_rsc/logo/NoBrand_logo.ico image_rsc/logo/RightWay_logo.ico diff --git a/app/fwupgrade/main.cpp b/app/fwupgrade/main.cpp index fd5f779a..7ddfc210 100644 --- a/app/fwupgrade/main.cpp +++ b/app/fwupgrade/main.cpp @@ -12,8 +12,12 @@ int main(int argc, char *argv[]) { QApplication a(argc, argv); + QTranslator translator_app; + if (translator_app.load(":translation/FWUpgrade_zh_CN.qm")) + a.installTranslator(&translator_app); + QTranslator translator_qt; - if (translator_qt.load(":translation/FWUpgrade_zh_CN.qm")) + if (translator_qt.load(":translation/qt_zh_CN.qm")) a.installTranslator(&translator_qt); MainWindow w; diff --git a/app/fwupgrade/qt_zh_CN.qm b/app/fwupgrade/qt_zh_CN.qm new file mode 100644 index 00000000..e8d65305 Binary files /dev/null and b/app/fwupgrade/qt_zh_CN.qm differ diff --git a/app/fwupgrade/qt_zh_CN.ts b/app/fwupgrade/qt_zh_CN.ts new file mode 100644 index 00000000..f6a25d21 --- /dev/null +++ b/app/fwupgrade/qt_zh_CN.ts @@ -0,0 +1,8077 @@ + + + + + MAC_APPLICATION_MENU + + + Services + 服务 + + + + Hide %1 + 隐藏%1 + + + + Hide Others + 隐藏其他 + + + + Show All + 全部显示 + + + + Preferences... + 偏好设置… + + + + Quit %1 + 退出 %1 + + + + About %1 + 关于 %1 + + + + AudioOutput + + + <html>The audio playback device <b>%1</b> does not work.<br/>Falling back to <b>%2</b>.</html> + <html>音频回放设备 <b>%1</b> 没有工作。<br/>回滚到 <b>%2</b>。</html> + + + + <html>Switching to the audio playback device <b>%1</b><br/>which just became available and has higher preference.</html> + <html>切换到音频回放设备 <b>%1</b>,<br/>它刚刚变为可用并且具有更高的优先级。</html> + + + + Revert back to device '%1' + 恢复到设备“%1” + + + + CloseButton + + + Close Tab + 关闭标签页 + + + + Phonon:: + + + Notifications + 通知 + + + + Music + 音乐 + + + + Video + 视频 + + + + Communication + 通讯 + + + + Games + 游戏 + + + + Accessibility + 无障碍环境 + + + + Phonon::Gstreamer::Backend + + + Warning: You do not seem to have the package gstreamer0.10-plugins-good installed. + Some video features have been disabled. + 警告:看起来,您没有安装 gstreamer0.10-plugins-good 包。 + 一些视频特性已经被关闭。 + + + + Warning: You do not seem to have the base GStreamer plugins installed. + All audio and video support has been disabled + 警告:看起来,您没有安装基础的 GStreamer 插件。 + 所有的音频和视频支持都已经被关闭。 + + + + Phonon::Gstreamer::MediaObject + + + Cannot start playback. + +Check your Gstreamer installation and make sure you +have libgstreamer-plugins-base installed. + 不能开始回放。 + +请检查您的 Gstreamer 安装并且确认您 +已经安装 libgstreamer-plugins-base。 + + + + A required codec is missing. You need to install the following codec(s) to play this content: %0 + 缺少一个需要的解码器。您需要安装如下解码器来播放这个内容:%0 + + + + + + + + + + + Could not open media source. + 不能打开媒体源。 + + + + Invalid source type. + 无效的源类型。 + + + + Could not locate media source. + 不能定位媒体源。 + + + + Could not open audio device. The device is already in use. + 不能打开音频设备。这个设备正在被使用。 + + + + Could not decode media source. + 不能解码媒体源。 + + + + Phonon::VolumeSlider + + + + Volume: %1% + 音量:%1% + + + + + + Use this slider to adjust the volume. The leftmost position is 0%, the rightmost is %1% + 请使用这个滑块调节音量。最左为%0,最右为%1% + + + + Q3Accel + + + %1, %2 not defined + %1,%2未定义 + + + + Ambiguous %1 not handled + 不明确的%1没有被处理 + + + + Q3DataTable + + + True + + + + + False + + + + + Insert + 插入 + + + + Update + 更新 + + + + Delete + 删除 + + + + Q3FileDialog + + + Copy or Move a File + 复制或者移动一个文件 + + + + Read: %1 + 读取:%1 + + + + + Write: %1 + 写入:%1 + + + + + Cancel + 取消 + + + + + + + All Files (*) + 所有文件 (*) + + + + Name + 名称 + + + + Size + 大小 + + + + Type + 类型 + + + + Date + 日期 + + + + Attributes + 属性 + + + + + &OK + 确定(&O) + + + + Look &in: + 查找范围(&I): + + + + + + File &name: + 文件名称(&N): + + + + File &type: + 文件类型(&T): + + + + Back + 后退 + + + + One directory up + 向上一级 + + + + Create New Folder + 创建新文件夹 + + + + List View + 列表视图 + + + + Detail View + 详细视图 + + + + Preview File Info + 预览文件信息 + + + + Preview File Contents + 预览文件内容 + + + + Read-write + 读写 + + + + Read-only + 只读 + + + + Write-only + 只写 + + + + Inaccessible + 不可访问的 + + + + Symlink to File + 文件的系统链接 + + + + Symlink to Directory + 目录的系统链接 + + + + Symlink to Special + 特殊的系统链接 + + + + File + 文件 + + + + Dir + 目录 + + + + Special + 特殊 + + + + + + Open + 打开 + + + + + Save As + 另存为 + + + + + + &Open + 打开(&O) + + + + + &Save + 保存(&S) + + + + &Rename + 重命名(&R) + + + + &Delete + 删除(&D) + + + + R&eload + 重新载入(&E) + + + + Sort by &Name + 按名称排列(&N) + + + + Sort by &Size + 按大小排列(&S) + + + + Sort by &Date + 按日期排列(&D) + + + + &Unsorted + 未排列的(&U) + + + + Sort + 排列 + + + + Show &hidden files + 显示隐藏文件(&H) + + + + the file + 文件 + + + + the directory + 目录 + + + + the symlink + 系统链接 + + + + Delete %1 + 删除%1 + + + + <qt>Are you sure you wish to delete %1 "%2"?</qt> + <qt>你确认你想删除%1,“%2”?</qt> + + + + &Yes + 是(&Y) + + + + &No + 否(&N) + + + + New Folder 1 + 新建文件夹1 + + + + New Folder + 新建文件夹 + + + + New Folder %1 + 新建文件夹%1 + + + + Find Directory + 查找目录 + + + + + Directories + 目录 + + + + Directory: + 目录: + + + + + Error + 错误 + + + + %1 +File not found. +Check path and filename. + 文件%1 +未找到。 +请检查路径和文件名。 + + + + + All Files (*.*) + 所有文件 (*.*) + + + + Open + 打开 + + + + Select a Directory + 选择一个目录 + + + + Q3LocalFs + + + + Could not read directory +%1 + 不能读取目录 +%1 + + + + Could not create directory +%1 + 不能创建目录 +%1 + + + + Could not remove file or directory +%1 + 不能移除文件或者目录 +%1 + + + + Could not rename +%1 +to +%2 + 不能把 +%1 +重命名为 +%2 + + + + Could not open +%1 + 不能打开 +%1 + + + + Could not write +%1 + 不能写入 +%1 + + + + Q3MainWindow + + + Line up + 排列 + + + + Customize... + 自定义... + + + + Q3NetworkProtocol + + + Operation stopped by the user + 操作被用户停止 + + + + Q3ProgressDialog + + + + Cancel + 取消 + + + + Q3TabDialog + + + + OK + 确认 + + + + Apply + 应用 + + + + Help + 帮助 + + + + Defaults + 默认 + + + + Cancel + 取消 + + + + Q3TextEdit + + + &Undo + 撤消(&U) + + + + &Redo + 恢复(&R) + + + + Cu&t + 剪切(&T) + + + + &Copy + 复制(&C) + + + + &Paste + 粘贴(&P) + + + + Clear + 清空 + + + + + Select All + 选择全部 + + + + Q3TitleBar + + + System + 系统 + + + + Restore up + 向上恢复 + + + + Minimize + 最小化 + + + + Restore down + 向下恢复 + + + + Maximize + 最大化 + + + + Close + 关闭 + + + + Contains commands to manipulate the window + 包含操作窗口的命令。 + + + + Puts a minimized back to normal + 把一个最小化窗口恢复为普通状态 + + + + Moves the window out of the way + 把窗口移到外面 + + + + Puts a maximized window back to normal + 把一个最大化窗口恢复为普通状态 + + + + Makes the window full screen + 窗口全屏化 + + + + Closes the window + 关闭窗口 + + + + Displays the name of the window and contains controls to manipulate it + 显示窗口名称并且包含维护它的控件 + + + + Q3ToolBar + + + More... + 更多... + + + + Q3UrlOperator + + + + + The protocol `%1' is not supported + 协议“%1”不被支持 + + + + The protocol `%1' does not support listing directories + 协议“%1”不支持列出目录 + + + + The protocol `%1' does not support creating new directories + 协议“%1”不支持创建新目录 + + + + The protocol `%1' does not support removing files or directories + 协议“%1”不支持移除文件或者目录 + + + + The protocol `%1' does not support renaming files or directories + 协议“%1”不支持重命名文件或者目录 + + + + The protocol `%1' does not support getting files + 协议“%1”不支持获取文件 + + + + The protocol `%1' does not support putting files + 协议“%1”不支持上传文件 + + + + + The protocol `%1' does not support copying or moving files or directories + 协议“%1”不支持复制或者移动文件或者目录 + + + + + (unknown) + (未知的) + + + + Q3Wizard + + + &Cancel + 取消(&C) + + + + < &Back + < 上一步(&B) + + + + &Next > + 下一步(&N) > + + + + &Finish + 完成(&F) + + + + &Help + 帮助(&H) + + + + QAbstractSocket + + + + + + Host not found + 主机未找到 + + + + + + Connection refused + 连接被拒绝 + + + + Connection timed out + 连接超时 + + + + + + Operation on socket is not supported + Socket操作不被支持 + + + + Socket operation timed out + 套接字操作超时 + + + + Socket is not connected + 套接字没有被连接 + + + + Network unreachable + 网络不能访问 + + + + QAbstractSpinBox + + + &Step up + 增加(&S) + + + + Step &down + 减少(&D) + + + + &Select All + 选择全部(&S) + + + + QApplication + + + Activate + 激活 + + + + Executable '%1' requires Qt %2, found Qt %3. + 执行“%1”需要Qt %2,只找到了Qt %3。 + + + + Incompatible Qt Library Error + 不兼容的Qt错误 + + + + Activates the program's main window + 激活这个程序的主窗口 + + + + QAxSelect + + + Select ActiveX Control + 选择ActiveX控件 + + + + OK + 确定 + + + + &Cancel + 取消(&C) + + + + COM &Object: + COM对象(&O): + + + + QCheckBox + + + Uncheck + 取消选中 + + + + Check + 选中 + + + + Toggle + 切换 + + + + QColorDialog + + + Hu&e: + 色调(&E): + + + + &Sat: + 饱和度(&S): + + + + &Val: + 亮度(&V): + + + + &Red: + 红色(&R): + + + + &Green: + 绿色(&G): + + + + Bl&ue: + 蓝色(&U): + + + + A&lpha channel: + Alpha通道(&A): + + + + Select Color + 选择颜色 + + + + &Basic colors + 基本颜色(&B) + + + + &Custom colors + 自定义颜色(&C) + + + + &Add to Custom Colors + 添加到自定义颜色(&A) + + + Select color + 选择颜色 + + + &Pick Screen Color + 拾取屏幕颜色(&P) + + + Cursor at %1, %2 +Press ESC to cancel + 光标位置 %1, %2 +按ESC键取消 + + + &HTML: + 颜色值(&H): + + + + QComboBox + + + + Open + 打开 + + + + False + + + + + True + + + + + Close + 关闭 + + + + QCoreApplication + + %1: permission denied + QSystemSemaphore + %1:权限被拒绝 + + + %1: already exists + QSystemSemaphore + %1:已经存在 + + + %1: doesn't exists + QSystemSemaphore + %1:不存在 + + + %1: out of resources + QSystemSemaphore + %1:资源耗尽了 + + + %1: unknown error %2 + QSystemSemaphore + %1:未知错误 %2 + + + + %1: key is empty + QSystemSemaphore + %1:键是空的 + + + + %1: unable to make key + QSystemSemaphore + %1:不能制造键 + + + + %1: ftok failed + QSystemSemaphore + %1:ftok 失败 + + + + QDB2Driver + + + Unable to connect + 不能连接 + + + + Unable to commit transaction + 不能提交事务 + + + + Unable to rollback transaction + 不能回滚事务 + + + + Unable to set autocommit + 不能设置自动提交 + + + + QDB2Result + + + + Unable to execute statement + 不能执行语句 + + + + Unable to prepare statement + 不能准备语句 + + + + Unable to bind variable + 不能帮定变量 + + + + Unable to fetch record %1 + 不能获取记录%1 + + + + Unable to fetch next + 不能获取下一个 + + + + Unable to fetch first + 不能获取第一个 + + + + QDateTimeEdit + + + AM + AM + + + + am + am + + + + PM + PM + + + + pm + pm + + + + QDial + + + QDial + QDial + + + + SpeedoMeter + SpeedoMeter + + + + SliderHandle + SliderHandle + + + + QDialog + + + What's This? + 这是什么? + + + + Done + 完成 + + + + QDialogButtonBox + + + + + OK + 确定 + + + + Save + 保存 + + + + &Save + 保存(&S) + + + + Open + 打开 + + + + Cancel + 取消 + + + + &Cancel + 取消(&C) + + + + Close + 关闭 + + + + &Close + 关闭(&C) + + + + Apply + 应用 + + + + Reset + 重置 + + + + Help + 帮助 + + + + Don't Save + 不保存 + + + + Discard + 抛弃 + + + + &Yes + 是(&Y) + + + + Yes to &All + 全部是(&A) + + + + &No + 否(&N) + + + + N&o to All + 全部否(&O) + + + + Save All + 保存全部 + + + + Abort + 放弃 + + + + Retry + 重试 + + + + Ignore + 忽略 + + + + Restore Defaults + 恢复默认 + + + + Close without Saving + 不保存关闭 + + + + &OK + 确定(&O) + + + + QDirModel + + + Name + 名称 + + + + Size + 大小 + + + + Kind + Match OS X Finder + 类型 + + + + Type + All other platforms + 类型 + + + + Date Modified + 日期被修改 + + + + QDockWidget + + + Close + 关闭 + + + + Dock + 锚接 + + + + Float + 浮动 + + + + QDoubleSpinBox + + + More + 更多 + + + + Less + 更少 + + + + QErrorMessage + + + Debug Message: + 调试消息: + + + + Warning: + 警告: + + + + Fatal Error: + 致命错误: + + + + &Show this message again + 再次显示这个消息(&S) + + + + &OK + 确定(&O) + + + + QFile + + + + Destination file exists + 目标文件已存在 + + + + Cannot remove source file + + + + + Cannot open %1 for input + 无法输入 %1 + + + + Cannot open for output + 无法输出 + + + + Failure to write block + 写块失败 + + + + Cannot create %1 for output + 无法创建 %1 + + + + QFileDialog + + + + All Files (*) + 所有文件 (*) + + + + Directories + 目录 + + + + + + + &Open + 打开(&O) + + + + + &Save + 保存(&S) + + + + &Cancel + 取消(&S) + + + + Cancel + 取消 + + + + Open + 打开 + + + + %1 already exists. +Do you want to replace it? + %1已经存在。 +你想要替换它么? + + + + %1 +File not found. +Please verify the correct file name was given. + 文件%1 +没有找到。 +请核实已给定正确文件名。 + + + + My Computer + 我的计算机 + + + + &Rename + 重命名(&R) + + + + &Delete + 删除(&D) + + + + Show &hidden files + 显示隐藏文件(&H) + + + + + Back + 后退 + + + + + Parent Directory + 父目录 + + + + + List View + 列表视图 + + + + + Detail View + 详细视图 + + + + + Files of type: + 文件类型: + + + + + Directory: + 目录: + + + + + %1 +Directory not found. +Please verify the correct directory name was given. + 目录%1 +没有找到。 +请核实已给定正确目录名。 + + + + '%1' is write protected. +Do you want to delete it anyway? + “%1“是写保护的。 +你还是想删除它么? + + + + Are sure you want to delete '%1'? + 你确认你想删除“%1“? + + + + Could not delete directory. + 不能删除目录。 + + + + Recent Places + 最近的地方 + + + + Save As + 另存为 + + + + Drive + 驱动器 + + + + + File + 文件 + + + + Unknown + 未知的 + + + + Find Directory + 查找目录 + + + + Show + 显示 + + + + + Forward + 前进 + + + + New Folder + 新建文件夹 + + + + &New Folder + 新建文件夹(&N) + + + + + &Choose + 选择(&C) + + + + Remove + 移除 + + + + + File &name: + 文件名称(&N): + + + + + Look in: + 查看: + + + + + Create New Folder + 创建新文件夹 + + + + All Files (*.*) + 所有文件 (*.*) + + + + QFileSystemModel + + + %1 TB + %1 TB + + + + %1 GB + %1 GB + + + + %1 MB + %1 MB + + + + %1 KB + %1千字节 + + + + %1 bytes + %1字节 + + + + Invalid filename + 无效文件名 + + + + <b>The name "%1" can not be used.</b><p>Try using another name, with fewer characters or no punctuations marks. + <b>名称“%1“不能被使用。</b><p>请使用另外一个包含更少字符或者不含有标点符号的名称。 + + + + Name + 名称 + + + + Size + 大小 + + + + Kind + Match OS X Finder + 类型 + + + + Type + All other platforms + 类型 + + + + Date Modified + 日期被修改 + + + + My Computer + 我的计算机 + + + + Computer + 计算机 + + + + QFontDatabase + + + + Normal + 普通 + + + + + + Bold + 粗体 + + + + + Demi Bold + 半粗体 + + + + + + Black + 黑体 + + + + Demi + 半体 + + + + + Light + 轻体 + + + + + Italic + 意大利体 + + + + + Oblique + 斜体 + + + + Any + 任意 + + + + Latin + 拉丁文 + + + + Greek + 希腊文 + + + + Cyrillic + 西里尔文 + + + + Armenian + 亚美尼亚文 + + + + Hebrew + 希伯来文 + + + + Arabic + 阿拉伯文 + + + + Syriac + 叙利亚文 + + + + Thaana + 马尔代夫文 + + + + Devanagari + 梵文 + + + + Bengali + 孟加拉文 + + + + Gurmukhi + 旁遮普文 + + + + Gujarati + 古吉拉特文 + + + + Oriya + 奥里雅文 + + + + Tamil + 泰米尔文 + + + + Telugu + 泰卢固文 + + + + Kannada + 埃纳德文 + + + + Malayalam + 马拉亚拉姆文 + + + + Sinhala + 僧伽罗文 + + + + Thai + 泰国文 + + + + Lao + 老挝文 + + + + Tibetan + 藏文 + + + + Myanmar + 缅甸文 + + + + Georgian + 格鲁吉亚文 + + + + Khmer + 谷美尔文 + + + + Simplified Chinese + 简体中文 + + + + Traditional Chinese + 繁体中文 + + + + Japanese + 日文 + + + + Korean + 韩文 + + + + Vietnamese + 越南文 + + + + Symbol + 符号 + + + + Ogham + 欧甘文 + + + + Runic + 古北欧文 + + + + QFontDialog + + + &Font + 字体(&F) + + + + Font st&yle + 字体风格(&Y) + + + + &Size + 大小(&S) + + + + Effects + 效果 + + + + Stri&keout + 删除线(&K) + + + + &Underline + 下划线(&U) + + + + Sample + 实例 + + + + Wr&iting System + 书写系统(&I) + + + + + Select Font + 选择字体 + + + + QFtp + + + + Not connected + 没有连接 + + + + + Host %1 not found + 主机%1没有找到 + + + + + Connection refused to host %1 + 连接被主机 %1 拒绝 + + + + Connection timed out to host %1 + 主机%1连接超时 + + + + + + Connected to host %1 + 连接到主机%1了 + + + + + Connection refused for data connection + 因为数据连接而被拒绝连接 + + + + + + + Unknown error + 未知的错误 + + + + + Connecting to host failed: +%1 + 连接主机失败: +%1 + + + + + Login failed: +%1 + 登录失败: +%1 + + + + + Listing directory failed: +%1 + 列出目录失败: +%1 + + + + + Changing directory failed: +%1 + 改变目录失败: +%1 + + + + + Downloading file failed: +%1 + 下载文件失败: +%1 + + + + + Uploading file failed: +%1 + 上传文件失败: +%1 + + + + + Removing file failed: +%1 + 移除文件失败: +%1 + + + + + Creating directory failed: +%1 + 创建目录失败: +%1 + + + + + Removing directory failed: +%1 + 移除目录失败: +%1 + + + + + + Connection closed + 连接关闭了 + + + + Host %1 found + 主机%1找到了 + + + + Connection to %1 closed + 到%1的连接关闭了 + + + + Host found + 主机找到了 + + + + Connected to host + 连接到主机了 + + + + QGuiApplication + + + QT_LAYOUT_DIRECTION + Translate this string to the string 'LTR' in left-to-right languages or to 'RTL' in right-to-left languages (such as Hebrew and Arabic) to get proper widget layout. + LTR + + + + QHostInfo + + + Unknown error + 未知的错误 + + + + QHostInfoAgent + + + + + + + + + + Host not found + 主机未找到 + + + + + + + Unknown address type + 未知的地址类型 + + + + + + Unknown error + 未知的错误 + + + + QHttp + + + + + + Unknown error + 未知的错误 + + + + + Request aborted + 请求被放弃了 + + + + + No server set to connect to + 没有设置要连接的服务器 + + + + + Wrong content length + 错误的内容长度 + + + + + Server closed connection unexpectedly + 服务器异常地关闭了连接 + + + + Unknown authentication method + + + + + Error writing response to device + 向设备中进行写回复时发生错误 + + + + + Connection refused + 连接被拒绝 + + + + + + Host %1 not found + 主机%1没有找到 + + + + + + + HTTP request failed + HTTP请求失败 + + + + + Invalid HTTP response header + 无效的HTTP响应头 + + + + + + + Invalid HTTP chunked body + 无效的HTTP臃肿体 + + + + Host %1 found + 主机%1找到了 + + + + Connected to host %1 + 连接到%1主机了 + + + + Connection to %1 closed + 到%1的连接关闭了 + + + + Host found + 主机找到了 + + + + Connected to host + 连接到主机了 + + + + + Connection closed + 连接关闭了 + + + + Proxy authentication required + 代理需要认证 + + + + Authentication required + 需要认证 + + + + Connection refused (or timed out) + 连接被拒绝(或者超时) + + + + Proxy requires authentication + 代理需要验证 + + + + Host requires authentication + 主机需要验证 + + + + Data corrupted + 数据错误 + + + + Unknown protocol specified + 所指定的协议是未知的 + + + + SSL handshake failed + SSL 握手失败 + + + + HTTPS connection requested but SSL support not compiled in + HTTPS 连接需要 SSL,但它没有被编译进来 + + + + QHttpSocketEngine + + + Did not receive HTTP response from proxy + 未收到代理的HTTP响应 + + + + Error parsing authentication request from proxy + 解析代理的认证请求出错 + + + + Authentication required + 需要认证 + + + + Proxy denied connection + 代理拒绝连接 + + + + Error communicating with HTTP proxy + 和HTTP代理通讯时发生错误 + + + + Proxy server not found + 未找到代理服务器 + + + + Proxy connection refused + 代理连接被拒绝 + + + + Proxy server connection timed out + 代理服务器连接超时 + + + + Proxy connection closed prematurely + 代理连接过早关闭 + + + + QIBaseDriver + + + Error opening database + 打开数据库错误 + + + + Could not start transaction + 不能开始事务 + + + + Unable to commit transaction + 不能提交事务 + + + + Unable to rollback transaction + 不能回滚事务 + + + + QIBaseResult + + + Unable to create BLOB + 不能创建BLOB + + + + Unable to write BLOB + 不能写入BLOB + + + + Unable to open BLOB + 不能打开BLOB + + + + Unable to read BLOB + 不能读取BLOB + + + + + Could not find array + 不能找到数组 + + + + Could not get array data + 不能得到数组数据 + + + + Could not get query info + 不能得到查询信息 + + + + Could not start transaction + 不能开始事务 + + + + Unable to commit transaction + 不能提交事务 + + + + Could not allocate statement + 不能分配语句 + + + + Could not prepare statement + 不能准备语句 + + + + + Could not describe input statement + 不能描述输入语句 + + + + Could not describe statement + 不能描述语句 + + + + Unable to close statement + 不能关闭语句 + + + + Unable to execute query + 不能执行查询 + + + + Could not fetch next item + 不能获取下一项 + + + + Could not get statement info + 不能得到语句信息 + + + + QIODevice + + + Permission denied + 权限被拒绝 + + + + Too many open files + 太多打开的文件 + + + + No such file or directory + 没有这个文件或者目录 + + + + No space left on device + 设备上没有空间了 + + + + Unknown error + 未知的错误 + + + + QInputContext + + + XIM + XIM + + + + XIM input method + XIM输入法 + + + + Windows input method + Windows输入法 + + + + Mac OS X input method + Mac OS X输入法 + + + + QInputDialog + + + Enter a value: + 输入一个值: + + + + QLibrary + + QLibrary::load_sys: Cannot load %1 (%2) + QLibrary::load_sys: 不能载入%1 (%2) + + + QLibrary::unload_sys: Cannot unload %1 (%2) + QLibrary::unload_sys:不能卸载%1 (%2) + + + QLibrary::resolve_sys: Symbol "%1" undefined in %2 (%3) + QLibrary::resolve_sys: 符号“%1”在%2(%3)没有被定义 + + + + Could not mmap '%1': %2 + 不能映射”%1“:%2 + + + + Plugin verification data mismatch in '%1' + “%1“中的插件验证数据不匹配 + + + + Could not unmap '%1': %2 + 不能取消映射“%1“:%2 + + + + The plugin '%1' uses incompatible Qt library. (%2.%3.%4) [%5] + 插件“%1”使用了不兼容的Qt库。(%2.%3.%4) [%5] + + + + The plugin '%1' uses incompatible Qt library. Expected build key "%2", got "%3" + 插件“%1“使用了不兼容的Qt库。期待的构建键是“%2“,得到的却是”%3“ + + + + Unknown error + 未知的错误 + + + + + The shared library was not found. + 共享库没有被找到。 + + + + The file '%1' is not a valid Qt plugin. + 文件“%1“不是有效的Qt插件。 + + + + The plugin '%1' uses incompatible Qt library. (Cannot mix debug and release libraries.) + 插件“%1“使用了不兼容的Qt库。(不能混合使用库的调试版本和发布版本。) + + + + + Cannot load library %1: %2 + 无法加载库%1:%2 + + + + + Cannot unload library %1: %2 + 无法卸载库%1:%2 + + + + + Cannot resolve symbol "%1" in %2: %3 + 无法解析%2中的符号“%1”:%3 + + + + QLineEdit + + + &Undo + 撤消(&U) + + + + &Redo + 恢复(&R) + + + + Cu&t + 剪切(&T) + + + + &Copy + 复制(&C) + + + + &Paste + 粘贴(&P) + + + + Delete + 删除 + + + + Select All + 选择全部 + + + + QLocalServer + + + + %1: Name error + %1: 名称错误 + + + + %1: Permission denied + %1:权限被拒绝 + + + + %1: Address in use + %1:地址正在被使用 + + + + + %1: Unknown error %2 + %1:未知错误 %2 + + + + QLocalSocket + + + + %1: Connection refused + %1:连接被拒绝 + + + + + %1: Remote closed + %1:远程已关闭 + + + + + + + %1: Invalid name + %1:无效名称 + + + + + %1: Socket access error + %1:套接字访问错误 + + + + + %1: Socket resource error + %1:套接字资源错误 + + + + + %1: Socket operation timed out + %1:套接字操作超时 + + + + + %1: Datagram too large + %1:数据报太大 + + + + + + %1: Connection error + %1:连接错误 + + + + + %1: The socket operation is not supported + %1:套接字操作不被支持 + + + + %1: Unknown error + %1:未知错误 + + + + + %1: Unknown error %2 + %1:未知错误 %2 + + + + QMYSQLDriver + + + Unable to open database ' + 不能打开数据库 + + + + Unable to connect + 不能连接 + + + + Unable to begin transaction + 不能开始事务 + + + + Unable to commit transaction + 不能提交事务 + + + + Unable to rollback transaction + 不能回滚事务 + + + + QMYSQLResult + + + Unable to fetch data + 不能获取数据 + + + + Unable to execute query + 不能执行查询 + + + + Unable to store result + 不能存储结果 + + + + + Unable to prepare statement + 不能准备语句 + + + + Unable to reset statement + 不能重置语句 + + + + Unable to bind value + 不能绑定值 + + + + Unable to execute statement + 不能执行语句 + + + + + Unable to bind outvalues + 不能绑定外值 + + + + Unable to store statement results + 不能存储语句结果 + + + + Unable to execute next query + 不能执行下一个查询 + + + + Unable to store next result + 不能存储下一个结果 + + + + QMdiArea + + + (Untitled) + (未命名的) + + + + QMdiSubWindow + + + %1 - [%2] + %1 - [%2] + + + + Close + 关闭 + + + + Minimize + 最小化 + + + + Restore Down + 向下恢复 + + + + &Restore + 恢复(&R) + + + + &Move + 移动(&M) + + + + &Size + 大小(&S) + + + + Mi&nimize + 最小化(&N) + + + + Ma&ximize + 最大化(&X) + + + + Stay on &Top + 总在最前(&T) + + + + &Close + 关闭(&C) + + + + - [%1] + - [%1] + + + + Maximize + 最大化 + + + + Unshade + 取消遮蔽 + + + + Shade + 遮蔽 + + + + Restore + 恢复 + + + + Help + 帮助 + + + + Menu + 菜单 + + + + QMenu + + + + Close + 关闭 + + + + + Open + 打开 + + + + + + Execute + 执行 + + + + QMenuBar + + About + 关于 + + + Config + 配置 + + + Preference + 首选项 + + + Options + 选项 + + + Setting + 设置 + + + Setup + 安装 + + + Quit + 退出 + + + Exit + 退出 + + + About %1 + 关于%1 + + + About Qt + 关于Qt + + + Preferences + 首选项 + + + Quit %1 + 退出%1 + + + + QMessageBox + + + Help + 帮助 + + + + + + + OK + 确定 + + + + About Qt + 关于Qt + + + <p>This program uses Qt version %1.</p> + <p>这个程序使用的是Qt %1版。</p> + + + + Show Details... + 显示细节…… + + + + Hide Details... + 隐藏细节…… + + + + <h3>About Qt</h3><p>This program uses Qt version %1.</p><p>Qt is a C++ toolkit for cross-platform application development.</p><p>Qt provides single-source portability across MS&nbsp;Windows, Mac&nbsp;OS&nbsp;X, Linux, and all major commercial Unix variants. Qt is also available for embedded devices as Qt for Embedded Linux and Qt for Windows CE.</p><p>Qt is available under three different licensing options designed to accommodate the needs of our various users.</p>Qt licensed under our commercial license agreement is appropriate for development of proprietary/commercial software where you do not want to share any source code with third parties or otherwise cannot comply with the terms of the GNU LGPL version 2.1 or GNU GPL version 3.0.</p><p>Qt licensed under the GNU LGPL version 2.1 is appropriate for the development of Qt applications (proprietary or open source) provided you can comply with the terms and conditions of the GNU LGPL version 2.1.</p><p>Qt licensed under the GNU General Public License version 3.0 is appropriate for the development of Qt applications where you wish to use such applications in combination with software subject to the terms of the GNU GPL version 3.0 or where you are otherwise willing to comply with the terms of the GNU GPL version 3.0.</p><p>Please see <a href="http://qt.nokia.com/products/licensing">qt.nokia.com/products/licensing</a> for an overview of Qt licensing.</p><p>Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).</p><p>Qt is a Nokia product. See <a href="http://qt.nokia.com/">qt.nokia.com</a> for more information.</p> + + + + <h3>About Qt</h3>%1<p>Qt is a C++ toolkit for cross-platform application development.</p><p>Qt provides single-source portability across MS&nbsp;Windows, Mac&nbsp;OS&nbsp;X, Linux, and all major commercial Unix variants. Qt is also available for embedded devices as Qt for Embedded Linux and Qt for Windows CE.</p><p>Qt is a Nokia product. See <a href="http://qt.nokia.com/">qt.nokiae.com</a> for more information.</p> + <h3>关于Qt</h3>%1<p>Qt是一个用于跨平台应用程序开发的C++工具包。</p><p>对于MS&nbsp;Windows、Mac&nbsp;OS&nbsp;X、Linux和所有主流商业Unix,Qt提供了单一源程序的可移植性。Qt也有用于嵌入式Linux和Windows CE的版本。</p><p>Qt是Nokia的产品。有关更多信息,请参考<a href="http://qt.nokia.com/">qt.nokia.com</a>。</p> + + + <p>This program uses Qt Open Source Edition version %1.</p><p>Qt Open Source Edition is intended for the development of Open Source applications. You need a commercial Qt license for development of proprietary (closed source) applications.</p><p>Please see <a href="http://qt.nokia.com/company/model/">qt.nokia.com/company/model/</a> for an overview of Qt licensing.</p> + <p>这个程序使用了Qt %1开源版本。</p><p>Qt开源版本只用于开源应用程序的开发。如果要开发私有(闭源)软件,你需要一个商业的Qt协议。</p><p>有关Qt协议的概览,请参考<a href="http://qt.nokia.com/company/model/">qt.nokia.com/company/model/</a>。</p> + + + <h3>About Qt</h3>%1<p>Qt is a C++ toolkit for cross-platform application development.</p><p>Qt provides single-source portability across MS&nbsp;Windows, Mac&nbsp;OS&nbsp;X, Linux, and all major commercial Unix variants. Qt is also available for embedded devices as Qt Embedded.</p><p>Qt is a Trolltech product. See <a href="http://qt.nokia.com/">qt.nokia.com</a> for more information.</p> + <h3>关于Qt</h3>%1<p>Qt是一个用于跨平台应用程序开发的C++工具包。</p><p>对于MS&nbsp;Windows、Mac&nbsp;OS&nbsp;X、Linux和所有主流商业Unix,Qt提供了单一源程序的可移植性。Qt对于嵌入式平台也是可用的,在嵌入式平台上它被称为Qt Embedded。</p><p>Qt是Trolltech的产品。有关更多信息,请参考<a href="http://qt.nokia.com/">qt.nokia.com</a>。</p> + + + + QMultiInputContext + + + Select IM + 选择输入法 + + + + QMultiInputContextPlugin + + + Multiple input method switcher + 多输入法切换器 + + + + Multiple input method switcher that uses the context menu of the text widgets + 使用文本窗口部件上下文菜单的多输入法切换器 + + + + QNativeSocketEngine + + + The remote host closed the connection + 远端主机关闭了这个连接 + + + + Network operation timed out + 网络操作超时 + + + + Out of resources + 资源耗尽了 + + + + Unsupported socket operation + 不被支持的套接字操作 + + + + Protocol type not supported + 协议类型不被支持 + + + + Invalid socket descriptor + 无效的套接字描述符 + + + + Network unreachable + 网络不能访问 + + + + Permission denied + 权限被拒绝 + + + + Connection timed out + 连接超时 + + + + Connection refused + 连接被拒绝 + + + + The bound address is already in use + 要启用的地址已经被使用 + + + + The address is not available + 这个地址不可用 + + + + The address is protected + 这个地址被保护了 + + + + Unable to send a message + 不能发送一个消息 + + + + Unable to receive a message + 不能接收一个消息 + + + + Unable to write + 不能写入 + + + + Network error + 网络错误 + + + + Another socket is already listening on the same port + 另一个套接字已经正在监听同一端口 + + + + Unable to initialize non-blocking socket + 不能初始化非阻塞套接字 + + + + Unable to initialize broadcast socket + 不能初始化广播套接字 + + + + Attempt to use IPv6 socket on a platform with no IPv6 support + 试图在不支持IPv6支持的平台上使用IPv6套接字 + + + + Host unreachable + 主机不能访问 + + + + Datagram was too large to send + 不能发送过大的数据报 + + + + Operation on non-socket + 对非套接字操作 + + + + Unknown error + 未知的错误 + + + + The proxy type is invalid for this operation + 对于这个操作代理类型是无效的。 + + + + QNetworkAccessCacheBackend + + + Error opening %1 + 打开%1发生错误 + + + + QNetworkAccessFileBackend + + + Request for opening non-local file %1 + 正在打开非本地文件 %1 的请求 + + + + Error opening %1: %2 + 打开 %1 错误:%2 + + + + Write error writing to %1: %2 + 写入 %1 错误:%2 + + + + Cannot open %1: Path is a directory + 无法打开 %1:路径是一个目录 + + + + Read error reading from %1: %2 + 读取 %1 错误:%2 + + + + QNetworkAccessFtpBackend + + + No suitable proxy found + 未找到合适的代理 + + + + Cannot open %1: is a directory + 无法读取 %1:是一个目录 + + + + Logging in to %1 failed: authentication required + 登入 %1 失败:需要验证 + + + + Error while downloading %1: %2 + 下载 %1 时错误:%2 + + + + Error while uploading %1: %2 + 上载 %1 时错误:%2 + + + + QNetworkAccessHttpBackend + + + No suitable proxy found + 未找到合适的代理 + + + + QNetworkReply + + + Error downloading %1 - server replied: %2 + 下载 %1 错误 - 服务器回复:%2 + + + + Protocol "%1" is unknown + 协议“%1”是未知的 + + + + QNetworkReplyImpl + + + + Operation canceled + 操作被取消 + + + + QOCIDriver + + + Unable to logon + 不能登录 + + + + Unable to initialize + QOCIDriver + 不能初始化 + + + + Unable to begin transaction + 不能开始事务 + + + + Unable to commit transaction + 不能提交事务 + + + + Unable to rollback transaction + 不能回滚事务 + + + + QOCIResult + + + + + Unable to bind column for batch execute + 不能绑定批处理执行的列 + + + + Unable to execute batch statement + 不能执行批处理语句 + + + + Unable to goto next + 不能进入下一个 + + + + Unable to alloc statement + 不能分配语句 + + + + Unable to prepare statement + 不能准备语句 + + + + Unable to bind value + 不能绑定值 + + + Unable to execute select statement + 不能执行选择语句 + + + + Unable to execute statement + 不能执行语句 + + + + QODBCDriver + + + Unable to connect + 不能连接 + + + + Unable to connect - Driver doesn't support all needed functionality + 不能连接—驱动程序不支持所有功能 + + + + Unable to disable autocommit + 不能禁止自动提交 + + + + Unable to commit transaction + 不能提交事务 + + + + Unable to rollback transaction + 不能回滚事务 + + + + Unable to enable autocommit + 不能打开自动提交 + + + + QODBCResult + + + + QODBCResult::reset: Unable to set 'SQL_CURSOR_STATIC' as statement attribute. Please check your ODBC driver configuration + QODBCResult::reset: 不能把“SQL_CURSOR_STATIC”设置为语句属性。请检查你的ODBC驱动程序设置。 + + + + + Unable to execute statement + 不能执行语句 + + + + Unable to fetch next + 不能获取下一个 + + + + Unable to prepare statement + 不能准备语句 + + + + Unable to bind variable + 不能帮定变量 + + + + + + Unable to fetch last + 不能获取最后一个 + + + + Unable to fetch + 不能获取 + + + + Unable to fetch first + 不能获取第一个 + + + + Unable to fetch previous + 不能获取上一个 + + + + QObject + + + Home + + + + + Operation not supported on %1 + 在 %1 上不被支持的操作 + + + + Invalid URI: %1 + 无效的 URI:%1 + + + + Write error writing to %1: %2 + 写入 %1 错误:%2 + + + + Read error reading from %1: %2 + 读取 %1 错误:%2 + + + + Socket error on %1: %2 + %1 上的套接字错误:%2 + + + + Remote host closed the connection prematurely on %1 + 远程主机过早地关闭了在 %1 上的这个连接 + + + + Protocol error: packet of size 0 received + 协议错误:收到了大小为 0 的包 + + + + + No host name given + 未指定主机名 + + + + QPPDOptionsModel + + + Name + 名称 + + + + Value + + + + + QPSQLDriver + + + Unable to connect + 不能连接 + + + + Could not begin transaction + 不能开始事务 + + + + Could not commit transaction + 不能提交事务 + + + + Could not rollback transaction + 不能回滚事务 + + + + Unable to subscribe + 不能订阅 + + + + Unable to unsubscribe + 不能取消订阅 + + + + QPSQLResult + + + Unable to create query + 不能创建查询 + + + + Unable to prepare statement + 不能准备语句 + + + + QPageSetupWidget + + + Centimeters (cm) + 厘米 (cm) + + + + Millimeters (mm) + 毫米 (mm) + + + + Inches (in) + 英寸 (in) + + + + Points (pt) + 点 (pt) + + + + Form + 窗体 + + + + Paper + 纸张 + + + + Page size: + 纸张大小: + + + + Width: + 宽度: + + + + Height: + 高度: + + + + Paper source: + 纸张源: + + + + Orientation + 方向 + + + + Portrait + 纵向 + + + + Landscape + 横向 + + + + Reverse landscape + 反向横向 + + + + Reverse portrait + 反向纵向 + + + + Margins + 边距 + + + + top margin + 上边距 + + + + left margin + 左边距 + + + + right margin + 右边距 + + + + bottom margin + 下边距 + + + + QPluginLoader + + + Unknown error + 未知的错误 + + + + The plugin was not loaded. + 插件没有被载入。 + + + + QPrintDialog + + + locally connected + 本地已经连接的 + + + + + Aliases: %1 + 别名:%1 + + + + + unknown + 未知的 + + + + Print all + 打印全部 + + + + Print selection + 打印选择 + + + + Print range + 打印范围 + + + + A0 (841 x 1189 mm) + A0 (841 x 1189 毫米) + + + + A1 (594 x 841 mm) + A1 (594 x 841 毫米) + + + + A2 (420 x 594 mm) + A2 (420 x 594 毫米) + + + + A3 (297 x 420 mm) + A3 (297 x 420 毫米) + + + + A4 (210 x 297 mm, 8.26 x 11.7 inches) + A4 (210 x 297 毫米,8.26 x 11.7 英寸) + + + + A5 (148 x 210 mm) + A5 (148 x 210 毫米) + + + + A6 (105 x 148 mm) + A6 (105 x 148 毫米) + + + + A7 (74 x 105 mm) + A7 (74 x 105 毫米) + + + + A8 (52 x 74 mm) + A8 (52 x 74 毫米) + + + + A9 (37 x 52 mm) + A9 (37 x 52 毫米) + + + + B0 (1000 x 1414 mm) + B0 (1000 x 1414 毫米) + + + + B1 (707 x 1000 mm) + B1 (707 x 1000 毫米) + + + + B2 (500 x 707 mm) + B2 (500 x 707 毫米) + + + + B3 (353 x 500 mm) + B3 (353 x 500 毫米) + + + + B4 (250 x 353 mm) + B4 (250 x 353 毫米) + + + + B5 (176 x 250 mm, 6.93 x 9.84 inches) + B5 (176 x 250 毫米,6.93 x 9.84 英寸) + + + + B6 (125 x 176 mm) + B6 (125 x 176 毫米) + + + + B7 (88 x 125 mm) + B7 (88 x 125 毫米) + + + + B8 (62 x 88 mm) + B8 (62 x 88 毫米) + + + + B9 (44 x 62 mm) + B9 (44 x 62 毫米) + + + + B10 (31 x 44 mm) + B10 (31 x 44 毫米) + + + + C5E (163 x 229 mm) + C5E (163 x 229 毫米) + + + + DLE (110 x 220 mm) + DLE (110 x 220 毫米) + + + + Executive (7.5 x 10 inches, 191 x 254 mm) + Executive (7.5 x 10 英寸,191 x 254 毫米) + + + + Folio (210 x 330 mm) + Folio (210 x 330 毫米) + + + + Ledger (432 x 279 mm) + Ledger (432 x 279 毫米) + + + + Legal (8.5 x 14 inches, 216 x 356 mm) + Legal (8.5 x 14 英寸,216 x 356 毫米) + + + + Letter (8.5 x 11 inches, 216 x 279 mm) + Letter (8.5 x 11 英寸,216 x 279 毫米) + + + + Tabloid (279 x 432 mm) + Tabloid (279 x 432 毫米) + + + + US Common #10 Envelope (105 x 241 mm) + 美国普通10号信封 (105 x 241 毫米) + + + + OK + 确定 + + + + + + Print + 打印 + + + + Print To File ... + 打印到文件…… + + + + File %1 is not writable. +Please choose a different file name. + 文件%1不可写。 +请选择一个不同的文件名。 + + + + %1 already exists. +Do you want to overwrite it? + %1已经存在。 +你想覆盖它么? + + + + File exists + 文件存在 + + + + <qt>Do you want to overwrite it?</qt> + <qt>你想覆盖它么?</qt> + + + + %1 is a directory. +Please choose a different file name. + %1是目录。 +请选择一个不同的文件名。 + + + + The 'From' value cannot be greater than the 'To' value. + “从”的数值不能大于“到”的数值。 + + + + A0 + A0 + + + + A1 + A1 + + + + A2 + A2 + + + + A3 + A3 + + + + A4 + A4 + + + + A5 + A5 + + + + A6 + A6 + + + + A7 + A7 + + + + A8 + A8 + + + + A9 + A9 + + + + B0 + B0 + + + + B1 + B1 + + + + B2 + B2 + + + + B3 + B3 + + + + B4 + B4 + + + + B5 + B5 + + + + B6 + B6 + + + + B7 + B7 + + + + B8 + B8 + + + + B9 + B9 + + + + B10 + B10 + + + + C5E + C5E + + + + DLE + DLE + + + + Executive + 决策文书 + + + + Folio + 对开纸 + + + + Ledger + 帐页 + + + + Legal + 法律文书 + + + + Letter + 信纸 + + + + Tabloid + 小型报纸 + + + + US Common #10 Envelope + 美国普通10号信封 + + + + Custom + 自定义 + + + + + &Options >> + 选项(&O) >> + + + + &Print + 打印(&P) + + + + &Options << + 选项(&O) << + + + + Print to File (PDF) + 打印到文件(PDF) + + + + Print to File (Postscript) + 打印到文件(Postscript) + + + + Local file + 本地文件 + + + + Write %1 file + 写入 %1 文件 + + + + QPrintPreviewDialog + + + + Page Setup + 页面设置 + + + + %1% + %1% + + + + Print Preview + 打印预览 + + + + Next page + 下一页 + + + + Previous page + 上一页 + + + + First page + 第一页 + + + + Last page + 最后一页 + + + + Fit width + 适应宽度 + + + + Fit page + 适应页面 + + + + Zoom in + 放大 + + + + Zoom out + 缩小 + + + + Portrait + 纵向 + + + + Landscape + 横向 + + + + Show single page + 显示单页 + + + + Show facing pages + 显示当前页 + + + + Show overview of all pages + 显示所有页的概览 + + + + Print + 打印 + + + + Page setup + 打印设置 + + + + Close + 关闭 + + + + Export to PDF + 导出为PDF + + + + Export to PostScript + 导出为PostScript + + + + QPrintPropertiesWidget + + + Form + 窗体 + + + + Page + + + + + Advanced + 高级 + + + + QPrintSettingsOutput + + + Form + 窗体 + + + + Copies + 拷贝 + + + + Print range + 打印范围 + + + + Print all + 打印全部 + + + + Pages from + 页数从 + + + + to + + + + + Selection + 选择 + + + + Output Settings + 输出设置 + + + + Copies: + 备份: + + + + Collate + 校对 + + + + Reverse + 反向 + + + + Options + 选项 + + + + Color Mode + 彩色模式 + + + + Color + 彩色 + + + + Grayscale + 灰度 + + + + Duplex Printing + 两部分打印 + + + + None + + + + + Long side + 长侧 + + + + Short side + 短侧 + + + + QPrintWidget + + + Form + 窗体 + + + + Printer + 打印机 + + + + &Name: + 名称(&N): + + + + P&roperties + 属性(&R) + + + + Location: + 位置: + + + + Preview + 预览 + + + + Type: + 类型: + + + + Output &file: + 输出文件(&F): + + + + ... + ... + + + + QProcess + + + + Could not open input redirection for reading + 无法打开用于读取的输入重定向 + + + + + Could not open output redirection for writing + 无法打开用于写入的输出重定向 + + + + Resource error (fork failure): %1 + 资源错误(fork失败):%1 + + + + + + + + + + + + Process operation timed out + 进程处理超时 + + + + + + + Error reading from process + 从进程中读取时发生错误 + + + + + + Error writing to process + 向进程写入时发生错误 + + + + Process crashed + 进程已崩溃 + + + + No program defined + + + + + Process failed to start + 启动进程失败 + + + + QProgressDialog + + + Cancel + 撤消 + + + + QPushButton + + + Open + 打开 + + + + QRadioButton + + + Check + 选中 + + + + QRegExp + + + no error occurred + 没有错误发生 + + + + disabled feature used + 使用了失效的特效 + + + + bad char class syntax + 错误的字符类语法 + + + + bad lookahead syntax + 错误的预测语法 + + + + bad repetition syntax + 错误的重复语法 + + + + invalid octal value + 无效的八进制数值 + + + + missing left delim + 找不到左分隔符 + + + + unexpected end + 意外的终止 + + + + met internal limit + 遇到内部限制 + + + + QSQLite2Driver + + + Error to open database + 打开数据库错误 + + + + Unable to begin transaction + 不能开始事务 + + + + Unable to commit transaction + 不能提交事务 + + + + Unable to rollback Transaction + 不能回滚事务 + + + + QSQLite2Result + + + Unable to fetch results + 不能获取结果 + + + + Unable to execute statement + 不能执行语句 + + + + QSQLiteDriver + + + Error opening database + 打开数据库错误 + + + + Error closing database + 关闭数据库错误 + + + + Unable to begin transaction + 不能开始事务 + + + + Unable to commit transaction + 不能提交事务 + + + + Unable to rollback transaction + 不能回滚事务 + + + + QSQLiteResult + + + + + Unable to fetch row + 不能获取行 + + + + Unable to execute statement + 不能执行语句 + + + + Unable to reset statement + 不能重置语句 + + + + Unable to bind parameters + 不能绑定参数 + + + + Parameter count mismatch + 参数数量不匹配 + + + + No query + 没有查询 + + + + QScrollBar + + + Scroll here + 滚动到这里 + + + + Left edge + 左边缘 + + + + Top + 顶部 + + + + Right edge + 右边缘 + + + + Bottom + 底部 + + + + Page left + 左一页 + + + + + Page up + 上一页 + + + + Page right + 右一页 + + + + + Page down + 下一页 + + + + Scroll left + 向左滚动 + + + + Scroll up + 向上滚动 + + + + Scroll right + 向右滚动 + + + + Scroll down + 向下滚动 + + + + Line up + 向上排列 + + + + Position + 位置 + + + + Line down + 向下排列 + + + + QSharedMemory + + + %1: unable to set key on lock + %1:无法设置锁定的键 + + + + %1: create size is less then 0 + %1:创建的大小小于 0 + + + + + %1: unable to lock + %1:无法锁定 + + + + %1: unable to unlock + %1:无法取消锁定 + + + + + %1: permission denied + %1:权限被拒绝 + + + + + %1: already exists + %1:已经存在 + + + + + %1: doesn't exists + %1:不存在 + + + + + %1: out of resources + %1:资源耗尽了 + + + + + %1: unknown error %2 + %1:未知错误 %2 + + + + %1: key is empty + %1:键是空的 + + + + %1: unix key file doesn't exists + %1:Unix 键文件不存在 + + + + %1: ftok failed + %1:ftok 失败 + + + + + %1: unable to make key + %1:不能制造键 + + + + %1: system-imposed size restrictions + %1:系统预设大小限制 + + + + %1: not attached + %1:没有附加 + + + + %1: invalid size + %1:无效大小 + + + + %1: key error + %1: 键错误 + + + + %1: size query failed + %1:大小查询失败 + + + + QShortcut + + + Space + 空格 + + + + Esc + Esc + + + + Tab + Tab + + + + Backtab + Backtab + + + + Backspace + Backspace + + + + Return + Return + + + + Enter + Enter + + + + Ins + Ins + + + + Del + Del + + + + Pause + Pause + + + + Print + Print + + + + SysReq + SysReq + + + + Home + Home + + + + End + End + + + + Left + Left + + + + Up + Up + + + + Right + Right + + + + Down + Down + + + + PgUp + PgUp + + + + PgDown + PgDown + + + + CapsLock + CapsLock + + + + NumLock + NumLock + + + + ScrollLock + ScrollLock + + + + Menu + Menu + + + + Help + Help + + + + Back + 后退 + + + + Forward + 前进 + + + + Stop + 停止 + + + + Refresh + 刷新 + + + + Volume Down + 调小音量 + + + + Volume Mute + 静音 + + + + Volume Up + 调大音量 + + + + Bass Boost + 低音增强 + + + + Bass Up + 调大低音 + + + + Bass Down + 调小低音 + + + + Treble Up + 调大高音 + + + + Treble Down + 调小高音 + + + + Media Play + 多媒体播放 + + + + Media Stop + 多媒体停止 + + + + Media Previous + 上一个多媒体 + + + + Media Next + 下一个多媒体 + + + + Media Record + 多媒体记录 + + + + Favorites + 最喜爱的 + + + + Search + 搜索 + + + + Standby + 等待 + + + + Open URL + 打开URL + + + + Launch Mail + 启动邮件 + + + + Launch Media + 启动多媒体 + + + + Launch (0) + 启动 (0) + + + + Launch (1) + 启动 (1) + + + + Launch (2) + 启动 (2) + + + + Launch (3) + 启动 (3) + + + + Launch (4) + 启动 (4) + + + + Launch (5) + 启动 (5) + + + + Launch (6) + 启动 (6) + + + + Launch (7) + 启动 (7) + + + + Launch (8) + 启动 (8) + + + + Launch (9) + 启动 (9) + + + + Launch (A) + 启动 (A) + + + + Launch (B) + 启动 (B) + + + + Launch (C) + 启动 (C) + + + + Launch (D) + 启动 (D) + + + + Launch (E) + 启动 (E) + + + + Launch (F) + 启动 (F) + + + + Print Screen + Print Screen + + + + Page Up + Page Up + + + + Page Down + Page Down + + + + Caps Lock + Caps Lock + + + + Num Lock + Num Lock + + + + Number Lock + Number Lock + + + + Scroll Lock + Scroll Lock + + + + Insert + Insert + + + + Delete + Delete + + + + Escape + Escape + + + + System Request + System Request + + + + Select + 选择 + + + + Yes + + + + + No + + + + + Context1 + 上下文1 + + + + Context2 + 上下文2 + + + + Context3 + 上下文3 + + + + Context4 + 上下文4 + + + + Call + 呼叫 + + + + Hangup + 挂起 + + + + Flip + 翻转 + + + + + Ctrl + Ctrl + + + + + Shift + Shift + + + + + Alt + Alt + + + + + Meta + Meta + + + + + + + + + + + F%1 + F%1 + + + + Home Page + 主页 + + + + QSlider + + + Page left + 左一页 + + + + Page up + 上一页 + + + + Position + 位置 + + + + Page right + 右一页 + + + + Page down + 下一页 + + + + QSocks5SocketEngine + + + Connection to proxy refused + 代理拒绝连接 + + + + Connection to proxy closed prematurely + 代理连接过早关闭 + + + + Proxy host not found + 代理主机未找到 + + + + Connection to proxy timed out + 代理连接超时 + + + + Proxy authentication failed + 代理认证失败 + + + + Proxy authentication failed: %1 + 代理认证失败: %1 + + + + SOCKS version 5 protocol error + SOCKS版本5协议错误 + + + + General SOCKSv5 server failure + 常规服务器失败 + + + + Connection not allowed by SOCKSv5 server + 连接不被SOCKSv5服务器允许 + + + + TTL expired + TTL已过期 + + + + SOCKSv5 command not supported + 不支持的SOCKSv5命令 + + + + Address type not supported + 不支持的地址类型 + + + + Unknown SOCKSv5 proxy error code 0x%1 + 未知SOCKSv5代理,错误代码 0x%1 + + + Socks5 timeout error connecting to socks server + 连接到套接字服务器的时候,Socks5超时错误 + + + + Network operation timed out + 网络操作超时 + + + + QSpinBox + + + More + 更多 + + + + Less + 更少 + + + + QSql + + + Delete + 删除 + + + + Delete this record? + 删除这条记录? + + + + + + Yes + + + + + + + No + + + + + Insert + 插入 + + + + Update + 更新 + + + + Save edits? + 保存编辑? + + + + Cancel + 取消 + + + + Confirm + 确认 + + + + Cancel your edits? + 取消您的编辑? + + + + QSslSocket + + + Unable to write data: %1 + 不能写入数据:%1 + + + + Error while reading: %1 + 读取时错误:%1 + + + + Error during SSL handshake: %1 + SSL握手错误:%1 + + + + Error creating SSL context (%1) + 创建SSL上下文错误(%1) + + + + Invalid or empty cipher list (%1) + 无效或者空白的密码列表(%1) + + + + Error creating SSL session, %1 + 创建SSL会话错误,%1 + + + + Error creating SSL session: %1 + 创建SSL会话错误:%1 + + + + Cannot provide a certificate with no key, %1 + 不能提供没有键的证书,%1 + + + + Error loading local certificate, %1 + 不能载入本地证书,%1 + + + + Error loading private key, %1 + 不能载入私有键,%1 + + + + Private key does not certificate public key, %1 + 私有键不能验证公有键,%1 + + + + QSystemSemaphore + + + + %1: out of resources + %1:资源耗尽了 + + + + + %1: permission denied + %1:权限被拒绝 + + + + %1: already exists + %1:已经存在 + + + + %1: does not exist + %1:不存在 + + + + + %1: unknown error %2 + %1:未知错误 %2 + + + + QTDSDriver + + + Unable to open connection + 不能打开连接 + + + + Unable to use database + 不能使用数据库 + + + + QTabBar + + + Scroll Left + 向左滚动 + + + + Scroll Right + 向右滚动 + + + + QTcpServer + + + Operation on socket is not supported + socket操作不被支持 + + + + QTextControl + + + &Undo + 撤消(&U) + + + + &Redo + 恢复(&R) + + + + Cu&t + 剪切(&T) + + + + &Copy + 复制(&C) + + + + Copy &Link Location + 复制链接位置(&L) + + + + &Paste + 粘贴(&P) + + + + Delete + 删除 + + + + Select All + 选择全部 + + + + QToolButton + + + + Press + 按下 + + + + + Open + 打开 + + + + QUdpSocket + + + This platform does not support IPv6 + 这个平台不支持IPv6 + + + + QUndoGroup + + + Undo + 撤销 + + + + Redo + 恢复 + + + + QUndoModel + + + <empty> + <空白> + + + + QUndoStack + + + Undo + 撤销 + + + + Redo + 恢复 + + + + QUnicodeControlCharacterMenu + + + LRM Left-to-right mark + LRM 从左到右标记 + + + + RLM Right-to-left mark + RLM 从右向左标记 + + + + ZWJ Zero width joiner + ZWJ 零宽度连接器 + + + + ZWNJ Zero width non-joiner + ZWNJ 零宽度非连接器 + + + + ZWSP Zero width space + ZWSP 零宽度空格 + + + + LRE Start of left-to-right embedding + LRE 开始从左到右嵌入 + + + + RLE Start of right-to-left embedding + RLE 开始从右向左嵌入 + + + + LRO Start of left-to-right override + LRO 开始从左向右覆盖 + + + + RLO Start of right-to-left override + RLO 开始从右向左覆盖 + + + + PDF Pop directional formatting + PDF 弹出方向格式 + + + + Insert Unicode control character + 插入Unicode控制字符 + + + + QWebFrame + + + Request cancelled + 请求被取消了 + + + + Request blocked + 请求被阻塞了 + + + + Cannot show URL + 无法显示 URL + + + + Frame load interruped by policy change + 因为策略调整打断了桢的加载 + + + + Cannot show mimetype + 无法显示 MIMETYPE + + + + File does not exist + 文件不存在 + + + + QWebPage + + + Bad HTTP request + 错误的 HTTP 请求 + + + + Submit + default label for Submit buttons in forms on web pages + 提交 + + + + Submit + Submit (input element) alt text for <input> elements with no alt, title, or value + 提交 + + + + Reset + default label for Reset buttons in forms on web pages + 重置 + + + + This is a searchable index. Enter search keywords: + text that appears at the start of nearly-obsolete web pages in the form of a 'searchable index' + 这是一个可以搜索的索引。请输入要搜索的关键字: + + + + Choose File + title for file button used in HTML forms + 选择文件 + + + + No file selected + text to display in file button used in HTML forms when no file is selected + 没有文件被选择 + + + + Open in New Window + Open in New Window context menu item + 在新窗口中打开 + + + + Save Link... + Download Linked File context menu item + 保存链接... + + + + Copy Link + Copy Link context menu item + 复制链接 + + + + Open Image + Open Image in New Window context menu item + 打开图片 + + + + Save Image + Download Image context menu item + 保存图片 + + + + Copy Image + Copy Link context menu item + 复制图片 + + + + Open Frame + Open Frame in New Window context menu item + 打开框架 + + + + Copy + Copy context menu item + 复制 + + + + Go Back + Back context menu item + 后退 + + + + Go Forward + Forward context menu item + 前进 + + + + Stop + Stop context menu item + 停止 + + + + Reload + Reload context menu item + 重新载入 + + + + Cut + Cut context menu item + 剪切 + + + + Paste + Paste context menu item + 粘贴 + + + + No Guesses Found + No Guesses Found context menu item + 没有找到猜测 + + + + Ignore + Ignore Spelling context menu item + 忽略 + + + + Add To Dictionary + Learn Spelling context menu item + 添加到字典 + + + + Search The Web + Search The Web context menu item + 搜索网页 + + + + Look Up In Dictionary + Look Up in Dictionary context menu item + 在字典中查找 + + + + Open Link + Open Link context menu item + 打开链接 + + + + Ignore + Ignore Grammar context menu item + 忽略 + + + + Spelling + Spelling and Grammar context sub-menu item + 拼写 + + + + Show Spelling and Grammar + menu item title + 显示拼写和语法 + + + + Hide Spelling and Grammar + menu item title + 隐藏拼写和语法 + + + + Check Spelling + Check spelling context menu item + 检查拼写 + + + + Check Spelling While Typing + Check spelling while typing context menu item + 在输入时检查拼写 + + + + Check Grammar With Spelling + Check grammar with spelling context menu item + 检查语法和拼写 + + + + Fonts + Font context sub-menu item + 字体 + + + + Bold + Bold context menu item + 粗体 + + + + Italic + Italic context menu item + 意大利体 + + + + Underline + Underline context menu item + 下划线 + + + + Outline + Outline context menu item + 轮廓 + + + + Direction + Writing direction context sub-menu item + 方向 + + + + Text Direction + Text direction context sub-menu item + 文本方向 + + + + Default + Default writing direction context menu item + 默认 + + + + LTR + Left to Right context menu item + LTR + + + + RTL + Right to Left context menu item + RTL + + + + Inspect + Inspect Element context menu item + 检查 + + + + No recent searches + Label for only item in menu that appears when clicking on the search field image, when no searches have been performed + 没有最近的搜索 + + + + Recent searches + label for first item in the menu that appears when clicking on the search field image, used as embedded menu title + 最近的搜索 + + + + Clear recent searches + menu item in Recent Searches menu that empties menu's contents + 清除最近的搜索 + + + + Unknown + Unknown filesize FTP directory listing item + 未知的 + + + + %1 (%2x%3 pixels) + Title string for images + %1 (%2x%3 像素) + + + + Web Inspector - %2 + 网页检查员 - %2 + + + + Scroll here + 滚动到这里 + + + + Left edge + 左边缘 + + + + Top + 顶部 + + + + Right edge + 右边缘 + + + + Bottom + 底部 + + + + Page left + 左一页 + + + + Page up + 上一页 + + + + Page right + 右一页 + + + + Page down + 下一页 + + + + Scroll left + 向左滚动 + + + + Scroll up + 向上滚动 + + + + Scroll right + 向右滚动 + + + + Scroll down + 向下滚动 + + + + %n file(s) + number of chosen file + + %n 个文件 + + + + + JavaScript Alert - %1 + JavaScript警告 - %1 + + + + JavaScript Confirm - %1 + JavaScript确认 - %1 + + + + JavaScript Prompt - %1 + JavaScript提示 - %1 + + + + Move the cursor to the next character + 移动光标到下一个字符 + + + + Move the cursor to the previous character + 移动光标到上一个字符 + + + + Move the cursor to the next word + 移动光标到下一个单词 + + + + Move the cursor to the previous word + 移动光标到上一个单词 + + + + Move the cursor to the next line + 移动光标到下一行 + + + + Move the cursor to the previous line + 移动光标到上一行 + + + + Move the cursor to the start of the line + 移动光标到行首 + + + + Move the cursor to the end of the line + 移动光标到行尾 + + + + Move the cursor to the start of the block + 移动光标到块首 + + + + Move the cursor to the end of the block + 移动光标到块尾 + + + + Move the cursor to the start of the document + 移动光标到文件开头 + + + + Move the cursor to the end of the document + 移动光标到文件末尾 + + + + Select all + + + + + Select to the next character + 选中到下一个字符 + + + + Select to the previous character + 选中到上一个字符 + + + + Select to the next word + 选中到下一个单词 + + + + Select to the previous word + 选中到上一个单词 + + + + Select to the next line + 选中到下一行 + + + + Select to the previous line + 选中到上一行 + + + + Select to the start of the line + 选中到行首 + + + + Select to the end of the line + 选中到行尾 + + + + Select to the start of the block + 选中到块首 + + + + Select to the end of the block + 选中到块尾 + + + + Select to the start of the document + 选中到文件首 + + + + Select to the end of the document + 选中到文件尾 + + + + Delete to the start of the word + 删除到单词首 + + + + Delete to the end of the word + 删除到单词尾 + + + + Insert a new paragraph + + + + + Insert a new line + + + + + QWhatsThisAction + + + What's This? + 这是什么? + + + + QWidget + + + * + * + + + + QWizard + + + Go Back + 返回 + + + + Continue + 继续 + + + + Commit + 提交 + + + + Done + 完成 + + + Quit + 退出 + + + + Help + 帮助 + + + + < &Back + < 上一步(&B) + + + + &Finish + 完成(&F) + + + + Cancel + 取消 + + + + &Help + 帮助(&H) + + + + &Next + 下一步(&N) + + + + &Next > + 下一步(&N) > + + + + QWorkspace + + + &Restore + 恢复(&R) + + + + &Move + 移动(&M) + + + + &Size + 大小(&S) + + + + Mi&nimize + 最小化(&N) + + + + Ma&ximize + 最大化(&X) + + + + &Close + 关闭(&C) + + + + Stay on &Top + 总在最前(&T) + + + + + Sh&ade + 卷起(&A) + + + + + %1 - [%2] + %1 - [%2] + + + + Minimize + 最小化 + + + + Restore Down + 恢复 + + + + Close + 关闭 + + + + &Unshade + 展开(&U) + + + + QXml + + + no error occurred + 没有错误发生 + + + + error triggered by consumer + 由消费者出发的错误 + + + + unexpected end of file + 意外的文件终止 + + + + more than one document type definition + 多于一个的文档类型定义 + + + + error occurred while parsing element + 在解析元素的时候发生错误 + + + + tag mismatch + 标记不匹配 + + + + error occurred while parsing content + 在解析内容的时候发生错误 + + + + unexpected character + 意外的字符 + + + + invalid name for processing instruction + 无效的处理指令名称 + + + + version expected while reading the XML declaration + 在读取XML声明的时候,版本被期待 + + + + wrong value for standalone declaration + 错误的独立声明的值 + + + + encoding declaration or standalone declaration expected while reading the XML declaration + 在读取XML声明的时候,编码声明或者独立声明被期待 + + + + standalone declaration expected while reading the XML declaration + 在读取XML声明的时候,独立声明被期待 + + + + error occurred while parsing document type definition + 在解析文档类型定义的时候发生错误 + + + + letter is expected + 字符被期待 + + + + error occurred while parsing comment + 在解析注释的时候发生错误 + + + + error occurred while parsing reference + 在解析参考的时候发生错误 + + + + internal general entity reference not allowed in DTD + 在DTD中不允许使用内部解析的通用实体参考 + + + + external parsed general entity reference not allowed in attribute value + 在属性值中不允许使用外部解析的通用实体参考 + + + + external parsed general entity reference not allowed in DTD + 在DTD中不允许使用外部解析的通用实体参考 + + + + unparsed entity reference in wrong context + 没有解析的错误上下文中的实体参考 + + + + recursive entities + 嵌套实体 + + + + error in the text declaration of an external entity + 在一个外部实体的文本声明里有错误 + + + + QXmlStream + + + + Extra content at end of document. + 文档末尾有额外内容。 + + + + Invalid entity value. + 无效的实体值。 + + + + Invalid XML character. + 无效的XML字符。 + + + + Sequence ']]>' not allowed in content. + 内容中不允许有“]]>“序列。 + + + + Namespace prefix '%1' not declared + 命名空间的”%1“前缀没有被声明 + + + + Attribute redefined. + 属性重复定义。 + + + + Unexpected character '%1' in public id literal. + 在公有标识文本中有意外的字符”%1“。 + + + + Invalid XML version string. + 无效的XML版本字符串。 + + + + Unsupported XML version. + 不被支持的XML版本。 + + + + %1 is an invalid encoding name. + %1是无效的编码名称。 + + + + Encoding %1 is unsupported + 编码%1不被支持。 + + + + Standalone accepts only yes or no. + 独立运行只允许是或者否。 + + + + Invalid attribute in XML declaration. + 在XML声明中无效的属性。 + + + + Premature end of document. + 文档过早的结束。 + + + + Invalid document. + 无效的文档。 + + + + Expected + 期待的 + + + + , but got ' + ,但是得到的是“ + + + + Unexpected ' + 意外的“ + + + + Expected character data. + 期待的字符数据。 + + + + Recursive entity detected. + 检测到嵌套实体。 + + + + Start tag expected. + 开始期待的标记。 + + + + XML declaration not at start of document. + XML声明没有在文档的开始位置。 + + + + NDATA in parameter entity declaration. + 在参数实体声明中有NDATA。 + + + + %1 is an invalid processing instruction name. + %1 是无效的处理指令名称。 + + + + Invalid processing instruction name. + 无效的处理指令名称。 + + + + + + + Illegal namespace declaration. + 非法的命名空间声明。 + + + + Invalid XML name. + 无效的XML名称。 + + + + Opening and ending tag mismatch. + 开始标记和结束标记不匹配。 + + + + Reference to unparsed entity '%1'. + 未解析实体“%1“的引用。 + + + + + + Entity '%1' not declared. + 实体”%1“没有被声明。 + + + + Reference to external entity '%1' in attribute value. + 在属性值中的外部实体“%1”的引用。 + + + + Invalid character reference. + 无效的字符引用。 + + + + + Encountered incorrectly encoded content. + 遇到不正确的编码内容。 + + + + The standalone pseudo attribute must appear after the encoding. + 独立运行伪属性必须出现在编码之后。 + + + + %1 is an invalid PUBLIC identifier. + %1是一个无效的公有(PUBLIC)标识符。 + + + + QtXmlPatterns + + + An %1-attribute with value %2 has already been declared. + 带有值 %2 的 %1 属性已经声明过了。 + + + + An %1-attribute must have a valid %2 as value, which %3 isn't. + 一个 %1 属性必须带有一个有效的 %2 作为值,但 %3 却不是。 + + + + Network timeout. + 网络超时。 + + + + Element %1 can't be serialized because it appears outside the document element. + 元素 %1 不能被串行化,因为它出现在文档元素之外。 + + + Attribute element %1 can't be serialized because it appears at the top level. + 属性元素 %1 不能被串行化,因为它出现在最顶层。 + + + + Year %1 is invalid because it begins with %2. + %1 年是无效的,因为应该从 %2 开始。 + + + + Day %1 is outside the range %2..%3. + %1 日是在 %2...%3 范围之外的。 + + + + Month %1 is outside the range %2..%3. + %1 月是在 %2...%3 范围之外的。 + + + + Overflow: Can't represent date %1. + 溢出:无法呈现数据 %1。 + + + + Day %1 is invalid for month %2. + %1 日对于 %2 月是无效的。 + + + + Time 24:%1:%2.%3 is invalid. Hour is 24, but minutes, seconds, and milliseconds are not all 0; + 时间 24:%1:%2.%3 是无效的。小时是 24,但是分钟、秒和毫秒不全为 0; + + + + Time %1:%2:%3.%4 is invalid. + 时间 %1:%2:%3.%4 是无效的。 + + + + Overflow: Date can't be represented. + 溢出:数据无法被呈现。 + + + + + At least one component must be present. + 至少有一个组件被呈现。 + + + + At least one time component must appear after the %1-delimiter. + 至少一个时间组件必须出现在这个 %1 界限之后。 + + + + No operand in an integer division, %1, can be %2. + 在整数除法中没有操作数,%1,可以是 %2。 + + + + The first operand in an integer division, %1, cannot be infinity (%2). + 除法中的第一个操作数,%1,不能是无穷(%2)。 + + + + The second operand in a division, %1, cannot be zero (%2). + 除法中的第二个操作数,%1,不能是零(%2)。 + + + + %1 is not a valid value of type %2. + %1 不是类型为 %2 的有效值。 + + + + When casting to %1 from %2, the source value cannot be %3. + 当从 %2 抛出到 %1 时,源值不能是 %3。 + + + + Integer division (%1) by zero (%2) is undefined. + 整数除法(%1)除零(%2)是未定义的。 + + + + Division (%1) by zero (%2) is undefined. + 除法(%1)除零(%2)是未定义的。 + + + + Modulus division (%1) by zero (%2) is undefined. + 求模除法(%1)除零(%2)是未定义的。 + + + + + Dividing a value of type %1 by %2 (not-a-number) is not allowed. + 一个类型为 %1 的值除以 %2(不是一个数值)是不允许的。 + + + + Dividing a value of type %1 by %2 or %3 (plus or minus zero) is not allowed. + 一个类型为 %1 的值除以 %2 或者 %3(正负零)是不允许的。 + + + + Multiplication of a value of type %1 by %2 or %3 (plus or minus infinity) is not allowed. + 一个类型为 %1 的值乘以 %2 或者 %3(正负无穷)是不允许的。 + + + + A value of type %1 cannot have an Effective Boolean Value. + 一个类型为 %1 的值不能是一个有效的布尔值(Effective Boolean Value)。 + + + + Effective Boolean Value cannot be calculated for a sequence containing two or more atomic values. + 有效的布尔值(Effective Boolean Value)不能被用于计算一个包含两个或者更多原子值的序列。 + + + + Value %1 of type %2 exceeds maximum (%3). + 类型为 %2 的值 %1 超过了最大值(%3)。 + + + + Value %1 of type %2 is below minimum (%3). + 类型为 %2 的值 %1 超过了最小值(%3)。 + + + + A value of type %1 must contain an even number of digits. The value %2 does not. + 类型为 %1 的值必须包含偶数个数字。值 %2 不是这样的。 + + + + %1 is not valid as a value of type %2. + %1 不是类型为 %2 的有效值。 + + + + Operator %1 cannot be used on type %2. + 操作符 %1 不能被用于类型 %2。 + + + + Operator %1 cannot be used on atomic values of type %2 and %3. + 操作符 %1 不能被用于类型为 %2 和 %3 的原子值。 + + + + The namespace URI in the name for a computed attribute cannot be %1. + 一个被计算的属性的名称中的命名空间 URI 不能是 %1。 + + + + The name for a computed attribute cannot have the namespace URI %1 with the local name %2. + 一个被计算的属性的名称不能使用带有本地名称 %2 的命名空间 URI %1。 + + + + Type error in cast, expected %1, received %2. + 抛出类型错误,期望的是 %1,收到的是 %2。 + + + + When casting to %1 or types derived from it, the source value must be of the same type, or it must be a string literal. Type %2 is not allowed. + 当抛出到 %1 或者它的派生类时,源类型必须是同一类型,或者它必须是一个字符串类型。类型 %2 是不被允许的。 + + + + No casting is possible with %1 as the target type. + 无法以 %1 为目标类型进行抛出。 + + + + It is not possible to cast from %1 to %2. + 无法从 %1 抛出到 %2。 + + + + Casting to %1 is not possible because it is an abstract type, and can therefore never be instantiated. + 无法抛出到 %1,因为它是一个抽象类型,并且因此无法被实例化。 + + + + It's not possible to cast the value %1 of type %2 to %3 + 无法从类型为 %2 的值 %1 抛出到 %3 + + + + Failure when casting from %1 to %2: %3 + 从 %2 抛出到 %1 失败:%3 + + + + A comment cannot contain %1 + 注释不能包含 %1 + + + + A comment cannot end with a %1. + 注释不能以 %1 结尾。 + + + + No comparisons can be done involving the type %1. + 对于类型 %1 不能进行比较。 + + + + Operator %1 is not available between atomic values of type %2 and %3. + 在类型 %2 和 %3 的原子值之间,操作符 %1 是不可用的。 + + + + An attribute node cannot be a child of a document node. Therefore, the attribute %1 is out of place. + 一个属性节点不能是一个文档节点的子节点。因此,这个属性 %1 所在位置是不合适的。 + + + + A library module cannot be evaluated directly. It must be imported from a main module. + 一个库模块不能被直接评估。它必须从一个主模块中导入。 + + + + No template by name %1 exists. + 没有名为 %1 的模板存在。 + + + + A value of type %1 cannot be a predicate. A predicate must have either a numeric type or an Effective Boolean Value type. + 类型为 %1 的值不能被判断。一个判断必须是数值类型或者一个有效的布尔值(Effective Boolean Value)类型。 + + + + A positional predicate must evaluate to a single numeric value. + 一个定位判断必须评估一个单一数值。 + + + + The target name in a processing instruction cannot be %1 in any combination of upper and lower case. Therefore, is %2 invalid. + 一个处理指令中的目标名称不能是任何大小写混合的 %1。因此,%2 是无效的。 + + + + %1 is not a valid target name in a processing instruction. It must be a %2 value, e.g. %3. + %1 不是处理指令的有效目标名称。它必须是值 %2,例如 %3。 + + + + The last step in a path must contain either nodes or atomic values. It cannot be a mixture between the two. + 一个路径中的最后一步必须包含节点或者原子值。它不能是两者的一个组合。 + + + + The data of a processing instruction cannot contain the string %1 + 处理指令的数据不能包含字符串 %1 + + + + No namespace binding exists for the prefix %1 + 对于前缀 %1,没有存在绑定的命名空间。 + + + + No namespace binding exists for the prefix %1 in %2 + 对于 %2 中的前缀 %1,没有存在绑定的命名空间。 + + + + + %1 is an invalid %2 + %1 是一个无效的 %2。 + + + + %1 takes at most %n argument(s). %2 is therefore invalid. + + %1 最多可以有 %n 个参数。因此 %2 是无效的。 + + + + + %1 requires at least %n argument(s). %2 is therefore invalid. + + %1 需要至少 %n 个参数。因此 %2 是无效的。 + + + + + The first argument to %1 cannot be of type %2. It must be a numeric type, xs:yearMonthDuration or xs:dayTimeDuration. + %1 的第一个参数不能是类型 %2 的。它必须是数字类型的,xs:yearMonthDuration 或者 xs:dayTimeDuration。 + + + + The first argument to %1 cannot be of type %2. It must be of type %3, %4, or %5. + %1 的第一个参数不能是类型 %2 的。它必须是类型 %3、%4 或者 %5 的。 + + + + The second argument to %1 cannot be of type %2. It must be of type %3, %4, or %5. + %1 的第二个参数不能是类型 %2 的。它必须是类型 %3、%4 或者 %5 的。 + + + + %1 is not a valid XML 1.0 character. + %1 不是一个有效的 XML 1.0 字符。 + + + + The first argument to %1 cannot be of type %2. + %1 的第一个参数不能是类型 %2 的。 + + + + If both values have zone offsets, they must have the same zone offset. %1 and %2 are not the same. + 如果两个值都有区偏移(zone offset),它们必须拥有相同的区偏移。%1 和 %2 的区偏移是不同的。 + + + + %1 was called. + %1 被调用了。 + + + + %1 must be followed by %2 or %3, not at the end of the replacement string. + %1 必须被 %2 或者 %3 跟随,不能在替换字符串的末尾。 + + + + In the replacement string, %1 must be followed by at least one digit when not escaped. + 在这个替换字符串中,%1 在没有被转义的时候必须被至少一个数字跟随。 + + + + In the replacement string, %1 can only be used to escape itself or %2, not %3 + 在这个替换字符串中,%1 只能被用于转义它本身或者 %2,而不是 %3 + + + + %1 matches newline characters + %1 匹配了换行符 + + + + %1 and %2 match the start and end of a line. + %1 和 %2 匹配了一行的头和尾。 + + + + Matches are case insensitive + 匹配是大小写不敏感的 + + + + Whitespace characters are removed, except when they appear in character classes + 空白字符被移除了,除非当它们出现在字符类中 + + + + %1 is an invalid regular expression pattern: %2 + %1 是正则表达式中的一个无效模式:%2 + + + + %1 is an invalid flag for regular expressions. Valid flags are: + %1 是正则表达式中的一个无效标记。有效标记为: + + + + If the first argument is the empty sequence or a zero-length string (no namespace), a prefix cannot be specified. Prefix %1 was specified. + 如果第一个参数是空序列或者零长度字符串(无命名空间),那么就不能指定前缀。前缀 %1 被指定了。 + + + + It will not be possible to retrieve %1. + 将不能获取 %1。 + + + + The root node of the second argument to function %1 must be a document node. %2 is not a document node. + 函数 %1 的第二个参数的根节点必须是一个文档节点。%2 不是一个文档节点。 + + + + The default collection is undefined + 默认收集(collection)是未定义的 + + + + %1 cannot be retrieved + 无法获取 %1 + + + + The normalization form %1 is unsupported. The supported forms are %2, %3, %4, and %5, and none, i.e. the empty string (no normalization). + 不支持正规化(normalization)表单 %1。被支持的表单是 %2、%3、%4 和 %5,以及无,例如空字符串(无正规化)。 + + + + A zone offset must be in the range %1..%2 inclusive. %3 is out of range. + 区偏移(zone offset)必须在 %1...%2 范围之内。%3 是在范围之外的。 + + + + %1 is not a whole number of minutes. + %1 不是分钟的整数。 + + + + Required cardinality is %1; got cardinality %2. + 所需要的表间关系是 %1;得到的表间关系却是 %2。 + + + + The item %1 did not match the required type %2. + 项 %1 和所需的类型 %2 不匹配。 + + + + + %1 is an unknown schema type. + %1 是一个未知的方案类型。 + + + + Only one %1 declaration can occur in the query prolog. + 只有一个 %1 的声明可以出现在查询序言中。 + + + + The initialization of variable %1 depends on itself + 变量 %1 的初始化依赖于它本身 + + + + No variable by name %1 exists + 没有名称为 %1 的变量存在。 + + + + The variable %1 is unused + 变量 %1 没有被使用 + + + + Version %1 is not supported. The supported XQuery version is 1.0. + 不支持版本 %1。被支持的 XQuery 版本是 1.0。 + + + + The encoding %1 is invalid. It must contain Latin characters only, must not contain whitespace, and must match the regular expression %2. + 编码方式 %1 是无效的。它必须只包含拉丁字符,必须不包含空白符号,并且必须和正则表达式 %2 匹配。 + + + + No function with signature %1 is available + 没有签名为 %1 的可用函数。 + + + + + A default namespace declaration must occur before function, variable, and option declarations. + 默认命名空间声明必须出现在函数、变量和选项声明之前。 + + + + Namespace declarations must occur before function, variable, and option declarations. + 命名空间声明必须出现在函数、变量和选项声明之前。 + + + + Module imports must occur before function, variable, and option declarations. + 模块导入不能出现在函数、变量和选项声明之前。 + + + + It is not possible to redeclare prefix %1. + 不能重复声明前缀 %1。 + + + Only the prefix %1 can be declared to bind the namespace %2. By default, it is already bound to the prefix %1. + 至于前缀 %1 可以被声明为和命名空间 %2 绑定。默认情况下,它已经被绑定到前缀 %1。 + + + + Prefix %1 is already declared in the prolog. + 前缀 %1 在序言中已经声明过了。 + + + + The name of an option must have a prefix. There is no default namespace for options. + 一个选项的名称必须带有前缀。对于选项没有默认命名空间。 + + + + The Schema Import feature is not supported, and therefore %1 declarations cannot occur. + 不支持方案导入(Schema Import)特性,并且因此 %1 声明不能出现。 + + + + The target namespace of a %1 cannot be empty. + %1 的目标命名空间不能为空。 + + + + The module import feature is not supported + 不支持模块导入特性 + + + A variable by name %1 has already been declared in the prolog. + 名称为 %1 的变量已经在序言中声明过了。 + + + + No value is available for the external variable by name %1. + 名称为 %1 的外部变量并没有可用的值。 + + + The namespace for a user defined function cannot be empty(try the predefined prefix %1 which exists for cases like this) + 用户定义的函数的命名空间不能为空(请试试预定义的前缀 %1,它就是用于这种情况的)。 + + + + A construct was encountered which only is allowed in XQuery. + 遇到了一个只允许在XQuery中出现的构造。 + + + + A template by name %1 has already been declared. + 模板%1已被声明 + + + + The keyword %1 cannot occur with any other mode name. + 任何其他模式名称不能出现关键字%1。 + + + + The value of attribute %1 must of type %2, which %3 isn't. + 属性%1的值必须是类型%2,但%3不是。 + + + + The prefix %1 can not be bound. By default, it is already bound to the namespace %2. + 前缀%1不能被绑定。默认的,它已被绑定到名字空间%2。 + + + + A variable by name %1 has already been declared. + 变量%1已被声明。 + + + + A stylesheet function must have a prefixed name. + 样式表函数必须有一个前缀名。 + + + + The namespace for a user defined function cannot be empty (try the predefined prefix %1 which exists for cases like this) + 用户定义函数的名字空间不能为空(试用为这种情况而存在的预定义前缀%1) + + + + The namespace %1 is reserved; therefore user defined functions may not use it. Try the predefined prefix %2, which exists for these cases. + 命名空间 %1 是保留的;因此用户定义的函数不能使用它。请试试预定义的前缀 %2,它就是用于这种情况的。 + + + + The namespace of a user defined function in a library module must be equivalent to the module namespace. In other words, it should be %1 instead of %2 + 用户在一个库模块中定义的函数的命名空间必须和这个模块的命名空间一致。也就是说,它应该是 %1,而不是 %2 + + + + A function already exists with the signature %1. + 一个带有签名 %1 的函数已经存在。 + + + + No external functions are supported. All supported functions can be used directly, without first declaring them as external + 不支持外部函数。所有支持的函数必须可以被直接使用,不能把它们声明为外部的 + + + + An argument by name %1 has already been declared. Every argument name must be unique. + 名称为 %1 的参数已经被声明了。每个参数名称必须唯一。 + + + + When function %1 is used for matching inside a pattern, the argument must be a variable reference or a string literal. + 当函数%1被用于样式匹配时,参数必须是变量参考或者字符串。 + + + + In an XSL-T pattern, the first argument to function %1 must be a string literal, when used for matching. + 在XSL-T样式中,函数%1的第一个参数必须是字符串,以便用于匹配。 + + + + In an XSL-T pattern, the first argument to function %1 must be a literal or a variable reference, when used for matching. + 在XSL-T样式中,函数%1的第一个参数必须是文字或者变量参考,以便用于匹配。 + + + + In an XSL-T pattern, function %1 cannot have a third argument. + 在XSL-T样式中,函数%1不能有第三个参数。 + + + + In an XSL-T pattern, only function %1 and %2, not %3, can be used for matching. + 在XSL-T样式中,只用函数%1和%2可以用于匹配,%3不可以。 + + + + In an XSL-T pattern, axis %1 cannot be used, only axis %2 or %3 can. + 在XSL-T仰视中,不能使用%1轴,只能使用%2轴或者%3轴。 + + + + %1 is an invalid template mode name. + %1不是一个合法的模板模式名称。 + + + + The name of a variable bound in a for-expression must be different from the positional variable. Hence, the two variables named %1 collide. + 一个在 for 表达式中绑定的变量的名称必须和这个定位变量不同。因此,这两个名称为 %1 的变量冲突。 + + + + The Schema Validation Feature is not supported. Hence, %1-expressions may not be used. + 不支持方案验证特性(Schema Validation Feature)。因此,也许不能使用 %1 表达式。 + + + + None of the pragma expressions are supported. Therefore, a fallback expression must be present + 不支持任何编译指示表达式(pragma expression)。因此,必须呈现一个回调表达式(fallback expression)。 + + + + Each name of a template parameter must be unique; %1 is duplicated. + 每一个模板参数的名称都必须是唯一的;%2是重复的。 + + + + The %1-axis is unsupported in XQuery + 这个 %1 轴在 XQuery 中是不被支持的。 + + + + %1 is not a valid name for a processing-instruction. + %1不是一个处理指令的合法名称。 + + + + %1 is not a valid numeric literal. + %1 不是一个有效的数字语义。 + + + + No function by name %1 is available. + 没有名称为 %1 的可用函数。 + + + + The namespace URI cannot be the empty string when binding to a prefix, %1. + 当这个命名空间 URI 被绑定到一个前缀 %1 时,它不能是空字符串。 + + + + %1 is an invalid namespace URI. + %1 是一个无效的命名空间 URI。 + + + + It is not possible to bind to the prefix %1 + 无法绑定到这个前缀 %1。 + + + + Namespace %1 can only be bound to %2 (and it is, in either case, pre-declared). + 命名空间 %1 只能和 %2 绑定(并且如果是这种情况,需要提前声明)。 + + + + Prefix %1 can only be bound to %2 (and it is, in either case, pre-declared). + 前缀 %1 只能和 %2 绑定(并且如果是这种情况,需要提前声明)。 + + + + Two namespace declaration attributes have the same name: %1. + 两个命名空间声明属性使用了相同的名称:%1。 + + + + The namespace URI must be a constant and cannot use enclosed expressions. + 命名空间 URI 必须是一个常量并且不能使用封闭的表达式。 + + + + An attribute by name %1 has already appeared on this element. + 一个名称为 %1 的属性已经出现在这个元素中了。 + + + + A direct element constructor is not well-formed. %1 is ended with %2. + 一个直接元素构造器没有很好地形成。%1 后面跟着 %2。 + + + + The name %1 does not refer to any schema type. + 名称 %1 没有指向任何方案类型。 + + + + %1 is an complex type. Casting to complex types is not possible. However, casting to atomic types such as %2 works. + %1 是一个复杂类型。无法抛出到复杂类型。因此,抛出到例如 %2 这样的原子类型是可以的。 + + + + %1 is not an atomic type. Casting is only possible to atomic types. + %1 不是原子类型。只能抛出到原子类型。 + + + %1 is not a valid name for a processing-instruction. Therefore this name test will never match. + %1 不是处理指令的有效名称。因此这个名称测试永远不会匹配。 + + + + + %1 is not in the in-scope attribute declarations. Note that the schema import feature is not supported. + %1 不是范围内属性声明。注意方案导入特性是不被支持的。 + + + + The name of an extension expression must be in a namespace. + 一个扩展表达式的名称必须在一个命名空间中。 + + + + empty + 空白 + + + + zero or one + 零或者一 + + + + exactly one + 确切地一 + + + + one or more + 一或者更多 + + + + zero or more + 零或者更多 + + + + Required type is %1, but %2 was found. + 需要的类型是 %1,但是找到的是 %2。 + + + + Promoting %1 to %2 may cause loss of precision. + 把 %1 升级为 %2 会导致精度的损失。 + + + + The focus is undefined. + 焦点未定义。 + + + + It's not possible to add attributes after any other kind of node. + 不能在任何其它类型节点后添加属性。 + + + + An attribute by name %1 has already been created. + 一个名称为 %1 的属性已经被创建。 + + + + Only the Unicode Codepoint Collation is supported(%1). %2 is unsupported. + 只支持 Unicode 代码点校验(Unicode Codepoint Collation)(%1)。%2 是不被支持的。 + + + + Attribute %1 can't be serialized because it appears at the top level. + 属性 %1 不能被串行化,因为它出现在最顶层。 + + + + %1 is an unsupported encoding. + %1 是不被支持的编码。 + + + + %1 contains octets which are disallowed in the requested encoding %2. + %1包含了在请求编码%2中不允许的八进位值。 + + + + The codepoint %1, occurring in %2 using encoding %3, is an invalid XML character. + 在使用编码%3的%2中出现的代码点%1不是一个有效的XML字符。 + + + + Ambiguous rule match. + 含糊规则匹配。 + + + In a namespace constructor, the value for a namespace value cannot be an empty string. + 在一个命名空间构造中,命名空间的值不能为空字符串。 + + + + In a namespace constructor, the value for a namespace cannot be an empty string. + + + + + The prefix must be a valid %1, which %2 is not. + 前缀必须是有效的%1,而%2不是。 + + + + The prefix %1 cannot be bound. + 前缀%1不能被绑定。 + + + + Only the prefix %1 can be bound to %2 and vice versa. + 只有前缀%1可以绑定到%2,反之也一样 + + + + Circularity detected + 检测到环 + + + + The parameter %1 is required, but no corresponding %2 is supplied. + 需要参数%1,但是没有提供对应的%2。 + + + + The parameter %1 is passed, but no corresponding %2 exists. + 参数%1已传递,但没有相应的%2存在。 + + + + The URI cannot have a fragment + URI不能有片段 + + + + Element %1 is not allowed at this location. + 元素%1不能在这个位置。 + + + + Text nodes are not allowed at this location. + 文本节点不能在这个位置。 + + + + Parse error: %1 + 解析错误:%1 + + + + The value of the XSL-T version attribute must be a value of type %1, which %2 isn't. + XSL-T版本属性的值必须是%1类型的值,而%2不是。 + + + + Running an XSL-T 1.0 stylesheet with a 2.0 processor. + 在XSL-T 2.0处理器中运行一个1.0的样式表。 + + + + Unknown XSL-T attribute %1. + 未知的XSL-T属性%1。 + + + + Attribute %1 and %2 are mutually exclusive. + 属性%1和%2彼此互斥。 + + + + In a simplified stylesheet module, attribute %1 must be present. + 在一个简化样式表模块中,属性%1必须存在。 + + + + If element %1 has no attribute %2, it cannot have attribute %3 or %4. + 如果元素%1没有属性%2,那么它也不能有属性%3或者%4。 + + + + Element %1 must have at least one of the attributes %2 or %3. + 元素%1必须至少有属性%2或者%3其中一个。 + + + + At least one mode must be specified in the %1-attribute on element %2. + 在元素%2的%1属性中至少要指定一个模式。 + + + + Attribute %1 cannot appear on the element %2. Only the standard attributes can appear. + 属性%1不能出现在元素%2上。只有标准属性可以出现。 + + + + Attribute %1 cannot appear on the element %2. Only %3 is allowed, and the standard attributes. + 属性%1不能出现在元素%2上。只有%3和标准属性是允许的。 + + + + Attribute %1 cannot appear on the element %2. Allowed is %3, %4, and the standard attributes. + 属性%1不能出现在元素%2上。只有%3、%4和标准属性是允许的。 + + + + Attribute %1 cannot appear on the element %2. Allowed is %3, and the standard attributes. + 属性%1不能出现在元素%2上。只有%3和标准属性是允许的。 + + + + XSL-T attributes on XSL-T elements must be in the null namespace, not in the XSL-T namespace which %1 is. + XSL-T元素中的XSL-T属性必须放在空(null)命名空间中,而不是在XSL-T命名空间中,%1却是这个样子。 + + + + The attribute %1 must appear on element %2. + 属性%1必须出现在元素%2中。 + + + + The element with local name %1 does not exist in XSL-T. + 有本地名称%1的元素在XSL-T中不存在。 + + + + Element %1 must come last. + 元素%1必须最后出现。 + + + + At least one %1-element must occur before %2. + 至少一个元素%1要出现在%2之前。 + + + + Only one %1-element can appear. + 只能出现一个元素%1。 + + + + At least one %1-element must occur inside %2. + 至少一个元素%1要出现在%2之内。 + + + + When attribute %1 is present on %2, a sequence constructor cannot be used. + 当属性%1出现在%2中时,不能使用顺序构造。 + + + + Element %1 must have either a %2-attribute or a sequence constructor. + 元素%1必须有在一个%2属性或者顺序构造。 + + + + When a parameter is required, a default value cannot be supplied through a %1-attribute or a sequence constructor. + 当需要参数时,不能通过属性%1或者顺序构造提供默认值。 + + + + Element %1 cannot have children. + 元素%1不能有子元素。 + + + + Element %1 cannot have a sequence constructor. + 元素%1不能有顺序构造。 + + + + + The attribute %1 cannot appear on %2, when it is a child of %3. + 属性%1不能出现在%2中,因为它是%3的子元素。 + + + + A parameter in a function cannot be declared to be a tunnel. + 函数内的参数不能被声明为通道(tunnel)。 + + + + This processor is not Schema-aware and therefore %1 cannot be used. + 这个处理器不能感知Schema,因此%1不能被使用。 + + + + Top level stylesheet elements must be in a non-null namespace, which %1 isn't. + 顶级样式表元素必须是在非空命名空间中的,而%1不是。 + + + + The value for attribute %1 on element %2 must either be %3 or %4, not %5. + 元素%2中属性%1的值必须是%3或者%4,而不是%5。 + + + + Attribute %1 cannot have the value %2. + 属性%1的值不能是%2。 + + + + The attribute %1 can only appear on the first %2 element. + 属性%1只能出现在前%2个元素中。 + + + + At least one %1 element must appear as child of %2. + %2必须至少又一个子元素%1。 + + + + VolumeSlider + + + Muted + 已静音 + + + + + Volume: %1% + 音量:%1% + + + + WebCore::PlatformScrollbar + + Scroll here + 滚动到这里 + + + Left edge + 左边缘 + + + Top + 顶部 + + + Right edge + 右边缘 + + + Bottom + 底部 + + + Page left + 左一页 + + + Page up + 上一页 + + + Page right + 右一页 + + + Page down + 下一页 + + + Scroll left + 向左滚动 + + + Scroll up + 向上滚动 + + + Scroll right + 向右滚动 + + + Scroll down + 向下滚动 + + + + QPlatformTheme + + OK + 确定 + + + &OK + 确定(&O) + + + Cancel + 取消 + + + &Cancel + 取消(&C) + + + Yes + + + + &Yes + 是(&Y) + + + No + + + + &No + 否(&N) + + + Yes to All + 应用到所有 + + + Yes to &All + 应用到所有(&A) + + + + QGnomeTheme + + OK + 确定 + + + &OK + 确定(&O) + + + Cancel + 取消 + + + &Cancel + 取消(&C) + + + Yes + + + + &Yes + 是(&Y) + + + No + + + + &No + 否(&N) + + + Yes to All + 应用到所有 + + + Yes to &All + 应用到所有(&A) + + + diff --git a/app/scanner/Scanner_zh_CN.qm b/app/scanner/Scanner_zh_CN.qm index 63141602..f57ab4a8 100644 Binary files a/app/scanner/Scanner_zh_CN.qm and b/app/scanner/Scanner_zh_CN.qm differ diff --git a/app/scanner/Scanner_zh_CN.ts b/app/scanner/Scanner_zh_CN.ts index 45be24f9..64dcf13c 100644 --- a/app/scanner/Scanner_zh_CN.ts +++ b/app/scanner/Scanner_zh_CN.ts @@ -1438,7 +1438,7 @@ This operation will NOT rotate the files that may contain multiple pages, such a 跳转至... - + pageIndex: 页数: @@ -2262,8 +2262,8 @@ bug description: - - + + Question 询问 @@ -2360,14 +2360,14 @@ Do you want to clear? - - - - - - - - + + + + + + + + Please wake up the device manually 请手动唤醒设备 @@ -2495,103 +2495,108 @@ Do you want to clear? 彩色 - + + Not supported + 不支持 + + + Warning 警告 - + Device is Running! Please finish scanning first. 设备正在运行! 请先结束扫描。 - + cache path folder limit:%1 无法访问当前缓存路径:%1 请尝试在【用户】菜单登录管理员账户,前往【缓存设置】更改缓存路径。 - + aquireinto folder limit:%1 无法访问当前缓存路径:%1 请尝试在【扫描到】更改缓存路径。 - + Image processing failed 图像处理失败 - + Ocr init failed OCR初始化错误 - + Ocr failed OCR错误 - + File does not exist 文件不存在 - + Failed to load dynamic library 加载动态库失败 - + File data error 文件数据错误 - + Image format processing error 图像格式处理错误 - + Out of memory 内存不足 - + Failed 错误 - - + + The language switch is successful and takes effect the next time the software is started! 语言切换成功,下次启动软件时生效! - + Are you sure to delete selected file? 您确定彻底删除选中项文件? - - - - - - - - + + + + + + + + already waked up device 已唤醒设备 - + be ready 就绪 @@ -2601,7 +2606,7 @@ Please finish scanning first. 请尝试在【用户】菜单登录管理员账户,前往【缓存设置】更改缓存路径 - + Insufficient access rights 文件访问权限不足 @@ -2614,46 +2619,46 @@ Please finish scanning first. 图像处理失败 - + Are you sure to close 您确定要断开设备: - + ? 吗? - - + + close 关闭 - + tip 提示 - + Other versions not available 未获取到其他版本 - - + + The device does not support this operation 设备不支持该操作 - - + + IO error IO错误 - - + + error 错误 @@ -2668,17 +2673,17 @@ Continue to close? 是否继续关闭? - + Sure to sign out administrator account? 是否确定登出管理员账户? - + confirm the operation 确认操作 - + Are you sure to clear the rollor acount? 你确定要清除滚轴计数吗 @@ -2687,36 +2692,36 @@ Continue to close? 请重新进入关于界面以获取最新值 - - + + <p>%1: <a href='%2'>%3</a> - - + + <p>%1: %2 - + roller number 滚轴张数 - + open scanner 打开扫描仪 - - + + app name 华高扫描软件 - - + + success 成功 @@ -2733,22 +2738,22 @@ Continue to close? 失败 - - + + failed 失败 - + warning 警告 - + the disk space in the current path is unsufficient, please select a new path or clear the disk space in time. 当前路径磁盘空间不足, 请重新选择路径或及时清理磁盘空间。 @@ -2758,7 +2763,7 @@ Continue to close? 配置丢失 - + apply setting 应用配置 @@ -2766,18 +2771,18 @@ Continue to close? - - - - - - - - - - - - + + + + + + + + + + + + start failed 启动失败 @@ -2939,12 +2944,12 @@ Continue to close? 保存图片文件失败: - + start failed! 启动安装程序失败! - + There are pictures that have not been saved. Are you sure to close? 有图像未保存,确定关闭? @@ -2964,54 +2969,54 @@ Are you sure to close? - - - - + + + + tips 提示 - + Are you sure to close? 确定关闭应用软件? - + confirm operation 确认操作 - + are you sure to clear the roller count? 您确定要清除滚轴计数吗 - - - + + + hint 提示 - - + + Roller scanned count has been set to 0. 辊轴计数已置零 - - + + Roller scanned count reset failed. 重置滚轴计数失败 - + Error 错误 - + Document missing! It would be deleted or renamed. 文档丢失!文档可能已被删除或被重命名。 @@ -3052,21 +3057,21 @@ Are you sure to close? <p>%1</p><p>版本: %2<br>版权: &#169; %3</p><p>%4%5%6%7%8%9</p> - - + + about %1 关于 %1 - - + + <p>Version: %1</p> <p>版本: %1</p> <p>版本: %1</p> - - + + <p>CopyRight: &#169; %1</p> <p>版权: &#169; %1</p> <p>版权: &#169; %1</p> diff --git a/app/scanner/Scanner_zh_EN.qm b/app/scanner/Scanner_zh_EN.qm index 3fc4c424..a063164a 100644 Binary files a/app/scanner/Scanner_zh_EN.qm and b/app/scanner/Scanner_zh_EN.qm differ diff --git a/app/scanner/Scanner_zh_EN.ts b/app/scanner/Scanner_zh_EN.ts index 52896a58..bedc410f 100644 --- a/app/scanner/Scanner_zh_EN.ts +++ b/app/scanner/Scanner_zh_EN.ts @@ -1359,7 +1359,7 @@ This operation will not rotate files that may include multiple pages.Jump to... - + pageIndex: Page number: @@ -2195,8 +2195,8 @@ Please make sure the two passwords are the same. - - + + Question Ask @@ -2249,7 +2249,7 @@ Please make sure the two passwords are the same. - + the disk space in the current path is unsufficient, please select a new path or clear the disk space in time. Insufficient disk space for the current path. Please reselect a path or clear disk space immediately. @@ -2257,7 +2257,7 @@ Please reselect a path or clear disk space immediately. - + warning Warning @@ -2317,46 +2317,46 @@ Please reselect a path or clear disk space immediately. - - - - - - - - - - - - + + + + + + + + + + + + start failed Failed to start - - - - - - - - + + + + + + + + Please wake up the device manually Please wake up the device manually - - - - - - - - + + + + + + + + already waked up device Device is awake @@ -2412,10 +2412,10 @@ Clear? - - - - + + + + tips prompt @@ -2528,90 +2528,95 @@ Clear? Color - + + Not supported + Not supported + + + Warning Warning - + Device is Running! Please finish scanning first. Device is currently running! Please stop scanning first. - + There are pictures that have not been saved. Are you sure to close? There are unsaved images; are you sure you want to close? - + Are you sure to close? Are you sure you want to close? - + Sure to sign out administrator account? Are you sure you want to log out of the administrator account? - + confirm operation Confirm operation - + are you sure to clear the roller count? Are you sure you want to clear the roller count? - - - + + + hint Prompt - - + + Roller scanned count has been set to 0. Roller count reset to zero. - - + + Roller scanned count reset failed. Failed to reset roller count. - + Error Error - + Document missing! It would be deleted or renamed. File lost! File may be deleted or renamed. - + confirm the operation Confirm operation - + Are you sure to clear the rollor acount? Are you sure you want to clear the roller count? - + cache path folder limit:%1 Unable to access the current path:%1 Please try to log in to the administrator account in the [User] menu and go to the [Cache settings] to change the cache path. - + aquireinto folder limit:%1 Unable to access the current path:%1 Please try to change the cache path in [Scan to]. @@ -2625,76 +2630,76 @@ Please try to change the cache path in [Scan to]. <p>%1</p><p>Version: %2<br>Copyright: &#169; %3</p><p>%4%5%6%7%8%9</p> - - + + about %1 About %1 - - + + <p>Version: %1</p> <p>Version: %1</p> - - + + <p>CopyRight: &#169; %1</p> <p>Copyright: &#169; %1</p> - - + + <p>%1: <a href='%2'>%3</a> <p>%1: <a href='%2'>%3</a> - - + + <p>%1: %2 <p>%1: %2 - + roller number Number of rollers - + open scanner Open scanner - - + + app name HUAGOSCAN scanning software - - + + success successfully - + be ready Ready - - + + failed failed - - + + error Error - + start failed! Failed to start! @@ -2704,106 +2709,106 @@ Please try to change the cache path in [Scan to]. Please go to “Scan to” and change the accessible scan folder and then perform the scan. - + Insufficient access rights Insufficient file access permissions - + Image processing failed Image processing failed - + Ocr init failed OCR initialization error - + Ocr failed OCR failed - + File does not exist File does not exist - + Failed to load dynamic library Failed to load dynamic library - + File data error File data error - + Image format processing error Image format processing error - + Out of memory Insufficient memory - + Failed Failed - + apply setting Apply configuration - + Are you sure to close Are you sure you want to disconnect device: - + ? ? - - + + close Close - + tip Prompt - + Other versions not available No other versions obtained - - + + The device does not support this operation Device does not support this operation - - + + IO error IO error - - + + The language switch is successful and takes effect the next time the software is started! The language switch is successful and takes effect the next time the software is started! - + Are you sure to delete selected file? Are you sure to delete the selected file completely? diff --git a/app/scanner/mainwindow.cpp b/app/scanner/mainwindow.cpp index ebffc003..d800bb08 100644 --- a/app/scanner/mainwindow.cpp +++ b/app/scanner/mainwindow.cpp @@ -1566,7 +1566,7 @@ HGImage MainWindow::createImage() float scale = 200.0f / 72.0f; HGImgFmt_LoadImageFromPdfReader(pdfReader, (HGUInt)m_multiIndex, scale, scale, 0, HGBASE_IMGORIGIN_TOP, &img); - HGBase_SetImageDpi(img, 200, 200); + //HGBase_SetImageDpi(img, 200, 200); HGImgFmt_ClosePdfReader(pdfReader); } else @@ -2468,16 +2468,26 @@ void MainWindow::on_act_imageInfo_triggered() depth = 32; imageValues.append(QString::number(depth));//add image depth imageValues.append(depth == 0 ? tr("None") : (depth == 1 ? tr("Mono") : (depth == 8 ? tr("Gray") : tr("Color"))));//add image color - QString dpi = QString::number(xDpi) + " x " + QString::number(yDpi); - imageValues.append(dpi);//add image dpi - double cm_x = (0 == xDpi) ? 0 : 2.54 * imgInfo.width / xDpi; - double cm_y = (0 == yDpi) ? 0 : 2.54 * imgInfo.height / yDpi; - QString cm_printsize = QString::number(cm_x, 'f', 2) + " x " + QString::number(cm_y, 'f', 2) + " cm"; - double inch_x = cm_x / 2.54; - double inch_y = cm_y / 2.54; - QString inch_printsize = QString::number(inch_x, 'f', 2) + " x " + QString::number(inch_y, 'f', 2) + " inches"; - imageValues.append(cm_printsize + ", " + inch_printsize);//add image print size + if (0 == xDpi || 0 == yDpi) + { + QString info = tr("Not supported"); + imageValues.append(info); + imageValues.append(info); + } + else + { + QString dpi = QString::number(xDpi) + " x " + QString::number(yDpi); + imageValues.append(dpi);//add image dpi + + double cm_x = (0 == xDpi) ? 0 : 2.54 * imgInfo.width / xDpi; + double cm_y = (0 == yDpi) ? 0 : 2.54 * imgInfo.height / yDpi; + QString cm_printsize = QString::number(cm_x, 'f', 2) + " x " + QString::number(cm_y, 'f', 2) + " cm"; + double inch_x = cm_x / 2.54; + double inch_y = cm_y / 2.54; + QString inch_printsize = QString::number(inch_x, 'f', 2) + " x " + QString::number(inch_y, 'f', 2) + " inches"; + imageValues.append(cm_printsize + ", " + inch_printsize);//add image print size + } imageValues.append(QString::number(m_multiIndex)); Dialog_ImageInfo d(fileKeys, fileValues, imageKeys, imageValues, this); diff --git a/build-qt/HGSolution/HGFWUpgrade/HGFWUpgrade.pro b/build-qt/HGSolution/HGFWUpgrade/HGFWUpgrade.pro index b86d8d1c..3aab3ea3 100644 --- a/build-qt/HGSolution/HGFWUpgrade/HGFWUpgrade.pro +++ b/build-qt/HGSolution/HGFWUpgrade/HGFWUpgrade.pro @@ -257,6 +257,8 @@ RESOURCES += \ TRANSLATIONS += \ ../../../app/fwupgrade/FWUpgrade_zh_CN.ts \ + ../../../app/fwupgrade/qt_zh_CN.ts DISTFILES += \ ../../../app/fwupgrade/FWUpgrade_zh_CN.qm \ + ../../../app/fwupgrade/qt_zh_CN.qm diff --git a/modules/base/HGImage.cpp b/modules/base/HGImage.cpp index dd9686fd..413725ee 100644 --- a/modules/base/HGImage.cpp +++ b/modules/base/HGImage.cpp @@ -26,8 +26,8 @@ struct HGImageImpl m_top = 0; m_right = 0; m_bottom = 0; - m_xDpi = 96; - m_yDpi = 96; + m_xDpi = 0; + m_yDpi = 0; } ~HGImageImpl() @@ -174,7 +174,7 @@ HGResult HGAPI HGBase_CreateImage(HGUInt width, HGUInt height, HGUInt type, HGUI } else { - hBmp = CreateHBITMAP(width, height, type, origin, 96, 96, &data); + hBmp = CreateHBITMAP(width, height, type, origin, 0, 0, &data); if (NULL == hBmp) return HGBASE_ERR_OUTOFMEMORY; else @@ -206,8 +206,8 @@ HGResult HGAPI HGBase_CreateImage(HGUInt width, HGUInt height, HGUInt type, HGUI imageImpl->m_top = 0; imageImpl->m_right = imageImpl->m_width; imageImpl->m_bottom = imageImpl->m_height; - imageImpl->m_xDpi = 96; - imageImpl->m_yDpi = 96; + imageImpl->m_xDpi = 0; + imageImpl->m_yDpi = 0; *image = (HGImage)imageImpl; return HGBASE_ERR_OK; @@ -265,8 +265,8 @@ HGResult HGAPI HGBase_CreateImageWithData(HGByte* data, const HGImageInfo* info, imageImpl->m_top = 0; imageImpl->m_right = imageImpl->m_width; imageImpl->m_bottom = imageImpl->m_height; - imageImpl->m_xDpi = 96; - imageImpl->m_yDpi = 96; + imageImpl->m_xDpi = 0; + imageImpl->m_yDpi = 0; *image = (HGImage)imageImpl; return HGBASE_ERR_OK; diff --git a/modules/base/HGImage.h b/modules/base/HGImage.h index cd87fdf0..50e6babe 100644 --- a/modules/base/HGImage.h +++ b/modules/base/HGImage.h @@ -63,7 +63,7 @@ typedef struct * 否则内部分配普通内存(无HBITMAP); 在linux系统上,新图像内部分配普通内存(无HBITMAP) * 2) 新图像的width=width; 新图像的height=height; 新图像的type=type; 新图像的widthStep为4字节对齐; 新图像的origin=origin * 3) 新图像的roi为{0, 0, width, height} -* 4) 新图像的xdpi=96, ydpi=96 +* 4) 新图像的xdpi=0, ydpi=0 */ HGEXPORT HGResult HGAPI HGBase_CreateImage(HGUInt width, HGUInt height, HGUInt type, HGUInt origin, HGImage* image); @@ -77,7 +77,7 @@ HGEXPORT HGResult HGAPI HGBase_CreateImage(HGUInt width, HGUInt height, HGUInt t * 2) 新图像的width=info->width; 新图像的height=info->height; 新图像的type=info->type; 新图像的widthStep=info->widthStep; * 新图像的origin=info->origin * 3) 新图像的roi为{0, 0, width, height} -* 4) 新图像的xdpi=96, ydpi=96 +* 4) 新图像的xdpi=0, ydpi=0 */ HGEXPORT HGResult HGAPI HGBase_CreateImageWithData(HGByte* data, const HGImageInfo* info, HGImage* image); @@ -95,7 +95,7 @@ HGEXPORT HGResult HGAPI HGBase_CreateImageWithData(HGByte* data, const HGImageIn * 2) 新图像的width=roi->right-roi->left; 新图像的height=roi->bottom-roi->top; 新图像的type=type; 新图像的widthStep为4字节对齐; * 新图像的origin=origin, 如果origin和info->origin不一致,拷贝时像素会进行上下翻转 * 3) 新图像的roi为{0, 0, width, height} -* 4) 新图像的xdpi=96, ydpi=96 +* 4) 新图像的xdpi=0, ydpi=0 */ HGEXPORT HGResult HGAPI HGBase_CreateImageFromData(HGByte* data, const HGImageInfo *info, const HGImageRoi *roi, HGUInt type, HGUInt origin, HGImage* image); diff --git a/modules/imgfmt/HGImgFmt.cpp b/modules/imgfmt/HGImgFmt.cpp index c2b4fcd9..93b43b39 100644 --- a/modules/imgfmt/HGImgFmt.cpp +++ b/modules/imgfmt/HGImgFmt.cpp @@ -618,7 +618,7 @@ HGResult HGAPI HGImgFmt_SaveImage(HGImage image, HGUInt fmtType, const HGImgFmtS } } - HGUInt xDpi = 96, yDpi = 96; + HGUInt xDpi = 0, yDpi = 0; HGBase_GetImageDpi(image, &xDpi, &yDpi); if (HGIMGFMT_TYPE_JPEG == fmtType) @@ -1333,7 +1333,7 @@ HGResult HGAPI HGImgFmt_SaveImageToWriter(HGImgFmtWriter writer, HGImage image, return HGBASE_ERR_INVALIDARG; } - HGUInt xDpi = 96, yDpi = 96; + HGUInt xDpi = 0, yDpi = 0; HGBase_GetImageDpi(image, &xDpi, &yDpi); HGImgFmtWriterImpl* imgFmtWriterImpl = (HGImgFmtWriterImpl*)writer; diff --git a/modules/imgproc/HGOCRTesseract.cpp b/modules/imgproc/HGOCRTesseract.cpp index b8f14b3b..60903424 100644 --- a/modules/imgproc/HGOCRTesseract.cpp +++ b/modules/imgproc/HGOCRTesseract.cpp @@ -171,20 +171,7 @@ HGResult HGOCRTesseract::ImageTextDirectOCR(HGImage image, HGUInt* direct) HGBase_GetImageDpi(image2, &xDpi, &yDpi); TessBaseAPISetSourceResolution(m_baseApi, (xDpi + yDpi) / 2); - TessPageIterator* iter = TessBaseAPIAnalyseLayout(m_baseApi); - if (NULL == iter) - { - if (image2 != image) - HGBase_DestroyImage(image2); - return HGIMGPROC_ERR_OCR; - } - - TessOrientation orientation; - TessWritingDirection writing_direction; - TessTextlineOrder textline_order; - float deskew_angle; - TessPageIteratorOrientation(iter, &orientation, &writing_direction, &textline_order, &deskew_angle); - + int orientation = MyOSD(m_baseApi); if (TessOrientation::ORIENTATION_PAGE_UP == orientation) *direct = HGIMGPROC_OCRTEXTDIRECT_ORI; else if (TessOrientation::ORIENTATION_PAGE_RIGHT == orientation) @@ -194,7 +181,6 @@ HGResult HGOCRTesseract::ImageTextDirectOCR(HGImage image, HGUInt* direct) else if (TessOrientation::ORIENTATION_PAGE_LEFT == orientation) *direct = HGIMGPROC_OCRTEXTDIRECT_LEFT; - TessPageIteratorDelete(iter); if (image2 != image) HGBase_DestroyImage(image2); return HGBASE_ERR_OK; diff --git a/sdk/scannerlib/HGLibDeviceImpl.cpp b/sdk/scannerlib/HGLibDeviceImpl.cpp index f163ba1f..e3a24a9c 100644 --- a/sdk/scannerlib/HGLibDeviceImpl.cpp +++ b/sdk/scannerlib/HGLibDeviceImpl.cpp @@ -220,7 +220,7 @@ HGLibDeviceImpl::HGLibDeviceImpl() HGBase_CreateLock(&m_lock); m_devHandle = NULL; m_devName.clear(); - m_dpi = 96; + m_dpi = 0; m_scanning = HGFALSE; m_scanEvent = NULL; m_eventFunc = NULL; @@ -1011,7 +1011,7 @@ HGBool HGLibDeviceImpl::StartScan(HGLibDeviceScanEventFunc eventFunc, HGPointer m_imageParam = NULL; HGBase_DestroyEvent(m_scanEvent); m_scanEvent = NULL; - m_dpi = 96; + m_dpi = 0; } else { @@ -1039,7 +1039,7 @@ HGBool HGLibDeviceImpl::StopScan() m_imageFunc = NULL; m_imageParam = NULL; m_scanning = HGFALSE; - m_dpi = 96; + m_dpi = 0; ret = HGTRUE; } HGBase_LeaveLock(m_lock); @@ -1197,7 +1197,7 @@ int HGLibDeviceImpl::sane_ex_callback(SANE_Handle hdev, int code, void* data, un deviceImpl->m_imageFunc = NULL; deviceImpl->m_imageParam = NULL; deviceImpl->m_scanning = HGFALSE; - deviceImpl->m_dpi = 96; + deviceImpl->m_dpi = 0; HGBase_LeaveLock(deviceImpl->m_lock); if (NULL != eventFunc) diff --git a/sdk/webscan/WebUser.cpp b/sdk/webscan/WebUser.cpp index ba8b38ec..12f57bf9 100644 --- a/sdk/webscan/WebUser.cpp +++ b/sdk/webscan/WebUser.cpp @@ -212,7 +212,7 @@ WebUser::WebUser(WebServer* server, HGUInt id, HGMsgPump msgPump, const std::str m_devNameList.clear(); m_devName.clear(); m_devHandle = NULL; - m_dpi = 96; + m_dpi = 0; m_scanEvent = NULL; SANE_Int version_code = 0; @@ -233,7 +233,7 @@ WebUser::~WebUser() if (NULL != m_devHandle) { - m_dpi = 96; + m_dpi = 0; sane_close(m_devHandle); m_devHandle = NULL; m_devName.clear(); @@ -285,7 +285,7 @@ void WebUser::CloseDev(const CloseDevParam* param) if (NULL != m_devHandle) { - m_dpi = 96; + m_dpi = 0; sane_close(m_devHandle); m_devHandle = NULL; m_devName.clear(); @@ -424,7 +424,7 @@ void WebUser::SelectDevice(cJSON* json) if (NULL != m_devHandle) { - m_dpi = 96; + m_dpi = 0; sane_close(m_devHandle); m_devHandle = NULL; m_devName.clear(); @@ -1287,7 +1287,7 @@ HGBool WebUser::SetParam(const char* optionName, const HGVoid* data) HGInt WebUser::GetDpi() { assert(NULL != m_devHandle); - HGInt dpi = 96; + HGInt dpi = 0; SANE_Int num_dev_options = 0; sane_control_option(m_devHandle, 0, SANE_ACTION_GET_VALUE, &num_dev_options, NULL); @@ -1305,7 +1305,7 @@ HGInt WebUser::GetDpi() { if (SANE_TYPE_INT == desp->type) { - SANE_Int value = 96; + SANE_Int value = 0; sane_control_option(m_devHandle, i, SANE_ACTION_GET_VALUE, &value, NULL); dpi = value; } diff --git a/test/webservice/webdemoproject/.idea/workspace.xml b/test/webservice/webdemoproject/.idea/workspace.xml index b440e683..475f7912 100644 --- a/test/webservice/webdemoproject/.idea/workspace.xml +++ b/test/webservice/webdemoproject/.idea/workspace.xml @@ -1,12 +1,7 @@ - - - - - - + + + + \ No newline at end of file diff --git a/test/webservice/webdemoproject/css/scan.css b/test/webservice/webdemoproject/css/scan.css index 36825f8e..e6eb9e22 100644 --- a/test/webservice/webdemoproject/css/scan.css +++ b/test/webservice/webdemoproject/css/scan.css @@ -82,8 +82,10 @@ ul { } .el-container .el-header .menuContainer { - float: left; - margin-left: 15px; + /*float: left;*/ + /*margin-left: 15px;*/ + /*height: 80px;*/ + overflow-x: auto; } .el-container .el-header .menuContainer ul { @@ -218,3 +220,10 @@ ul { .cursor-pointer { cursor: pointer } + + +.menuStyle { + display: inline-block; + /*margin-left: 10px;*/ + margin: 5px; +} diff --git a/test/webservice/webdemoproject/js/WebScanController.js b/test/webservice/webdemoproject/js/WebScanController.js index 2af62e23..f81a6ccb 100644 --- a/test/webservice/webdemoproject/js/WebScanController.js +++ b/test/webservice/webdemoproject/js/WebScanController.js @@ -448,11 +448,11 @@ }, //插入本地图像(需返回成功后前端缩略图才能作相应的UI修改) - insertLocalImage: function (imagePath, insertIndex, callBack) { + insertLocalImage: function (imagePath, insertIndex, idenInfo, callBack) { const that = this this.sendCommand({ func: "insert_local_image", - iden: that.wslicence, + iden: JSON.stringify(idenInfo), image_path: imagePath, insert_pos: insertIndex,//插入位置,-1表示最后 image_tag: ''//标签名,可以为空 @@ -501,11 +501,11 @@ }, //修改图像 - modifyImage: function (imageIndex, imageBase64, callBack) { + modifyImage: function (imageIndex, imageBase64, idenInfo, callBack) { const that = this this.sendCommand({ func: "modify_image", - iden: that.wslicence, + iden: idenInfo == null ? that.wslicence : JSON.stringify(idenInfo), image_index: imageIndex, image_base64: imageBase64 }, callBack) diff --git a/test/webservice/webdemoproject/js/scanWeb.js b/test/webservice/webdemoproject/js/scanWeb.js index 0a3f952f..ef912159 100644 --- a/test/webservice/webdemoproject/js/scanWeb.js +++ b/test/webservice/webdemoproject/js/scanWeb.js @@ -292,8 +292,10 @@ new Vue({ this.eleMessage(info.info, info.is_error ? 'error' : 'warning') break case "scan_image"://图片回调 - this.appendLog('图片回调:' + info.image_path) - console.log('图片回调:' + info.image_path) + let imagePath = info.image_path + + this.appendLog('图片回调:' + imagePath) + console.log('图片回调:' + imagePath + ' info:' + JSON.stringify(info)) let that = this if (this.scanMode == 'insert') {//是插入扫描 @@ -306,18 +308,25 @@ new Vue({ this.curInsertIndex = this.selectImageObj.index } - console.log('插入扫描:待插入index:' + this.curInsertIndex + " path:" + info.image_path) - this.WebScanController.insertLocalImage(info.image_path, this.curInsertIndex, function (insertInfo) { - console.log('插入扫描:插入index' + that.curInsertIndex) - - that.urls.splice(that.curInsertIndex, 0, { - path: info.image_path, + console.log('插入扫描:待插入index:' + this.curInsertIndex + " path:" + imagePath) + this.WebScanController.insertLocalImage(imagePath, this.curInsertIndex, + { + path: imagePath, thumbnail: info.image_base64, base64: info.image_base64 - }); - that.curInsertIndex++ - that.$forceUpdate() - }) + }, + function (insertInfo) { + console.log('插入扫描:插入index' + that.curInsertIndex) + let idenInfo = JSON.parse(insertInfo.iden); + + that.urls.splice(that.curInsertIndex, 0, { + path: idenInfo.path, + thumbnail: idenInfo.thumbnail, + base64: idenInfo.base64 + }); + that.curInsertIndex++ + that.$forceUpdate() + }) } else if (this.scanMode == 'cover') {//是覆盖扫描 @@ -333,15 +342,20 @@ new Vue({ } if (this.needCoverCount > 0) {//还在覆盖范围内,直接覆盖掉 - this.WebScanController.modifyImage(this.curCoverIndex, info.image_base64, function (modifyInfo) { + this.WebScanController.modifyImage(this.curCoverIndex, info.image_base64, { + base64: info.image_base64, + thumbnail: info.image_base64, + path: imagePath + }, function (modifyInfo) { console.log('覆盖扫描:修改成功 index:' + that.curCoverIndex) console.log('覆盖前:index==' + that.curCoverIndex + ' path:' + that.urls[that.curCoverIndex].path) + let idenInfo = JSON.parse(modifyInfo.iden); that.urls[that.curCoverIndex] = { - base64: info.image_base64, - thumbnail: info.image_base64, - path: info.image_path + base64: idenInfo.base64, + thumbnail: idenInfo.thumbnail, + path: idenInfo.path } console.log('覆盖后:index==' + that.curCoverIndex + ' path:' + that.urls[that.curCoverIndex].path) @@ -351,12 +365,18 @@ new Vue({ that.$forceUpdate() }) } else {//之后都是新增的往后添加了 - this.WebScanController.insertLocalImage(info.image_path, this.urls.length, function (result) { + this.WebScanController.insertLocalImage(imagePath, this.urls.length, { + path: imagePath, + thumbnail: info.image_base64, + base64: info.image_base64 + }, function (result) { console.log('覆盖扫描:插入成功 index:' + that.urls.length) + let idenInfo = JSON.parse(result.iden); + that.urls.push({ - path: info.image_path, - thumbnail: info.image_base64, - base64: info.image_base64 + path: idenInfo.path, + thumbnail: idenInfo.thumbnail, + base64: idenInfo.base64 }) that.$forceUpdate() @@ -374,12 +394,20 @@ new Vue({ let that = this; - this.WebScanController.insertLocalImage(info.image_path, this.urls.length, function (result) { - console.log('正常扫描:插入成功 index:' + that.urls.length) + + this.WebScanController.insertLocalImage(imagePath, this.urls.length, { + path: imagePath, + thumbnail: info.image_base64, + base64: info.image_base64 + }, function (result) { + let idenInfo = JSON.parse(result.iden); + + console.log('正常扫描:插入成功 index:' + that.urls.length + ' path:' + idenInfo.path) + that.urls.push({ - path: info.image_path, - thumbnail: info.image_base64, - base64: info.image_base64 + path: idenInfo.path, + thumbnail: idenInfo.thumbnail, + base64: idenInfo.base64 }) that.$nextTick(function () { if (that.$refs.imageArea) { @@ -1023,7 +1051,7 @@ new Vue({ that.WebScanController.imageAddWatermark(modifyIndex, that.waterMarkInfo, true, function (info) { console.log('添加水印成功:') - that.WebScanController.modifyImage(modifyIndex, info.image_base64, function (modifyInfo) { + that.WebScanController.modifyImage(modifyIndex, info.image_base64, {}, function (modifyInfo) { console.log('添加水印:修改' + modifyIndex + '成功:') that.urls[modifyIndex].thumbnail = info.image_base64 that.urls[modifyIndex].base64 = info.image_base64 @@ -1056,7 +1084,7 @@ new Vue({ this.WebScanController.imageAddWatermark(imageIndex, markInfoParams, true, function (markInfo) { console.log('多张添加水印成功:index:' + imageIndex) let resultImage = markInfo.image_base64 - that.WebScanController.modifyImage(imageIndex, resultImage, function (modifyInfo) { + that.WebScanController.modifyImage(imageIndex, resultImage, {}, function (modifyInfo) { console.log('多张添加水印:修改' + imageIndex + '成功:') that.urls[imageIndex].thumbnail = resultImage that.urls[imageIndex].base64 = resultImage @@ -1249,9 +1277,9 @@ new Vue({ this.totalAngle = 0 this.canvas.discardActiveObject() let that = this - console.log('准备加载图像到画布:' + JSON.stringify(imageSrc)) + // console.log('准备加载图像到画布:' + JSON.stringify(imageSrc)) new fabric.Image.fromURL(imageSrc ? imageSrc.base64 : null, function (image) { - console.log('加载图像:image===' + image) + // console.log('加载图像:image===' + image) let result = imageSrc ? image : null that.image = result that.canvas.add(image) @@ -1452,7 +1480,7 @@ new Vue({ let firstPath = info.image_path_list[0] let secondPath = info.image_path_list[1] - that.WebScanController.modifyImage(currentIndex, secondBase64, function (info) { + that.WebScanController.modifyImage(currentIndex, secondBase64, {}, function (info) { console.log('图像拆分:第二张修改成功...') that.urls[currentIndex] = { base64: secondBase64, @@ -1886,7 +1914,7 @@ new Vue({ console.log('save image dataUrl:' + dataUrl) - this.WebScanController.modifyImage(this.selectImageObj.index, dataUrl, function (info) { + this.WebScanController.modifyImage(this.selectImageObj.index, dataUrl, {}, function (info) { console.log('修改图像成功:' + JSON.stringify(info)) that.eleUnloadding() that.undoStack.length = 0; @@ -2073,7 +2101,7 @@ new Vue({ console.log('save image dataUrl:' + dataUrl) - that.WebScanController.modifyImage(currentIndex, dataUrl, function (info) { + that.WebScanController.modifyImage(currentIndex, dataUrl, {}, function (info) { that.eleUnloadding() console.log('修改成功') that.urls[currentIndex].base64 = dataUrl diff --git a/test/webservice/webdemoproject/webDemo.html b/test/webservice/webdemoproject/webDemo.html index 082f7c23..fdaaeae6 100644 --- a/test/webservice/webdemoproject/webDemo.html +++ b/test/webservice/webdemoproject/webDemo.html @@ -9,7 +9,7 @@ - + + + + + + -
  • +
  • -
  • + + -
  • -
  • + +
  • -
  • + +
  • -
  • + +
  • - + + + diff --git a/third_party/ocr/tesseract-ocr/kylin/aarch64/include/tesseract/baseapi.h b/third_party/ocr/tesseract-ocr/kylin/aarch64/include/tesseract/baseapi.h index 3724dd92..fe12351b 100644 --- a/third_party/ocr/tesseract-ocr/kylin/aarch64/include/tesseract/baseapi.h +++ b/third_party/ocr/tesseract-ocr/kylin/aarch64/include/tesseract/baseapi.h @@ -93,6 +93,8 @@ class TESS_API TessBaseAPI { TessBaseAPI(); virtual ~TessBaseAPI(); + int MyOSD(); + /** * Returns the version identifier as a static string. Do not delete. */ diff --git a/third_party/ocr/tesseract-ocr/kylin/aarch64/include/tesseract/capi.h b/third_party/ocr/tesseract-ocr/kylin/aarch64/include/tesseract/capi.h index 7ed64ef4..8752816a 100644 --- a/third_party/ocr/tesseract-ocr/kylin/aarch64/include/tesseract/capi.h +++ b/third_party/ocr/tesseract-ocr/kylin/aarch64/include/tesseract/capi.h @@ -176,6 +176,8 @@ struct Pix; struct Boxa; struct Pixa; +TESS_API int MyOSD(TessBaseAPI* api); + /* General free functions */ TESS_API const char* TESS_CALL TessVersion(); diff --git a/third_party/ocr/tesseract-ocr/kylin/aarch64/lib/libtesseract.a b/third_party/ocr/tesseract-ocr/kylin/aarch64/lib/libtesseract.a index 47aa9d0d..9d5a9047 100644 Binary files a/third_party/ocr/tesseract-ocr/kylin/aarch64/lib/libtesseract.a and b/third_party/ocr/tesseract-ocr/kylin/aarch64/lib/libtesseract.a differ diff --git a/third_party/ocr/tesseract-ocr/kylin/amd64/include/tesseract/baseapi.h b/third_party/ocr/tesseract-ocr/kylin/amd64/include/tesseract/baseapi.h index 3724dd92..fe12351b 100644 --- a/third_party/ocr/tesseract-ocr/kylin/amd64/include/tesseract/baseapi.h +++ b/third_party/ocr/tesseract-ocr/kylin/amd64/include/tesseract/baseapi.h @@ -93,6 +93,8 @@ class TESS_API TessBaseAPI { TessBaseAPI(); virtual ~TessBaseAPI(); + int MyOSD(); + /** * Returns the version identifier as a static string. Do not delete. */ diff --git a/third_party/ocr/tesseract-ocr/kylin/amd64/include/tesseract/capi.h b/third_party/ocr/tesseract-ocr/kylin/amd64/include/tesseract/capi.h index 7ed64ef4..8752816a 100644 --- a/third_party/ocr/tesseract-ocr/kylin/amd64/include/tesseract/capi.h +++ b/third_party/ocr/tesseract-ocr/kylin/amd64/include/tesseract/capi.h @@ -176,6 +176,8 @@ struct Pix; struct Boxa; struct Pixa; +TESS_API int MyOSD(TessBaseAPI* api); + /* General free functions */ TESS_API const char* TESS_CALL TessVersion(); diff --git a/third_party/ocr/tesseract-ocr/kylin/amd64/lib/libtesseract.a b/third_party/ocr/tesseract-ocr/kylin/amd64/lib/libtesseract.a index d4aeb5ee..e2a2d25f 100644 Binary files a/third_party/ocr/tesseract-ocr/kylin/amd64/lib/libtesseract.a and b/third_party/ocr/tesseract-ocr/kylin/amd64/lib/libtesseract.a differ diff --git a/third_party/ocr/tesseract-ocr/kylin/loongarch64/include/tesseract/baseapi.h b/third_party/ocr/tesseract-ocr/kylin/loongarch64/include/tesseract/baseapi.h index 3724dd92..fe12351b 100644 --- a/third_party/ocr/tesseract-ocr/kylin/loongarch64/include/tesseract/baseapi.h +++ b/third_party/ocr/tesseract-ocr/kylin/loongarch64/include/tesseract/baseapi.h @@ -93,6 +93,8 @@ class TESS_API TessBaseAPI { TessBaseAPI(); virtual ~TessBaseAPI(); + int MyOSD(); + /** * Returns the version identifier as a static string. Do not delete. */ diff --git a/third_party/ocr/tesseract-ocr/kylin/loongarch64/include/tesseract/capi.h b/third_party/ocr/tesseract-ocr/kylin/loongarch64/include/tesseract/capi.h index 7ed64ef4..8752816a 100644 --- a/third_party/ocr/tesseract-ocr/kylin/loongarch64/include/tesseract/capi.h +++ b/third_party/ocr/tesseract-ocr/kylin/loongarch64/include/tesseract/capi.h @@ -176,6 +176,8 @@ struct Pix; struct Boxa; struct Pixa; +TESS_API int MyOSD(TessBaseAPI* api); + /* General free functions */ TESS_API const char* TESS_CALL TessVersion(); diff --git a/third_party/ocr/tesseract-ocr/kylin/loongarch64/lib/libtesseract.a b/third_party/ocr/tesseract-ocr/kylin/loongarch64/lib/libtesseract.a index 866ad476..2d3370f7 100644 Binary files a/third_party/ocr/tesseract-ocr/kylin/loongarch64/lib/libtesseract.a and b/third_party/ocr/tesseract-ocr/kylin/loongarch64/lib/libtesseract.a differ diff --git a/third_party/ocr/tesseract-ocr/kylin/mips64/include/tesseract/baseapi.h b/third_party/ocr/tesseract-ocr/kylin/mips64/include/tesseract/baseapi.h index 3724dd92..fe12351b 100644 --- a/third_party/ocr/tesseract-ocr/kylin/mips64/include/tesseract/baseapi.h +++ b/third_party/ocr/tesseract-ocr/kylin/mips64/include/tesseract/baseapi.h @@ -93,6 +93,8 @@ class TESS_API TessBaseAPI { TessBaseAPI(); virtual ~TessBaseAPI(); + int MyOSD(); + /** * Returns the version identifier as a static string. Do not delete. */ diff --git a/third_party/ocr/tesseract-ocr/kylin/mips64/include/tesseract/capi.h b/third_party/ocr/tesseract-ocr/kylin/mips64/include/tesseract/capi.h index 7ed64ef4..8752816a 100644 --- a/third_party/ocr/tesseract-ocr/kylin/mips64/include/tesseract/capi.h +++ b/third_party/ocr/tesseract-ocr/kylin/mips64/include/tesseract/capi.h @@ -176,6 +176,8 @@ struct Pix; struct Boxa; struct Pixa; +TESS_API int MyOSD(TessBaseAPI* api); + /* General free functions */ TESS_API const char* TESS_CALL TessVersion(); diff --git a/third_party/ocr/tesseract-ocr/kylin/mips64/lib/libtesseract.a b/third_party/ocr/tesseract-ocr/kylin/mips64/lib/libtesseract.a index 7fbb3435..1e740828 100644 Binary files a/third_party/ocr/tesseract-ocr/kylin/mips64/lib/libtesseract.a and b/third_party/ocr/tesseract-ocr/kylin/mips64/lib/libtesseract.a differ diff --git a/third_party/ocr/tesseract-ocr/src/CMakeLists.txt b/third_party/ocr/tesseract-ocr/src/CMakeLists.txt new file mode 100644 index 00000000..eb3fdba6 --- /dev/null +++ b/third_party/ocr/tesseract-ocr/src/CMakeLists.txt @@ -0,0 +1,594 @@ +# +# tesseract +# + +############################################################################### +# +# cmake settings +# +############################################################################### + +cmake_minimum_required(VERSION 3.6 FATAL_ERROR) + +# In-source builds are disabled. +if ("${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}") + message(FATAL_ERROR + "CMake generation is not possible within the source directory!" + "\n Remove the CMakeCache.txt file and try again from another folder, e.g.:" + "\n " + "\n rm CMakeCache.txt" + "\n mkdir build" + "\n cd build" + "\n cmake .." + ) +endif() + +set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${CMAKE_CURRENT_SOURCE_DIR}/cmake") + +set(EXECUTABLE_OUTPUT_PATH "${CMAKE_BINARY_DIR}/bin") +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${EXECUTABLE_OUTPUT_PATH}") + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -O2") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -O2") + +# Use solution folders. +set_property(GLOBAL PROPERTY USE_FOLDERS ON) +set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER "CMake Targets") + +############################################################################### +# +# project settings +# +############################################################################### + +project(tesseract C CXX) + +# Get version with components from VERSION file. +file(STRINGS "VERSION" VERSION_PLAIN) +string(REGEX REPLACE "^([^.]*)\\..*" "\\1" VERSION_MAJOR ${VERSION_PLAIN}) +string(REGEX REPLACE "^[^.]*\\.([^.]*)\\..*" "\\1" VERSION_MINOR ${VERSION_PLAIN}) +string(REGEX REPLACE "^[^.]*\\.[^.]*\\.([0-9]*).*" "\\1" VERSION_PATCH ${VERSION_PLAIN}) +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git) + execute_process(COMMAND git --git-dir ${CMAKE_CURRENT_SOURCE_DIR}/.git describe --abbrev=4 + OUTPUT_VARIABLE GIT_REV) + string(REGEX REPLACE "\n$" "" PACKAGE_VERSION "${GIT_REV}") +endif() +if(NOT PACKAGE_VERSION) + set(PACKAGE_VERSION ${VERSION_PLAIN}) +endif() + +# Provide also same macro names as autoconf (see configure.ac). +set(GENERIC_MAJOR_VERSION ${VERSION_MAJOR}) +set(GENERIC_MINOR_VERSION ${VERSION_MINOR}) +set(GENERIC_MICRO_VERSION ${VERSION_PATCH}) + +set(MINIMUM_LEPTONICA_VERSION 1.74) + +############################################################################### +# +# options +# +############################################################################### +message( "Configuring tesseract version ${PACKAGE_VERSION}...") + +option(CPPAN_BUILD "Build with cppan" ON) +option(SW_BUILD "Build with sw" OFF) +option(OPENMP_BUILD "Build with openmp support" OFF) # see issue #1662 +option(AUTO_OPTIMIZE "Usage of cmake auto optimize macros (not suitable for portable build)" ON) +option(GRAPHICS_DISABLED "Disable disable graphics (ScrollView)" OFF) +option(DISABLED_LEGACY_ENGINE "Disable the legacy OCR engine" OFF) +option(BUILD_TRAINING_TOOLS "Build training tools" ON) +option(BUILD_TESTS "Build tests" OFF) + +if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.cppan OR SW_BUILD) + set(CPPAN_BUILD OFF) +endif() + +############################################################################### +# +# compiler and linker +# +############################################################################### + +if(NOT CMAKE_BUILD_TYPE) + message(STATUS "Setting build type to 'Release' as none was specified.") + set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release") +endif() + +include(CheckCXXCompilerFlag) + +# Check for C++ standard to use +get_property(known_features GLOBAL PROPERTY CMAKE_CXX_KNOWN_FEATURES) +if (cxx_std_17 IN_LIST known_features) + set(CMAKE_CXX_STANDARD 17) +elseif (cxx_std_14 IN_LIST known_features) + set(CMAKE_CXX_STANDARD 14) +else() # minimum required standard + set(CMAKE_CXX_STANDARD 11) +endif() + +# Avoid using experimental c++1y (c++1z) standard even if the compiler announces cxx14 (cxx17) +# in CMAKE_CXX_KNOWN_FEATURES and CMAKE_CXX_COMPILE_FEATURES +# It is the case of clang 3.9, 4.0 (announces c++1z) and gcc 4.8 (announces c++1y) +if ("${CMAKE_CXX17_STANDARD_COMPILE_OPTION}" STREQUAL "-std=c++1z") + set(CMAKE_CXX_STANDARD 14) +endif() +if ("${CMAKE_CXX14_STANDARD_COMPILE_OPTION}" STREQUAL "-std=c++1y") + set(CMAKE_CXX_STANDARD 11) +endif() + +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +set(LIBRARY_TYPE STATIC) +if (STATIC) + set(LIBRARY_TYPE) +endif() + +# auto optimize +if (AUTO_OPTIMIZE) + include(OptimizeForArchitecture) + AutodetectHostArchitecture() + OptimizeForArchitecture() +endif() +# Compiler specific environments +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + set(CLANG 1) +endif() +if(CMAKE_COMPILER_IS_GNUCXX OR MINGW) + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall -DDEBUG -pedantic -Og") +elseif(MSVC) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /utf-8") + if (NOT CLANG) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") + endif() + # Don't use /Wall because it generates too many warnings. + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /W4 /bigobj") +endif() +if(CLANG) # clang all platforms + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Wno-unused-command-line-argument") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall -DDEBUG -pedantic -O0") +endif() + +if (OPENMP_BUILD) + find_package(OpenMP QUIET) + if (OpenMP_FOUND) + message(">> ${OpenMP_FOUND} ${OpenMP_VERSION}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") + add_library(OpenMP::OpenMP_CXX IMPORTED INTERFACE) + endif() + # https://stackoverflow.com/questions/12399422/how-to-set-linker-flags-for-openmp-in-cmakes-try-compile-function + if (NOT OpenMP_FOUND AND CLANG AND WIN32) + # workaroung because find_package(OpenMP) does not work for clang-cl + # https://gitlab.kitware.com/cmake/cmake/issues/19404 + check_include_file_cxx(omp.h HAVE_OMP_H_INCLUDE) + find_library(OpenMP_LIBRARY NAMES omp libomp.lib) + message(">> OpenMP_LIBRARY: ${OpenMP_LIBRARY}") + if (MSVC) + set(OpenMP_CXX_FLAGS "${OpenMP_CXX_FLAGS} /openmp") + else() + set(OpenMP_CXX_FLAGS "${OpenMP_CXX_FLAGS} -fopenmp") + endif() + set(OpenMP_FOUND 1) + add_definitions(-D_OPENMP=201107) # 3.1 version is supported from Clang 3.8.0 + endif() +endif() + + +if (CYGWIN) + add_definitions(-D__CYGWIN__) +elseif(UNIX) + if (NOT ANDROID) + set(LIB_pthread pthread) + endif() +elseif(WIN32) + set(LIB_Ws2_32 Ws2_32) +endif() + +############################################################################### +# +# packages +# +############################################################################### + +if(CPPAN_BUILD) + if (STATIC) + set(CPPAN_BUILD_SHARED_LIBS 0) + else() + set(CPPAN_BUILD_SHARED_LIBS 1) + endif() + add_subdirectory(.cppan) +elseif (SW_BUILD) + find_package(SW REQUIRED) + if (STATIC) + set(SW_BUILD_SHARED_LIBS 0) + else() + set(SW_BUILD_SHARED_LIBS 1) + endif() + sw_add_package( + org.sw.demo.danbloomberg.leptonica-master + org.sw.demo.libarchive.libarchive + ) + if (BUILD_TRAINING_TOOLS) + sw_add_package( + org.sw.demo.gnome.pango.pangocairo + org.sw.demo.unicode.icu.i18n + ) + endif() + sw_execute() +else() + find_package(PkgConfig) + if(PKG_CONFIG_EXECUTABLE AND NOT Leptonica_DIR) + pkg_check_modules(Leptonica REQUIRED lept>=${MINIMUM_LEPTONICA_VERSION}) + link_directories(${Leptonica_LIBRARY_DIRS}) + else() + find_package(Leptonica ${MINIMUM_LEPTONICA_VERSION} REQUIRED CONFIG) + endif() + if (NOT Leptonica_FOUND) + message(FATAL_ERROR "Cannot find required library Leptonica. Quitting!") + endif(NOT Leptonica_FOUND) + + find_package(LibArchive) + if(LibArchive_FOUND) + set(HAVE_LIBARCHIVE ON) + endif() +endif() + +find_package(OpenCL QUIET) + + +############################################################################### +# +# configure +# +############################################################################### + +foreach(flag ${Vc_ARCHITECTURE_FLAGS}) + set(Vc_CXX_FLAGS "${Vc_CXX_FLAGS} ${flag}") +endforeach() + +# add definition as expected in src/arch/simddetect.cpp +set(AVX_OPT OFF) +set(AVX2_OPT OFF) +set(FMA_OPT OFF) +set(SSE41_OPT OFF) +set(MARCH_NATIVE_OPT OFF) +foreach(flag ${_enable_vector_unit_list}) # from OptimizeForArchitecture() + string(TOUPPER "${flag}" flag) + string(REPLACE "\." "_" flag "${flag}") + set(simd_flags "${simd_flags} -D${flag}") + string(REPLACE "_" "" flag "${flag}") + if("${flag}" MATCHES "AVX|AVX2|FMA|SSE41") + set("${flag}_OPT" ON) + endif() +endforeach(flag) +if (NOT MSVC) + set(MARCH_NATIVE_FLAGS "${MARCH_NATIVE_FLAGS} -O3 -ffast-math") +endif() +CHECK_CXX_COMPILER_FLAG("-march=native" COMPILER_SUPPORTS_MARCH_NATIVE) +if(COMPILER_SUPPORTS_MARCH_NATIVE) + set(MARCH_NATIVE_FLAGS "${MARCH_NATIVE_FLAGS} -march=native -mtune=native") + set(MARCH_NATIVE_OPT ON) +endif() + +set(AUTOCONFIG_SRC ${CMAKE_CURRENT_BINARY_DIR}/config_auto.h.in) +set(AUTOCONFIG ${CMAKE_CURRENT_BINARY_DIR}/config_auto.h) +add_definitions(-DHAVE_CONFIG_H) + +if(GRAPHICS_DISABLED) + message("ScrollView debugging disabled.") +endif() +set (CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} "${CMAKE_PREFIX_PATH}/include" "${CMAKE_INSTALL_PREFIX}/include") +include(Configure) + +configure_file(${AUTOCONFIG_SRC} ${AUTOCONFIG} @ONLY) + +set(INCLUDE_DIR "${CMAKE_INSTALL_PREFIX}/include" "${CMAKE_INSTALL_PREFIX}/include/tesseract") + +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/src/api/tess_version.h.in + ${CMAKE_CURRENT_BINARY_DIR}/api/tess_version.h @ONLY) +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/src/vs2010/tesseract/tesseract.rc.in + ${CMAKE_CURRENT_BINARY_DIR}/vs2010/tesseract/tesseract.rc @ONLY) +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/src/vs2010/tesseract/libtesseract.rc.in + ${CMAKE_CURRENT_BINARY_DIR}/vs2010/tesseract/libtesseract.rc @ONLY) +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/TesseractConfig-version.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/TesseractConfig-version.cmake @ONLY) +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/TesseractConfig.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/TesseractConfig.cmake @ONLY) + +# show summary of configuration +if(${CMAKE_BUILD_TYPE} MATCHES Debug) + set(COMPILER_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_DEBUG}") +elseif(${CMAKE_BUILD_TYPE} MATCHES Release) + set(COMPILER_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_RELEASE}") +endif() +message( STATUS ) +message( STATUS "General configuration for Tesseract ${PACKAGE_VERSION}") +message( STATUS "--------------------------------------------------------") +message( STATUS "Build type: ${CMAKE_BUILD_TYPE}") +message( STATUS "Compiler: ${CMAKE_CXX_COMPILER_ID}") +message( STATUS "Used standard: C++${CMAKE_CXX_STANDARD}") +message( STATUS "CXX compiler options: ${COMPILER_FLAGS}") +message( STATUS "Linker options: ${CMAKE_EXE_LINKER_FLAGS} ${CMAKE_EXE_LINKER_FLAGS_${CMAKE_BUILD_TYPE_UP}}") +message( STATUS "Install directory: ${CMAKE_INSTALL_PREFIX}") +message( STATUS "Architecture flags: ${Vc_ARCHITECTURE_FLAGS}") +message( STATUS "Vector unit list: ${_enable_vector_unit_list}") +message( STATUS "AVX_OPT: ${AVX_OPT}") +message( STATUS "AVX2_OPT: ${AVX2_OPT}") +message( STATUS "FMA_OPT: ${FMA_OPT}") +message( STATUS "SSE41_OPT: ${SSE41_OPT}") +message( STATUS "MARCH_NATIVE_OPT: ${MARCH_NATIVE_OPT}") +message( STATUS "simd_flags: ${simd_flags}") +message( STATUS "--------------------------------------------------------") +message( STATUS "Build with cppan [CPPAN_BUILD]: ${CPPAN_BUILD}") +if (CPPAN_BUILD) +message( STATUS "##################################################################################") +message( "!! CPPAN is depreciated! Please consider switching to SW Build.\n" + " More details: https://github.com/tesseract-ocr/tesseract/wiki/Compiling#windows") +message( STATUS "##################################################################################") +endif() +message( STATUS "Build with sw [SW_BUILD]: ${SW_BUILD}") +message( STATUS "Build with openmp support [OPENMP_BUILD]: ${OPENMP_BUILD}") +message( STATUS "Disable disable graphics (ScrollView) [GRAPHICS_DISABLED]: ${GRAPHICS_DISABLED}") +message( STATUS "Disable the legacy OCR engine [DISABLED_LEGACY_ENGINE]: ${DISABLED_LEGACY_ENGINE}") +message( STATUS "Build training tools [BUILD_TRAINING_TOOLS]: ${BUILD_TRAINING_TOOLS}") +message( STATUS "Build tests [BUILD_TESTS]: ${BUILD_TESTS}") +message( STATUS "--------------------------------------------------------") +message( STATUS ) + +############################################################################### +# +# build +# +############################################################################### + +include(BuildFunctions) +include(SourceGroups) + +add_definitions(-D_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS=1) + +include_directories(${Leptonica_INCLUDE_DIRS}) +include_directories(${LibArchive_INCLUDE_DIRS}) + +include_directories(${CMAKE_CURRENT_BINARY_DIR}) +include_directories(src/api) +include_directories(${CMAKE_CURRENT_BINARY_DIR}/api) +include_directories(src/arch) +include_directories(src/ccmain) +include_directories(src/ccstruct) +include_directories(src/ccutil) +include_directories(src/classify) +include_directories(src/cutil) +include_directories(src/dict) +include_directories(src/lstm) +include_directories(src/opencl) +include_directories(src/textord) +include_directories(src/viewer) +include_directories(src/wordrec) +include_directories(src/training) +if(ANDROID_TOOLCHAIN) + include_directories(${ANDROID_TOOLCHAIN}/sysroot/usr/include) + add_compile_definitions(__ANDROID_API_FUTURE__) +endif() + +######################################## +# LIBRARY tesseract +######################################## + +file(GLOB tesseract_src + src/ccmain/*.cpp + src/ccstruct/*.cpp + src/ccutil/*.cpp + src/classify/*.cpp + src/cutil/*.cpp + src/dict/*.cpp + src/lstm/*.cpp + src/opencl/*.cpp + src/textord/*.cpp + src/viewer/*.cpp + src/wordrec/*.cpp +) + +list(APPEND arch_files + src/arch/dotproduct.cpp + src/arch/simddetect.cpp + src/arch/intsimdmatrix.cpp +) +set_source_files_properties(${arch_files} PROPERTIES COMPILE_FLAGS "${simd_flags}") +set_source_files_properties(src/arch/dotproduct.cpp PROPERTIES COMPILE_FLAGS "${MARCH_NATIVE_FLAGS} ${Vc_CXX_FLAGS}") +if(AVX_OPT) + list(APPEND arch_files_opt src/arch/dotproductavx.cpp) + set_source_files_properties(src/arch/dotproductavx.cpp PROPERTIES COMPILE_FLAGS "-DAVX") +endif(AVX_OPT) +if(AVX2_OPT) + list(APPEND arch_files_opt src/arch/intsimdmatrixavx2.cpp) + set_source_files_properties(src/arch/intsimdmatrixavx2.cpp PROPERTIES COMPILE_FLAGS "-DAVX2") +endif(AVX2_OPT) +if(FMA_OPT) + list(APPEND arch_files_opt src/arch/dotproductfma.cpp) + set_source_files_properties(src/arch/dotproductfma.cpp PROPERTIES COMPILE_FLAGS "-mfma") +endif(FMA_OPT) +if(SSE41_OPT) + list(APPEND arch_files_opt src/arch/dotproductsse.cpp src/arch/intsimdmatrixsse.cpp) + set_source_files_properties(src/arch/dotproductsse.cpp src/arch/intsimdmatrixsse.cpp PROPERTIES COMPILE_FLAGS "-DSSE4_1 -msse4.1") +endif(SSE41_OPT) +set_source_files_properties(${arch_files_opt} PROPERTIES COMPILE_FLAGS "${Vc_CXX_FLAGS}") + +file(GLOB tesseract_hdr + src/api/*.h + src/arch/*.h + src/ccmain/*.h + src/ccstruct/*.h + src/ccutil/*.h + src/classify/*.h + src/cutil/*.h + src/dict/*.h + src/lstm/*.h + src/opencl/*.h + src/textord/*.h + src/viewer/*.h + src/wordrec/*.h +) + +set(tesseract_src ${tesseract_src} + src/api/baseapi.cpp + src/api/capi.cpp + src/api/renderer.cpp + src/api/altorenderer.cpp + src/api/hocrrenderer.cpp + src/api/lstmboxrenderer.cpp + src/api/pdfrenderer.cpp + src/api/wordstrboxrenderer.cpp +) + +if (WIN32) + if (MSVC) + include_directories(src/vs2010/tesseract) + set(tesseract_hdr + ${tesseract_hdr} + ${CMAKE_CURRENT_SOURCE_DIR}/src/vs2010/tesseract/resource.h) + set(tesseract_rsc ${CMAKE_CURRENT_BINARY_DIR}/vs2010/tesseract/libtesseract.rc) + endif() # MSVC +endif() + +add_library (libtesseract ${LIBRARY_TYPE} ${tesseract_src} ${arch_files} + ${arch_files_opt} ${tesseract_hdr} ${tesseract_rsc} + ) +if (NOT STATIC) +target_compile_definitions (libtesseract + PRIVATE -DTESS_EXPORTS + INTERFACE -DTESS_IMPORTS +) +set_target_properties (libtesseract PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS True) +endif() +target_link_libraries (libtesseract PRIVATE ${LIB_Ws2_32} ${LIB_pthread}) +set_target_properties (libtesseract PROPERTIES VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) +set_target_properties (libtesseract PROPERTIES SOVERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) +if (WIN32) +set_target_properties (libtesseract PROPERTIES OUTPUT_NAME tesseract${VERSION_MAJOR}${VERSION_MINOR}) +set_target_properties (libtesseract PROPERTIES DEBUG_OUTPUT_NAME tesseract${VERSION_MAJOR}${VERSION_MINOR}d) +else() +set_target_properties (libtesseract PROPERTIES OUTPUT_NAME tesseract) +endif() + +if (CPPAN_BUILD) + target_link_libraries (libtesseract PUBLIC + pvt.cppan.demo.danbloomberg.leptonica + pvt.cppan.demo.libarchive.libarchive + ) + file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/TesseractTargets.cmake "include(${CMAKE_CURRENT_BINARY_DIR}/cppan.cmake)\n") + export(TARGETS libtesseract APPEND FILE ${CMAKE_CURRENT_BINARY_DIR}/TesseractTargets.cmake) +elseif (SW_BUILD) + target_link_libraries (libtesseract PUBLIC + org.sw.demo.danbloomberg.leptonica-master + org.sw.demo.libarchive.libarchive + ) + file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/TesseractTargets.cmake "include(${CMAKE_CURRENT_BINARY_DIR}/cppan.cmake)\n") + export(TARGETS libtesseract APPEND FILE ${CMAKE_CURRENT_BINARY_DIR}/TesseractTargets.cmake) +else() + target_link_libraries (libtesseract PUBLIC + ${Leptonica_LIBRARIES} + ${LibArchive_LIBRARIES} + ) + export(TARGETS libtesseract FILE ${CMAKE_CURRENT_BINARY_DIR}/TesseractTargets.cmake) +endif() + +if (WIN32 AND CLANG AND OPENMP_BUILD) + # Workaround for "libomp.lib is not automatically added on Windows" + # see: http://lists.llvm.org/pipermail/openmp-dev/2015-August/000857.html + target_link_libraries (libtesseract PRIVATE ${OpenMP_LIBRARY}) +endif() + +######################################## +# EXECUTABLE tesseractmain +######################################## + +set(tesseractmain_src src/api/tesseractmain.cpp) +if (MSVC) + set(tesseractmain_rsc ${CMAKE_CURRENT_BINARY_DIR}/vs2010/tesseract/tesseract.rc) +endif() + +add_executable (tesseract ${tesseractmain_src} ${tesseractmain_rsc}) +target_link_libraries (tesseract libtesseract) +if (HAVE_TIFFIO_H) + target_link_libraries(tesseract tiff) +endif() + +if (OPENMP_BUILD AND UNIX) +target_link_libraries (tesseract pthread) +endif() + +######################################## + +if (BUILD_TESTS AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/googletest/CMakeLists.txt) + add_subdirectory(googletest) +endif() + +if (BUILD_TRAINING_TOOLS) +add_subdirectory(src/training) +endif() + +get_target_property(tesseract_NAME libtesseract NAME) +get_target_property(tesseract_VERSION libtesseract VERSION) +get_target_property(tesseract_OUTPUT_NAME libtesseract OUTPUT_NAME) +configure_file(tesseract.pc.cmake ${CMAKE_CURRENT_BINARY_DIR}/tesseract.pc @ONLY) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/tesseract.pc DESTINATION lib/pkgconfig) +install(TARGETS tesseract RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib) +install(TARGETS libtesseract EXPORT TesseractTargets RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib) +install(EXPORT TesseractTargets DESTINATION cmake) +install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/TesseractConfig.cmake + ${CMAKE_CURRENT_BINARY_DIR}/TesseractConfig-version.cmake + DESTINATION cmake) + +install(FILES + # from api/makefile.am + src/api/apitypes.h + src/api/baseapi.h + src/api/capi.h + src/api/renderer.h + ${CMAKE_CURRENT_BINARY_DIR}/api/tess_version.h + + #from ccmain/makefile.am + src/ccmain/thresholder.h + src/ccmain/ltrresultiterator.h + src/ccmain/pageiterator.h + src/ccmain/resultiterator.h + src/ccmain/osdetect.h + + #from ccstruct/makefile.am + src/ccstruct/publictypes.h + + #from ccutil/makefile.am + src/ccutil/genericvector.h + src/ccutil/helpers.h + src/ccutil/ocrclass.h + src/ccutil/platform.h + src/ccutil/serialis.h + src/ccutil/strngs.h + src/ccutil/tesscallback.h + src/ccutil/unichar.h + #${CMAKE_CURRENT_BINARY_DIR}/src/endianness.h + DESTINATION include/tesseract) + +######################################## +# uninstall target +######################################## +if(NOT TARGET uninstall) + configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/cmake_uninstall.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" + IMMEDIATE @ONLY) + + add_custom_target(uninstall + COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) +endif() + +############################################################################### diff --git a/third_party/ocr/tesseract-ocr/src/baseapi.cpp b/third_party/ocr/tesseract-ocr/src/baseapi.cpp new file mode 100644 index 00000000..66640c52 --- /dev/null +++ b/third_party/ocr/tesseract-ocr/src/baseapi.cpp @@ -0,0 +1,2696 @@ +/********************************************************************** + * File: baseapi.cpp + * Description: Simple API for calling tesseract. + * Author: Ray Smith + * + * (C) Copyright 2006, Google Inc. + ** Licensed under the Apache License, Version 2.0 (the "License"); + ** you may not use this file except in compliance with the License. + ** You may obtain a copy of the License at + ** http://www.apache.org/licenses/LICENSE-2.0 + ** Unless required by applicable law or agreed to in writing, software + ** distributed under the License is distributed on an "AS IS" BASIS, + ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ** See the License for the specific language governing permissions and + ** limitations under the License. + * + **********************************************************************/ + +#define _USE_MATH_DEFINES // for M_PI + +// Include automatically generated configuration file if running autoconf. +#ifdef HAVE_CONFIG_H +#include "config_auto.h" +#endif + +#include "baseapi.h" +#ifdef __linux__ +#include // for sigaction, SA_RESETHAND, SIGBUS, SIGFPE +#endif + +#if defined(_WIN32) +#include +#include +#else +#include // for closedir, opendir, readdir, DIR, dirent +#include +#include +#include // for stat, S_IFDIR +#include +#endif // _WIN32 + +#include // for round, M_PI +#include // for int32_t +#include // for strcmp, strcpy +#include // for size_t +#include // for std::cin +#include // for std::locale::classic +#include // for std::unique_ptr +#include // for std::pair +#include // for std::stringstream +#include // for std::vector +#ifdef HAVE_LIBCURL +#include +#endif +#include "allheaders.h" // for pixDestroy, boxCreate, boxaAddBox, box... +#ifndef DISABLED_LEGACY_ENGINE +#include "blobclass.h" // for ExtractFontName +#endif +#include "boxword.h" // for BoxWord +#include "config_auto.h" // for PACKAGE_VERSION +#include "coutln.h" // for C_OUTLINE_IT, C_OUTLINE_LIST +#include "dawg_cache.h" // for DawgCache +#include "dict.h" // for Dict +#include "edgblob.h" // for extract_edges +#include "elst.h" // for ELIST_ITERATOR, ELISTIZE, ELISTIZEH +#include "environ.h" // for l_uint8 +#include "equationdetect.h" // for EquationDetect +#include "errcode.h" // for ASSERT_HOST +#include "helpers.h" // for IntCastRounded, chomp_string +#include "imageio.h" // for IFF_TIFF_G4, IFF_TIFF, IFF_TIFF_G3, ... +#ifndef DISABLED_LEGACY_ENGINE +#include "intfx.h" // for INT_FX_RESULT_STRUCT +#endif +#include "mutableiterator.h" // for MutableIterator +#include "normalis.h" // for kBlnBaselineOffset, kBlnXHeight +#include "ocrclass.h" // for ETEXT_DESC +#if defined(USE_OPENCL) +#include "openclwrapper.h" // for OpenclDevice +#endif +#include "osdetect.h" // for OSResults, OSBestResult, OrientationId... +#include "pageres.h" // for PAGE_RES_IT, WERD_RES, PAGE_RES, CR_DE... +#include "paragraphs.h" // for DetectParagraphs +#include "params.h" // for BoolParam, IntParam, DoubleParam, Stri... +#include "pdblock.h" // for PDBLK +#include "points.h" // for FCOORD +#include "polyblk.h" // for POLY_BLOCK +#include "rect.h" // for TBOX +#include "renderer.h" // for TessResultRenderer +#include "resultiterator.h" // for ResultIterator +#include "stepblob.h" // for C_BLOB_IT, C_BLOB, C_BLOB_LIST +#include "strngs.h" // for STRING +#include "tessdatamanager.h" // for TessdataManager, kTrainedDataSuffix +#include "tesseractclass.h" // for Tesseract +#include "thresholder.h" // for ImageThresholder +#include "tprintf.h" // for tprintf +#include "werd.h" // for WERD, WERD_IT, W_FUZZY_NON, W_FUZZY_SP + +static BOOL_VAR(stream_filelist, false, "Stream a filelist from stdin"); +static STRING_VAR(document_title, "", "Title of output document (used for hOCR and PDF output)"); + +namespace tesseract { + +/** Minimum sensible image size to be worth running tesseract. */ +const int kMinRectSize = 10; +/** Character returned when Tesseract couldn't recognize as anything. */ +const char kTesseractReject = '~'; +/** Character used by UNLV error counter as a reject. */ +const char kUNLVReject = '~'; +/** Character used by UNLV as a suspect marker. */ +const char kUNLVSuspect = '^'; +/** + * Filename used for input image file, from which to derive a name to search + * for a possible UNLV zone file, if none is specified by SetInputName. + */ +static const char* kInputFile = "noname.tif"; +/** + * Temp file used for storing current parameters before applying retry values. + */ +static const char* kOldVarsFile = "failed_vars.txt"; +/** Max string length of an int. */ +const int kMaxIntSize = 22; + +/* Add all available languages recursively. +*/ +static void addAvailableLanguages(const STRING &datadir, const STRING &base, + GenericVector* langs) +{ + const STRING base2 = (base.string()[0] == '\0') ? base : base + "/"; + const size_t extlen = sizeof(kTrainedDataSuffix); +#ifdef _WIN32 + WIN32_FIND_DATA data; + HANDLE handle = FindFirstFile((datadir + base2 + "*").string(), &data); + if (handle != INVALID_HANDLE_VALUE) { + BOOL result = TRUE; + for (; result;) { + char *name = data.cFileName; + // Skip '.', '..', and hidden files + if (name[0] != '.') { + if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == + FILE_ATTRIBUTE_DIRECTORY) { + addAvailableLanguages(datadir, base2 + name, langs); + } else { + size_t len = strlen(name); + if (len > extlen && name[len - extlen] == '.' && + strcmp(&name[len - extlen + 1], kTrainedDataSuffix) == 0) { + name[len - extlen] = '\0'; + langs->push_back(base2 + name); + } + } + } + result = FindNextFile(handle, &data); + } + FindClose(handle); + } +#else // _WIN32 + DIR* dir = opendir((datadir + base).string()); + if (dir != nullptr) { + dirent *de; + while ((de = readdir(dir))) { + char *name = de->d_name; + // Skip '.', '..', and hidden files + if (name[0] != '.') { + struct stat st; + if (stat((datadir + base2 + name).string(), &st) == 0 && + (st.st_mode & S_IFDIR) == S_IFDIR) { + addAvailableLanguages(datadir, base2 + name, langs); + } else { + size_t len = strlen(name); + if (len > extlen && name[len - extlen] == '.' && + strcmp(&name[len - extlen + 1], kTrainedDataSuffix) == 0) { + name[len - extlen] = '\0'; + langs->push_back(base2 + name); + } + } + } + } + closedir(dir); + } +#endif +} + +// Compare two STRING values (used for sorting). +static int CompareSTRING(const void* p1, const void* p2) { + const auto* s1 = static_cast(p1); + const auto* s2 = static_cast(p2); + return strcmp(s1->c_str(), s2->c_str()); +} + +TessBaseAPI::TessBaseAPI() + : tesseract_(nullptr), + osd_tesseract_(nullptr), + equ_detect_(nullptr), + reader_(nullptr), + // Thresholder is initialized to nullptr here, but will be set before use by: + // A constructor of a derived API, SetThresholder(), or + // created implicitly when used in InternalSetImage. + thresholder_(nullptr), + paragraph_models_(nullptr), + block_list_(nullptr), + page_res_(nullptr), + input_file_(nullptr), + output_file_(nullptr), + datapath_(nullptr), + language_(nullptr), + last_oem_requested_(OEM_DEFAULT), + recognition_done_(false), + truth_cb_(nullptr), + rect_left_(0), + rect_top_(0), + rect_width_(0), + rect_height_(0), + image_width_(0), + image_height_(0) { +#if defined(DEBUG) + // The Tesseract executables would use the "C" locale by default, + // but other software which is linked against the Tesseract library + // typically uses the locale from the user's environment. + // Here the default is overridden to allow debugging of potential + // problems caused by the locale settings. + + // Use the current locale if building debug code. + std::locale::global(std::locale("")); +#endif +} + +TessBaseAPI::~TessBaseAPI() { + End(); +} + +int TessBaseAPI::MyOSD() { + return FindLines(); +} + +//int TessBaseAPI::AnalyseLayout() { +// return AnalyseLayout(false); +//} + +/** + * Returns the version identifier as a static string. Do not delete. + */ +const char* TessBaseAPI::Version() { + return PACKAGE_VERSION; +} + +/** + * If compiled with OpenCL AND an available OpenCL + * device is deemed faster than serial code, then + * "device" is populated with the cl_device_id + * and returns sizeof(cl_device_id) + * otherwise *device=nullptr and returns 0. + */ +size_t TessBaseAPI::getOpenCLDevice(void **data) { +#ifdef USE_OPENCL + ds_device device = OpenclDevice::getDeviceSelection(); + if (device.type == DS_DEVICE_OPENCL_DEVICE) { + *data = new cl_device_id; + memcpy(*data, &device.oclDeviceID, sizeof(cl_device_id)); + return sizeof(cl_device_id); + } +#endif + + *data = nullptr; + return 0; +} + +/** + * This method used to write the thresholded image to stderr as a PBM file + * on receipt of a SIGSEGV, SIGFPE, or SIGBUS signal. (Linux/Unix only). + */ +void TessBaseAPI::CatchSignals() { + // Warn API users that an implementation is needed. + tprintf("Deprecated method CatchSignals has only a dummy implementation!\n"); +} + +/** + * Set the name of the input file. Needed only for training and + * loading a UNLV zone file. + */ +void TessBaseAPI::SetInputName(const char* name) { + if (input_file_ == nullptr) + input_file_ = new STRING(name); + else + *input_file_ = name; +} + +/** Set the name of the output files. Needed only for debugging. */ +void TessBaseAPI::SetOutputName(const char* name) { + if (output_file_ == nullptr) + output_file_ = new STRING(name); + else + *output_file_ = name; +} + +bool TessBaseAPI::SetVariable(const char* name, const char* value) { + if (tesseract_ == nullptr) tesseract_ = new Tesseract; + return ParamUtils::SetParam(name, value, SET_PARAM_CONSTRAINT_NON_INIT_ONLY, + tesseract_->params()); +} + +bool TessBaseAPI::SetDebugVariable(const char* name, const char* value) { + if (tesseract_ == nullptr) tesseract_ = new Tesseract; + return ParamUtils::SetParam(name, value, SET_PARAM_CONSTRAINT_DEBUG_ONLY, + tesseract_->params()); +} + +bool TessBaseAPI::GetIntVariable(const char *name, int *value) const { + auto *p = ParamUtils::FindParam( + name, GlobalParams()->int_params, tesseract_->params()->int_params); + if (p == nullptr) return false; + *value = (int32_t)(*p); + return true; +} + +bool TessBaseAPI::GetBoolVariable(const char *name, bool *value) const { + auto *p = ParamUtils::FindParam( + name, GlobalParams()->bool_params, tesseract_->params()->bool_params); + if (p == nullptr) return false; + *value = bool(*p); + return true; +} + +const char *TessBaseAPI::GetStringVariable(const char *name) const { + auto *p = ParamUtils::FindParam( + name, GlobalParams()->string_params, tesseract_->params()->string_params); + return (p != nullptr) ? p->string() : nullptr; +} + +bool TessBaseAPI::GetDoubleVariable(const char *name, double *value) const { + auto *p = ParamUtils::FindParam( + name, GlobalParams()->double_params, tesseract_->params()->double_params); + if (p == nullptr) return false; + *value = (double)(*p); + return true; +} + +/** Get value of named variable as a string, if it exists. */ +bool TessBaseAPI::GetVariableAsString(const char *name, STRING *val) { + return ParamUtils::GetParamAsString(name, tesseract_->params(), val); +} + +/** Print Tesseract parameters to the given file. */ +void TessBaseAPI::PrintVariables(FILE *fp) const { + ParamUtils::PrintParams(fp, tesseract_->params()); +} + +/** + * The datapath must be the name of the data directory or + * some other file in which the data directory resides (for instance argv[0].) + * The language is (usually) an ISO 639-3 string or nullptr will default to eng. + * If numeric_mode is true, then only digits and Roman numerals will + * be returned. + * @return: 0 on success and -1 on initialization failure. + */ +int TessBaseAPI::Init(const char* datapath, const char* language, + OcrEngineMode oem, char **configs, int configs_size, + const GenericVector *vars_vec, + const GenericVector *vars_values, + bool set_only_non_debug_params) { + return Init(datapath, 0, language, oem, configs, configs_size, vars_vec, + vars_values, set_only_non_debug_params, nullptr); +} + +// In-memory version reads the traineddata file directly from the given +// data[data_size] array. Also implements the version with a datapath in data, +// flagged by data_size = 0. +int TessBaseAPI::Init(const char* data, int data_size, const char* language, + OcrEngineMode oem, char** configs, int configs_size, + const GenericVector* vars_vec, + const GenericVector* vars_values, + bool set_only_non_debug_params, FileReader reader) { + // Default language is "eng". + if (language == nullptr) language = "eng"; + STRING datapath = data_size == 0 ? data : language; + // If the datapath, OcrEngineMode or the language have changed - start again. + // Note that the language_ field stores the last requested language that was + // initialized successfully, while tesseract_->lang stores the language + // actually used. They differ only if the requested language was nullptr, in + // which case tesseract_->lang is set to the Tesseract default ("eng"). + if (tesseract_ != nullptr && + (datapath_ == nullptr || language_ == nullptr || *datapath_ != datapath || + last_oem_requested_ != oem || + (*language_ != language && tesseract_->lang != language))) { + delete tesseract_; + tesseract_ = nullptr; + } +#ifdef USE_OPENCL + OpenclDevice od; + od.InitEnv(); +#endif + bool reset_classifier = true; + if (tesseract_ == nullptr) { + reset_classifier = false; + tesseract_ = new Tesseract; + if (reader != nullptr) reader_ = reader; + TessdataManager mgr(reader_); + if (data_size != 0) { + mgr.LoadMemBuffer(language, data, data_size); + } + if (tesseract_->init_tesseract( + datapath.string(), + output_file_ != nullptr ? output_file_->string() : nullptr, + language, oem, configs, configs_size, vars_vec, vars_values, + set_only_non_debug_params, &mgr) != 0) { + return -1; + } + } + + // Update datapath and language requested for the last valid initialization. + if (datapath_ == nullptr) + datapath_ = new STRING(datapath); + else + *datapath_ = datapath; + if ((strcmp(datapath_->string(), "") == 0) && + (strcmp(tesseract_->datadir.string(), "") != 0)) + *datapath_ = tesseract_->datadir; + + if (language_ == nullptr) + language_ = new STRING(language); + else + *language_ = language; + last_oem_requested_ = oem; + +#ifndef DISABLED_LEGACY_ENGINE + // For same language and datapath, just reset the adaptive classifier. + if (reset_classifier) { + tesseract_->ResetAdaptiveClassifier(); + } +#endif // ndef DISABLED_LEGACY_ENGINE + return 0; +} + +/** + * Returns the languages string used in the last valid initialization. + * If the last initialization specified "deu+hin" then that will be + * returned. If hin loaded eng automatically as well, then that will + * not be included in this list. To find the languages actually + * loaded use GetLoadedLanguagesAsVector. + * The returned string should NOT be deleted. + */ +const char* TessBaseAPI::GetInitLanguagesAsString() const { + return (language_ == nullptr || language_->string() == nullptr) ? + "" : language_->string(); +} + +/** + * Returns the loaded languages in the vector of STRINGs. + * Includes all languages loaded by the last Init, including those loaded + * as dependencies of other loaded languages. + */ +void TessBaseAPI::GetLoadedLanguagesAsVector( + GenericVector* langs) const { + langs->clear(); + if (tesseract_ != nullptr) { + langs->push_back(tesseract_->lang); + int num_subs = tesseract_->num_sub_langs(); + for (int i = 0; i < num_subs; ++i) + langs->push_back(tesseract_->get_sub_lang(i)->lang); + } +} + +/** + * Returns the available languages in the sorted vector of STRINGs. + */ +void TessBaseAPI::GetAvailableLanguagesAsVector( + GenericVector* langs) const { + langs->clear(); + if (tesseract_ != nullptr) { + addAvailableLanguages(tesseract_->datadir, "", langs); + langs->sort(CompareSTRING); + } +} + +//TODO(amit): Adapt to lstm +#ifndef DISABLED_LEGACY_ENGINE +/** + * Init only the lang model component of Tesseract. The only functions + * that work after this init are SetVariable and IsValidWord. + * WARNING: temporary! This function will be removed from here and placed + * in a separate API at some future time. + */ +int TessBaseAPI::InitLangMod(const char* datapath, const char* language) { + if (tesseract_ == nullptr) + tesseract_ = new Tesseract; + else + ParamUtils::ResetToDefaults(tesseract_->params()); + TessdataManager mgr; + return tesseract_->init_tesseract_lm(datapath, nullptr, language, &mgr); +} +#endif // ndef DISABLED_LEGACY_ENGINE + +/** + * Init only for page layout analysis. Use only for calls to SetImage and + * AnalysePage. Calls that attempt recognition will generate an error. + */ +void TessBaseAPI::InitForAnalysePage() { + if (tesseract_ == nullptr) { + tesseract_ = new Tesseract; + #ifndef DISABLED_LEGACY_ENGINE + tesseract_->InitAdaptiveClassifier(nullptr); + #endif + } +} + +/** + * Read a "config" file containing a set of parameter name, value pairs. + * Searches the standard places: tessdata/configs, tessdata/tessconfigs + * and also accepts a relative or absolute path name. + */ +void TessBaseAPI::ReadConfigFile(const char* filename) { + tesseract_->read_config_file(filename, SET_PARAM_CONSTRAINT_NON_INIT_ONLY); +} + +/** Same as above, but only set debug params from the given config file. */ +void TessBaseAPI::ReadDebugConfigFile(const char* filename) { + tesseract_->read_config_file(filename, SET_PARAM_CONSTRAINT_DEBUG_ONLY); +} + +/** + * Set the current page segmentation mode. Defaults to PSM_AUTO. + * The mode is stored as an IntParam so it can also be modified by + * ReadConfigFile or SetVariable("tessedit_pageseg_mode", mode as string). + */ +void TessBaseAPI::SetPageSegMode(PageSegMode mode) { + if (tesseract_ == nullptr) + tesseract_ = new Tesseract; + tesseract_->tessedit_pageseg_mode.set_value(mode); +} + +/** Return the current page segmentation mode. */ +PageSegMode TessBaseAPI::GetPageSegMode() const { + if (tesseract_ == nullptr) + return PSM_SINGLE_BLOCK; + return static_cast( + static_cast(tesseract_->tessedit_pageseg_mode)); +} + +/** + * Recognize a rectangle from an image and return the result as a string. + * May be called many times for a single Init. + * Currently has no error checking. + * Greyscale of 8 and color of 24 or 32 bits per pixel may be given. + * Palette color images will not work properly and must be converted to + * 24 bit. + * Binary images of 1 bit per pixel may also be given but they must be + * byte packed with the MSB of the first byte being the first pixel, and a + * one pixel is WHITE. For binary images set bytes_per_pixel=0. + * The recognized text is returned as a char* which is coded + * as UTF8 and must be freed with the delete [] operator. + */ +char* TessBaseAPI::TesseractRect(const unsigned char* imagedata, + int bytes_per_pixel, + int bytes_per_line, + int left, int top, + int width, int height) { + if (tesseract_ == nullptr || width < kMinRectSize || height < kMinRectSize) + return nullptr; // Nothing worth doing. + + // Since this original api didn't give the exact size of the image, + // we have to invent a reasonable value. + int bits_per_pixel = bytes_per_pixel == 0 ? 1 : bytes_per_pixel * 8; + SetImage(imagedata, bytes_per_line * 8 / bits_per_pixel, height + top, + bytes_per_pixel, bytes_per_line); + SetRectangle(left, top, width, height); + + return GetUTF8Text(); +} + +#ifndef DISABLED_LEGACY_ENGINE +/** + * Call between pages or documents etc to free up memory and forget + * adaptive data. + */ +void TessBaseAPI::ClearAdaptiveClassifier() { + if (tesseract_ == nullptr) + return; + tesseract_->ResetAdaptiveClassifier(); + tesseract_->ResetDocumentDictionary(); +} +#endif // ndef DISABLED_LEGACY_ENGINE + +/** + * Provide an image for Tesseract to recognize. Format is as + * TesseractRect above. Copies the image buffer and converts to Pix. + * SetImage clears all recognition results, and sets the rectangle to the + * full image, so it may be followed immediately by a GetUTF8Text, and it + * will automatically perform recognition. + */ +void TessBaseAPI::SetImage(const unsigned char* imagedata, + int width, int height, + int bytes_per_pixel, int bytes_per_line) { + if (InternalSetImage()) { + thresholder_->SetImage(imagedata, width, height, + bytes_per_pixel, bytes_per_line); + SetInputImage(thresholder_->GetPixRect()); + } +} + +void TessBaseAPI::SetSourceResolution(int ppi) { + if (thresholder_) + thresholder_->SetSourceYResolution(ppi); + else + tprintf("Please call SetImage before SetSourceResolution.\n"); +} + +/** + * Provide an image for Tesseract to recognize. As with SetImage above, + * Tesseract takes its own copy of the image, so it need not persist until + * after Recognize. + * Pix vs raw, which to use? + * Use Pix where possible. Tesseract uses Pix as its internal representation + * and it is therefore more efficient to provide a Pix directly. + */ +void TessBaseAPI::SetImage(Pix* pix) { + if (InternalSetImage()) { + if (pixGetSpp(pix) == 4 && pixGetInputFormat(pix) == IFF_PNG) { + // remove alpha channel from png + Pix* p1 = pixRemoveAlpha(pix); + pixSetSpp(p1, 3); + (void)pixCopy(pix, p1); + pixDestroy(&p1); + } + thresholder_->SetImage(pix); + SetInputImage(thresholder_->GetPixRect()); + } +} + +/** + * Restrict recognition to a sub-rectangle of the image. Call after SetImage. + * Each SetRectangle clears the recogntion results so multiple rectangles + * can be recognized with the same image. + */ +void TessBaseAPI::SetRectangle(int left, int top, int width, int height) { + if (thresholder_ == nullptr) + return; + thresholder_->SetRectangle(left, top, width, height); + ClearResults(); +} + +/** + * ONLY available after SetImage if you have Leptonica installed. + * Get a copy of the internal thresholded image from Tesseract. + */ +Pix* TessBaseAPI::GetThresholdedImage() { + if (tesseract_ == nullptr || thresholder_ == nullptr) return nullptr; + if (tesseract_->pix_binary() == nullptr && + !Threshold(tesseract_->mutable_pix_binary())) { + return nullptr; + } + return pixClone(tesseract_->pix_binary()); +} + +/** + * Get the result of page layout analysis as a leptonica-style + * Boxa, Pixa pair, in reading order. + * Can be called before or after Recognize. + */ +Boxa* TessBaseAPI::GetRegions(Pixa** pixa) { + return GetComponentImages(RIL_BLOCK, false, pixa, nullptr); +} + +/** + * Get the textlines as a leptonica-style Boxa, Pixa pair, in reading order. + * Can be called before or after Recognize. + * If blockids is not nullptr, the block-id of each line is also returned as an + * array of one element per line. delete [] after use. + * If paraids is not nullptr, the paragraph-id of each line within its block is + * also returned as an array of one element per line. delete [] after use. + */ +Boxa* TessBaseAPI::GetTextlines(const bool raw_image, const int raw_padding, + Pixa** pixa, int** blockids, int** paraids) { + return GetComponentImages(RIL_TEXTLINE, true, raw_image, raw_padding, + pixa, blockids, paraids); +} + +/** + * Get textlines and strips of image regions as a leptonica-style Boxa, Pixa + * pair, in reading order. Enables downstream handling of non-rectangular + * regions. + * Can be called before or after Recognize. + * If blockids is not nullptr, the block-id of each line is also returned as an + * array of one element per line. delete [] after use. + */ +Boxa* TessBaseAPI::GetStrips(Pixa** pixa, int** blockids) { + return GetComponentImages(RIL_TEXTLINE, false, pixa, blockids); +} + +/** + * Get the words as a leptonica-style + * Boxa, Pixa pair, in reading order. + * Can be called before or after Recognize. + */ +Boxa* TessBaseAPI::GetWords(Pixa** pixa) { + return GetComponentImages(RIL_WORD, true, pixa, nullptr); +} + +/** + * Gets the individual connected (text) components (created + * after pages segmentation step, but before recognition) + * as a leptonica-style Boxa, Pixa pair, in reading order. + * Can be called before or after Recognize. + */ +Boxa* TessBaseAPI::GetConnectedComponents(Pixa** pixa) { + return GetComponentImages(RIL_SYMBOL, true, pixa, nullptr); +} + +/** + * Get the given level kind of components (block, textline, word etc.) as a + * leptonica-style Boxa, Pixa pair, in reading order. + * Can be called before or after Recognize. + * If blockids is not nullptr, the block-id of each component is also returned + * as an array of one element per component. delete [] after use. + * If text_only is true, then only text components are returned. + */ +Boxa* TessBaseAPI::GetComponentImages(PageIteratorLevel level, + bool text_only, bool raw_image, + const int raw_padding, + Pixa** pixa, int** blockids, + int** paraids) { + PageIterator* page_it = GetIterator(); + if (page_it == nullptr) + page_it = AnalyseLayout(); + if (page_it == nullptr) + return nullptr; // Failed. + + // Count the components to get a size for the arrays. + int component_count = 0; + int left, top, right, bottom; + + TessResultCallback* get_bbox = nullptr; + if (raw_image) { + // Get bounding box in original raw image with padding. + get_bbox = NewPermanentTessCallback(page_it, &PageIterator::BoundingBox, + level, raw_padding, + &left, &top, &right, &bottom); + } else { + // Get bounding box from binarized imaged. Note that this could be + // differently scaled from the original image. + get_bbox = NewPermanentTessCallback(page_it, + &PageIterator::BoundingBoxInternal, + level, &left, &top, &right, &bottom); + } + do { + if (get_bbox->Run() && + (!text_only || PTIsTextType(page_it->BlockType()))) + ++component_count; + } while (page_it->Next(level)); + + Boxa* boxa = boxaCreate(component_count); + if (pixa != nullptr) + *pixa = pixaCreate(component_count); + if (blockids != nullptr) + *blockids = new int[component_count]; + if (paraids != nullptr) + *paraids = new int[component_count]; + + int blockid = 0; + int paraid = 0; + int component_index = 0; + page_it->Begin(); + do { + if (get_bbox->Run() && + (!text_only || PTIsTextType(page_it->BlockType()))) { + Box* lbox = boxCreate(left, top, right - left, bottom - top); + boxaAddBox(boxa, lbox, L_INSERT); + if (pixa != nullptr) { + Pix* pix = nullptr; + if (raw_image) { + pix = page_it->GetImage(level, raw_padding, GetInputImage(), &left, + &top); + } else { + pix = page_it->GetBinaryImage(level); + } + pixaAddPix(*pixa, pix, L_INSERT); + pixaAddBox(*pixa, lbox, L_CLONE); + } + if (paraids != nullptr) { + (*paraids)[component_index] = paraid; + if (page_it->IsAtFinalElement(RIL_PARA, level)) + ++paraid; + } + if (blockids != nullptr) { + (*blockids)[component_index] = blockid; + if (page_it->IsAtFinalElement(RIL_BLOCK, level)) { + ++blockid; + paraid = 0; + } + } + ++component_index; + } + } while (page_it->Next(level)); + delete page_it; + delete get_bbox; + return boxa; +} + +int TessBaseAPI::GetThresholdedImageScaleFactor() const { + if (thresholder_ == nullptr) { + return 0; + } + return thresholder_->GetScaleFactor(); +} + +/** + * Runs page layout analysis in the mode set by SetPageSegMode. + * May optionally be called prior to Recognize to get access to just + * the page layout results. Returns an iterator to the results. + * If merge_similar_words is true, words are combined where suitable for use + * with a line recognizer. Use if you want to use AnalyseLayout to find the + * textlines, and then want to process textline fragments with an external + * line recognizer. + * Returns nullptr on error or an empty page. + * The returned iterator must be deleted after use. + * WARNING! This class points to data held within the TessBaseAPI class, and + * therefore can only be used while the TessBaseAPI class still exists and + * has not been subjected to a call of Init, SetImage, Recognize, Clear, End + * DetectOS, or anything else that changes the internal PAGE_RES. + */ +PageIterator* TessBaseAPI::AnalyseLayout() { return AnalyseLayout(false); } + +PageIterator* TessBaseAPI::AnalyseLayout(bool merge_similar_words) { + if (FindLines() == 0) { + if (block_list_->empty()) + return nullptr; // The page was empty. + page_res_ = new PAGE_RES(merge_similar_words, block_list_, nullptr); + DetectParagraphs(false); + return new PageIterator( + page_res_, tesseract_, thresholder_->GetScaleFactor(), + thresholder_->GetScaledYResolution(), + rect_left_, rect_top_, rect_width_, rect_height_); + } + return nullptr; +} + +/** + * Recognize the tesseract global image and return the result as Tesseract + * internal structures. + */ +int TessBaseAPI::Recognize(ETEXT_DESC* monitor) { + if (tesseract_ == nullptr) + return -1; + if (FindLines() != 0) + return -1; + delete page_res_; + if (block_list_->empty()) { + page_res_ = new PAGE_RES(false, block_list_, + &tesseract_->prev_word_best_choice_); + return 0; // Empty page. + } + + tesseract_->SetBlackAndWhitelist(); + recognition_done_ = true; +#ifndef DISABLED_LEGACY_ENGINE + if (tesseract_->tessedit_resegment_from_line_boxes) { + page_res_ = tesseract_->ApplyBoxes(*input_file_, true, block_list_); + } else if (tesseract_->tessedit_resegment_from_boxes) { + page_res_ = tesseract_->ApplyBoxes(*input_file_, false, block_list_); + } else +#endif // ndef DISABLED_LEGACY_ENGINE + { + page_res_ = new PAGE_RES(tesseract_->AnyLSTMLang(), + block_list_, &tesseract_->prev_word_best_choice_); + } + + if (page_res_ == nullptr) { + return -1; + } + + if (tesseract_->tessedit_train_line_recognizer) { + if (!tesseract_->TrainLineRecognizer(*input_file_, *output_file_, block_list_)) { + return -1; + } + tesseract_->CorrectClassifyWords(page_res_); + return 0; + } +#ifndef DISABLED_LEGACY_ENGINE + if (tesseract_->tessedit_make_boxes_from_boxes) { + tesseract_->CorrectClassifyWords(page_res_); + return 0; + } +#endif // ndef DISABLED_LEGACY_ENGINE + + if (truth_cb_ != nullptr) { + tesseract_->wordrec_run_blamer.set_value(true); + auto *page_it = new PageIterator( + page_res_, tesseract_, thresholder_->GetScaleFactor(), + thresholder_->GetScaledYResolution(), + rect_left_, rect_top_, rect_width_, rect_height_); + truth_cb_->Run(tesseract_->getDict().getUnicharset(), + image_height_, page_it, this->tesseract()->pix_grey()); + delete page_it; + } + + int result = 0; + if (tesseract_->interactive_display_mode) { + #ifndef GRAPHICS_DISABLED + tesseract_->pgeditor_main(rect_width_, rect_height_, page_res_); + #endif // GRAPHICS_DISABLED + // The page_res is invalid after an interactive session, so cleanup + // in a way that lets us continue to the next page without crashing. + delete page_res_; + page_res_ = nullptr; + return -1; + #ifndef DISABLED_LEGACY_ENGINE + } else if (tesseract_->tessedit_train_from_boxes) { + STRING fontname; + ExtractFontName(*output_file_, &fontname); + tesseract_->ApplyBoxTraining(fontname, page_res_); + } else if (tesseract_->tessedit_ambigs_training) { + FILE *training_output_file = tesseract_->init_recog_training(*input_file_); + // OCR the page segmented into words by tesseract. + tesseract_->recog_training_segmented( + *input_file_, page_res_, monitor, training_output_file); + fclose(training_output_file); + #endif // ndef DISABLED_LEGACY_ENGINE + } else { + // Now run the main recognition. + bool wait_for_text = true; + GetBoolVariable("paragraph_text_based", &wait_for_text); + if (!wait_for_text) DetectParagraphs(false); + if (tesseract_->recog_all_words(page_res_, monitor, nullptr, nullptr, 0)) { + if (wait_for_text) DetectParagraphs(true); + } else { + result = -1; + } + } + return result; +} + +#ifndef DISABLED_LEGACY_ENGINE +/** Tests the chopper by exhaustively running chop_one_blob. */ +int TessBaseAPI::RecognizeForChopTest(ETEXT_DESC* monitor) { + if (tesseract_ == nullptr) + return -1; + if (thresholder_ == nullptr || thresholder_->IsEmpty()) { + tprintf("Please call SetImage before attempting recognition.\n"); + return -1; + } + if (page_res_ != nullptr) + ClearResults(); + if (FindLines() != 0) + return -1; + // Additional conditions under which chopper test cannot be run + if (tesseract_->interactive_display_mode) return -1; + + recognition_done_ = true; + + page_res_ = new PAGE_RES(false, block_list_, + &(tesseract_->prev_word_best_choice_)); + + PAGE_RES_IT page_res_it(page_res_); + + while (page_res_it.word() != nullptr) { + WERD_RES *word_res = page_res_it.word(); + GenericVector boxes; + tesseract_->MaximallyChopWord(boxes, page_res_it.block()->block, + page_res_it.row()->row, word_res); + page_res_it.forward(); + } + return 0; +} +#endif // ndef DISABLED_LEGACY_ENGINE + +// Takes ownership of the input pix. +void TessBaseAPI::SetInputImage(Pix* pix) { tesseract_->set_pix_original(pix); } + +Pix* TessBaseAPI::GetInputImage() { return tesseract_->pix_original(); } + +const char * TessBaseAPI::GetInputName() { + if (input_file_) + return input_file_->c_str(); + return nullptr; +} + +const char * TessBaseAPI::GetDatapath() { + return tesseract_->datadir.c_str(); +} + +int TessBaseAPI::GetSourceYResolution() { + return thresholder_->GetSourceYResolution(); +} + +// If flist exists, get data from there. Otherwise get data from buf. +// Seems convoluted, but is the easiest way I know of to meet multiple +// goals. Support streaming from stdin, and also work on platforms +// lacking fmemopen. +bool TessBaseAPI::ProcessPagesFileList(FILE *flist, + STRING *buf, + const char* retry_config, + int timeout_millisec, + TessResultRenderer* renderer, + int tessedit_page_number) { + if (!flist && !buf) return false; + int page = (tessedit_page_number >= 0) ? tessedit_page_number : 0; + char pagename[MAX_PATH]; + + GenericVector lines; + if (!flist) { + buf->split('\n', &lines); + if (lines.empty()) return false; + } + + // Skip to the requested page number. + for (int i = 0; i < page; i++) { + if (flist) { + if (fgets(pagename, sizeof(pagename), flist) == nullptr) break; + } + } + + // Begin producing output + if (renderer && !renderer->BeginDocument(document_title.c_str())) { + return false; + } + + // Loop over all pages - or just the requested one + while (true) { + if (flist) { + if (fgets(pagename, sizeof(pagename), flist) == nullptr) break; + } else { + if (page >= lines.size()) break; + snprintf(pagename, sizeof(pagename), "%s", lines[page].c_str()); + } + chomp_string(pagename); + Pix *pix = pixRead(pagename); + if (pix == nullptr) { + tprintf("Image file %s cannot be read!\n", pagename); + return false; + } + tprintf("Page %d : %s\n", page, pagename); + bool r = ProcessPage(pix, page, pagename, retry_config, + timeout_millisec, renderer); + pixDestroy(&pix); + if (!r) return false; + if (tessedit_page_number >= 0) break; + ++page; + } + + // Finish producing output + if (renderer && !renderer->EndDocument()) { + return false; + } + return true; +} + +bool TessBaseAPI::ProcessPagesMultipageTiff(const l_uint8 *data, + size_t size, + const char* filename, + const char* retry_config, + int timeout_millisec, + TessResultRenderer* renderer, + int tessedit_page_number) { +#ifndef ANDROID_BUILD + Pix *pix = nullptr; + int page = (tessedit_page_number >= 0) ? tessedit_page_number : 0; + size_t offset = 0; + for (; ; ++page) { + if (tessedit_page_number >= 0) { + page = tessedit_page_number; + pix = (data) ? pixReadMemTiff(data, size, page) + : pixReadTiff(filename, page); + } else { + pix = (data) ? pixReadMemFromMultipageTiff(data, size, &offset) + : pixReadFromMultipageTiff(filename, &offset); + } + if (pix == nullptr) break; + tprintf("Page %d\n", page + 1); + char page_str[kMaxIntSize]; + snprintf(page_str, kMaxIntSize - 1, "%d", page); + SetVariable("applybox_page", page_str); + bool r = ProcessPage(pix, page, filename, retry_config, + timeout_millisec, renderer); + pixDestroy(&pix); + if (!r) return false; + if (tessedit_page_number >= 0) break; + if (!offset) break; + } + return true; +#else + return false; +#endif +} + +// Master ProcessPages calls ProcessPagesInternal and then does any post- +// processing required due to being in a training mode. +bool TessBaseAPI::ProcessPages(const char* filename, const char* retry_config, + int timeout_millisec, + TessResultRenderer* renderer) { + bool result = + ProcessPagesInternal(filename, retry_config, timeout_millisec, renderer); + #ifndef DISABLED_LEGACY_ENGINE + if (result) { + if (tesseract_->tessedit_train_from_boxes && + !tesseract_->WriteTRFile(*output_file_)) { + tprintf("Write of TR file failed: %s\n", output_file_->string()); + return false; + } + } + #endif // ndef DISABLED_LEGACY_ENGINE + return result; +} + +static size_t +WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) +{ + size = size * nmemb; + std::string* buf = reinterpret_cast(userp); + buf->append(reinterpret_cast(contents), size); + return size; +} + +// In the ideal scenario, Tesseract will start working on data as soon +// as it can. For example, if you stream a filelist through stdin, we +// should start the OCR process as soon as the first filename is +// available. This is particularly useful when hooking Tesseract up to +// slow hardware such as a book scanning machine. +// +// Unfortunately there are tradeoffs. You can't seek on stdin. That +// makes automatic detection of datatype (TIFF? filelist? PNG?) +// impractical. So we support a command line flag to explicitly +// identify the scenario that really matters: filelists on +// stdin. We'll still do our best if the user likes pipes. +bool TessBaseAPI::ProcessPagesInternal(const char* filename, + const char* retry_config, + int timeout_millisec, + TessResultRenderer* renderer) { + bool stdInput = !strcmp(filename, "stdin") || !strcmp(filename, "-"); + if (stdInput) { +#ifdef WIN32 + if (_setmode(_fileno(stdin), _O_BINARY) == -1) + tprintf("ERROR: cin to binary: %s", strerror(errno)); +#endif // WIN32 + } + + if (stream_filelist) { + return ProcessPagesFileList(stdin, nullptr, retry_config, + timeout_millisec, renderer, + tesseract_->tessedit_page_number); + } + + // At this point we are officially in autodection territory. + // That means any data in stdin must be buffered, to make it + // seekable. + std::string buf; + const l_uint8 *data = nullptr; + if (stdInput) { + buf.assign((std::istreambuf_iterator(std::cin)), + (std::istreambuf_iterator())); + data = reinterpret_cast(buf.data()); + } else if (strncmp(filename, "http:", 5) == 0 || + strncmp(filename, "https:", 6) == 0 ) { + // Get image or image list by URL. +#ifdef HAVE_LIBCURL + CURL* curl = curl_easy_init(); + if (curl == nullptr) { + fprintf(stderr, "Error, curl_easy_init failed\n"); + return false; + } else { + CURLcode curlcode; + curlcode = curl_easy_setopt(curl, CURLOPT_URL, filename); + ASSERT_HOST(curlcode == CURLE_OK); + curlcode = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); + ASSERT_HOST(curlcode == CURLE_OK); + curlcode = curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buf); + ASSERT_HOST(curlcode == CURLE_OK); + curlcode = curl_easy_perform(curl); + ASSERT_HOST(curlcode == CURLE_OK); + curl_easy_cleanup(curl); + data = reinterpret_cast(buf.data()); + } +#else + fprintf(stderr, "Error, this tesseract has no URL support\n"); + return false; +#endif + } else { + // Check whether the input file can be read. + if (FILE* file = fopen(filename, "rb")) { + fclose(file); + } else { + fprintf(stderr, "Error, cannot read input file %s: %s\n", + filename, strerror(errno)); + return false; + } + } + + // Here is our autodetection + int format; + int r = (data != nullptr) ? + findFileFormatBuffer(data, &format) : + findFileFormat(filename, &format); + + // Maybe we have a filelist + if (r != 0 || format == IFF_UNKNOWN) { + STRING s; + if (data != nullptr) { + s = buf.c_str(); + } else { + std::ifstream t(filename); + std::string u((std::istreambuf_iterator(t)), + std::istreambuf_iterator()); + s = u.c_str(); + } + return ProcessPagesFileList(nullptr, &s, retry_config, + timeout_millisec, renderer, + tesseract_->tessedit_page_number); + } + + // Maybe we have a TIFF which is potentially multipage + bool tiff = (format == IFF_TIFF || format == IFF_TIFF_PACKBITS || + format == IFF_TIFF_RLE || format == IFF_TIFF_G3 || + format == IFF_TIFF_G4 || format == IFF_TIFF_LZW || +#if LIBLEPT_MAJOR_VERSION > 1 || LIBLEPT_MINOR_VERSION > 76 + format == IFF_TIFF_JPEG || +#endif + format == IFF_TIFF_ZIP); + + // Fail early if we can, before producing any output + Pix *pix = nullptr; + if (!tiff) { + pix = (data != nullptr) ? pixReadMem(data, buf.size()) : pixRead(filename); + if (pix == nullptr) { + return false; + } + } + + // Begin the output + if (renderer && !renderer->BeginDocument(document_title.c_str())) { + pixDestroy(&pix); + return false; + } + + // Produce output + r = (tiff) ? + ProcessPagesMultipageTiff(data, buf.size(), filename, retry_config, + timeout_millisec, renderer, + tesseract_->tessedit_page_number) : + ProcessPage(pix, 0, filename, retry_config, + timeout_millisec, renderer); + + // Clean up memory as needed + pixDestroy(&pix); + + // End the output + if (!r || (renderer && !renderer->EndDocument())) { + return false; + } + return true; +} + +bool TessBaseAPI::ProcessPage(Pix* pix, int page_index, const char* filename, + const char* retry_config, int timeout_millisec, + TessResultRenderer* renderer) { + SetInputName(filename); + SetImage(pix); + bool failed = false; + + if (tesseract_->tessedit_pageseg_mode == PSM_AUTO_ONLY) { + // Disabled character recognition + PageIterator* it = AnalyseLayout(); + + if (it == nullptr) { + failed = true; + } else { + delete it; + } + } else if (tesseract_->tessedit_pageseg_mode == PSM_OSD_ONLY) { + failed = FindLines() != 0; + } else if (timeout_millisec > 0) { + // Running with a timeout. + ETEXT_DESC monitor; + monitor.cancel = nullptr; + monitor.cancel_this = nullptr; + monitor.set_deadline_msecs(timeout_millisec); + + // Now run the main recognition. + failed = Recognize(&monitor) < 0; + } else { + // Normal layout and character recognition with no timeout. + failed = Recognize(nullptr) < 0; + } + + if (tesseract_->tessedit_write_images) { +#ifndef ANDROID_BUILD + Pix* page_pix = GetThresholdedImage(); + pixWrite("tessinput.tif", page_pix, IFF_TIFF_G4); +#endif // ANDROID_BUILD + } + + if (failed && retry_config != nullptr && retry_config[0] != '\0') { + // Save current config variables before switching modes. + FILE* fp = fopen(kOldVarsFile, "wb"); + if (fp == nullptr) { + tprintf("Error, failed to open file \"%s\"\n", kOldVarsFile); + } else { + PrintVariables(fp); + fclose(fp); + } + // Switch to alternate mode for retry. + ReadConfigFile(retry_config); + SetImage(pix); + Recognize(nullptr); + // Restore saved config variables. + ReadConfigFile(kOldVarsFile); + } + + if (renderer && !failed) { + failed = !renderer->AddImage(this); + } + + return !failed; +} + +/** + * Get a left-to-right iterator to the results of LayoutAnalysis and/or + * Recognize. The returned iterator must be deleted after use. + */ +LTRResultIterator* TessBaseAPI::GetLTRIterator() { + if (tesseract_ == nullptr || page_res_ == nullptr) + return nullptr; + return new LTRResultIterator( + page_res_, tesseract_, + thresholder_->GetScaleFactor(), thresholder_->GetScaledYResolution(), + rect_left_, rect_top_, rect_width_, rect_height_); +} + +/** + * Get a reading-order iterator to the results of LayoutAnalysis and/or + * Recognize. The returned iterator must be deleted after use. + * WARNING! This class points to data held within the TessBaseAPI class, and + * therefore can only be used while the TessBaseAPI class still exists and + * has not been subjected to a call of Init, SetImage, Recognize, Clear, End + * DetectOS, or anything else that changes the internal PAGE_RES. + */ +ResultIterator* TessBaseAPI::GetIterator() { + if (tesseract_ == nullptr || page_res_ == nullptr) + return nullptr; + return ResultIterator::StartOfParagraph(LTRResultIterator( + page_res_, tesseract_, + thresholder_->GetScaleFactor(), thresholder_->GetScaledYResolution(), + rect_left_, rect_top_, rect_width_, rect_height_)); +} + +/** + * Get a mutable iterator to the results of LayoutAnalysis and/or Recognize. + * The returned iterator must be deleted after use. + * WARNING! This class points to data held within the TessBaseAPI class, and + * therefore can only be used while the TessBaseAPI class still exists and + * has not been subjected to a call of Init, SetImage, Recognize, Clear, End + * DetectOS, or anything else that changes the internal PAGE_RES. + */ +MutableIterator* TessBaseAPI::GetMutableIterator() { + if (tesseract_ == nullptr || page_res_ == nullptr) + return nullptr; + return new MutableIterator(page_res_, tesseract_, + thresholder_->GetScaleFactor(), + thresholder_->GetScaledYResolution(), + rect_left_, rect_top_, rect_width_, rect_height_); +} + +/** Make a text string from the internal data structures. */ +char* TessBaseAPI::GetUTF8Text() { + if (tesseract_ == nullptr || + (!recognition_done_ && Recognize(nullptr) < 0)) + return nullptr; + STRING text(""); + ResultIterator *it = GetIterator(); + do { + if (it->Empty(RIL_PARA)) continue; + const std::unique_ptr para_text(it->GetUTF8Text(RIL_PARA)); + text += para_text.get(); + } while (it->Next(RIL_PARA)); + char* result = new char[text.length() + 1]; + strncpy(result, text.string(), text.length() + 1); + delete it; + return result; +} + +static void AddBoxToTSV(const PageIterator* it, PageIteratorLevel level, + STRING* text) { + int left, top, right, bottom; + it->BoundingBox(level, &left, &top, &right, &bottom); + text->add_str_int("\t", left); + text->add_str_int("\t", top); + text->add_str_int("\t", right - left); + text->add_str_int("\t", bottom - top); +} + +/** + * Make a TSV-formatted string from the internal data structures. + * page_number is 0-based but will appear in the output as 1-based. + * Returned string must be freed with the delete [] operator. + */ +char* TessBaseAPI::GetTSVText(int page_number) { + if (tesseract_ == nullptr || (page_res_ == nullptr && Recognize(nullptr) < 0)) + return nullptr; + + int lcnt = 1, bcnt = 1, pcnt = 1, wcnt = 1; + int page_id = page_number + 1; // we use 1-based page numbers. + + STRING tsv_str(""); + + int page_num = page_id; + int block_num = 0; + int par_num = 0; + int line_num = 0; + int word_num = 0; + + tsv_str.add_str_int("1\t", page_num); // level 1 - page + tsv_str.add_str_int("\t", block_num); + tsv_str.add_str_int("\t", par_num); + tsv_str.add_str_int("\t", line_num); + tsv_str.add_str_int("\t", word_num); + tsv_str.add_str_int("\t", rect_left_); + tsv_str.add_str_int("\t", rect_top_); + tsv_str.add_str_int("\t", rect_width_); + tsv_str.add_str_int("\t", rect_height_); + tsv_str += "\t-1\t\n"; + + ResultIterator* res_it = GetIterator(); + while (!res_it->Empty(RIL_BLOCK)) { + if (res_it->Empty(RIL_WORD)) { + res_it->Next(RIL_WORD); + continue; + } + + // Add rows for any new block/paragraph/textline. + if (res_it->IsAtBeginningOf(RIL_BLOCK)) { + block_num++; + par_num = 0; + line_num = 0; + word_num = 0; + tsv_str.add_str_int("2\t", page_num); // level 2 - block + tsv_str.add_str_int("\t", block_num); + tsv_str.add_str_int("\t", par_num); + tsv_str.add_str_int("\t", line_num); + tsv_str.add_str_int("\t", word_num); + AddBoxToTSV(res_it, RIL_BLOCK, &tsv_str); + tsv_str += "\t-1\t\n"; // end of row for block + } + if (res_it->IsAtBeginningOf(RIL_PARA)) { + par_num++; + line_num = 0; + word_num = 0; + tsv_str.add_str_int("3\t", page_num); // level 3 - paragraph + tsv_str.add_str_int("\t", block_num); + tsv_str.add_str_int("\t", par_num); + tsv_str.add_str_int("\t", line_num); + tsv_str.add_str_int("\t", word_num); + AddBoxToTSV(res_it, RIL_PARA, &tsv_str); + tsv_str += "\t-1\t\n"; // end of row for para + } + if (res_it->IsAtBeginningOf(RIL_TEXTLINE)) { + line_num++; + word_num = 0; + tsv_str.add_str_int("4\t", page_num); // level 4 - line + tsv_str.add_str_int("\t", block_num); + tsv_str.add_str_int("\t", par_num); + tsv_str.add_str_int("\t", line_num); + tsv_str.add_str_int("\t", word_num); + AddBoxToTSV(res_it, RIL_TEXTLINE, &tsv_str); + tsv_str += "\t-1\t\n"; // end of row for line + } + + // Now, process the word... + int left, top, right, bottom; + res_it->BoundingBox(RIL_WORD, &left, &top, &right, &bottom); + word_num++; + tsv_str.add_str_int("5\t", page_num); // level 5 - word + tsv_str.add_str_int("\t", block_num); + tsv_str.add_str_int("\t", par_num); + tsv_str.add_str_int("\t", line_num); + tsv_str.add_str_int("\t", word_num); + tsv_str.add_str_int("\t", left); + tsv_str.add_str_int("\t", top); + tsv_str.add_str_int("\t", right - left); + tsv_str.add_str_int("\t", bottom - top); + tsv_str.add_str_int("\t", res_it->Confidence(RIL_WORD)); + tsv_str += "\t"; + + // Increment counts if at end of block/paragraph/textline. + if (res_it->IsAtFinalElement(RIL_TEXTLINE, RIL_WORD)) lcnt++; + if (res_it->IsAtFinalElement(RIL_PARA, RIL_WORD)) pcnt++; + if (res_it->IsAtFinalElement(RIL_BLOCK, RIL_WORD)) bcnt++; + + do { + tsv_str += + std::unique_ptr(res_it->GetUTF8Text(RIL_SYMBOL)).get(); + res_it->Next(RIL_SYMBOL); + } while (!res_it->Empty(RIL_BLOCK) && !res_it->IsAtBeginningOf(RIL_WORD)); + tsv_str += "\n"; // end of row + wcnt++; + } + + char* ret = new char[tsv_str.length() + 1]; + strcpy(ret, tsv_str.string()); + delete res_it; + return ret; +} + +/** The 5 numbers output for each box (the usual 4 and a page number.) */ +const int kNumbersPerBlob = 5; +/** + * The number of bytes taken by each number. Since we use int16_t for ICOORD, + * assume only 5 digits max. + */ +const int kBytesPerNumber = 5; +/** + * Multiplier for max expected textlength assumes (kBytesPerNumber + space) + * * kNumbersPerBlob plus the newline. Add to this the + * original UTF8 characters, and one kMaxBytesPerLine for safety. + */ +const int kBytesPerBoxFileLine = (kBytesPerNumber + 1) * kNumbersPerBlob + 1; +/** Max bytes in the decimal representation of int64_t. */ +const int kBytesPer64BitNumber = 20; +/** + * A maximal single box could occupy kNumbersPerBlob numbers at + * kBytesPer64BitNumber digits (if someone sneaks in a 64 bit value) and a + * space plus the newline and the maximum length of a UNICHAR. + * Test against this on each iteration for safety. + */ +const int kMaxBytesPerLine = kNumbersPerBlob * (kBytesPer64BitNumber + 1) + 1 + + UNICHAR_LEN; + +/** + * The recognized text is returned as a char* which is coded + * as a UTF8 box file. + * page_number is a 0-base page index that will appear in the box file. + * Returned string must be freed with the delete [] operator. + */ +char* TessBaseAPI::GetBoxText(int page_number) { + if (tesseract_ == nullptr || + (!recognition_done_ && Recognize(nullptr) < 0)) + return nullptr; + int blob_count; + int utf8_length = TextLength(&blob_count); + int total_length = blob_count * kBytesPerBoxFileLine + utf8_length + + kMaxBytesPerLine; + char* result = new char[total_length]; + result[0] = '\0'; + int output_length = 0; + LTRResultIterator* it = GetLTRIterator(); + do { + int left, top, right, bottom; + if (it->BoundingBox(RIL_SYMBOL, &left, &top, &right, &bottom)) { + const std::unique_ptr text( + it->GetUTF8Text(RIL_SYMBOL)); + // Tesseract uses space for recognition failure. Fix to a reject + // character, kTesseractReject so we don't create illegal box files. + for (int i = 0; text[i] != '\0'; ++i) { + if (text[i] == ' ') + text[i] = kTesseractReject; + } + snprintf(result + output_length, total_length - output_length, + "%s %d %d %d %d %d\n", text.get(), left, image_height_ - bottom, + right, image_height_ - top, page_number); + output_length += strlen(result + output_length); + // Just in case... + if (output_length + kMaxBytesPerLine > total_length) + break; + } + } while (it->Next(RIL_SYMBOL)); + delete it; + return result; +} + +/** + * Conversion table for non-latin characters. + * Maps characters out of the latin set into the latin set. + * TODO(rays) incorporate this translation into unicharset. + */ +const int kUniChs[] = { + 0x20ac, 0x201c, 0x201d, 0x2018, 0x2019, 0x2022, 0x2014, 0 +}; +/** Latin chars corresponding to the unicode chars above. */ +const int kLatinChs[] = { + 0x00a2, 0x0022, 0x0022, 0x0027, 0x0027, 0x00b7, 0x002d, 0 +}; + +/** + * The recognized text is returned as a char* which is coded + * as UNLV format Latin-1 with specific reject and suspect codes. + * Returned string must be freed with the delete [] operator. + */ +char* TessBaseAPI::GetUNLVText() { + if (tesseract_ == nullptr || + (!recognition_done_ && Recognize(nullptr) < 0)) + return nullptr; + bool tilde_crunch_written = false; + bool last_char_was_newline = true; + bool last_char_was_tilde = false; + + int total_length = TextLength(nullptr); + PAGE_RES_IT page_res_it(page_res_); + char* result = new char[total_length]; + char* ptr = result; + for (page_res_it.restart_page(); page_res_it.word () != nullptr; + page_res_it.forward()) { + WERD_RES *word = page_res_it.word(); + // Process the current word. + if (word->unlv_crunch_mode != CR_NONE) { + if (word->unlv_crunch_mode != CR_DELETE && + (!tilde_crunch_written || + (word->unlv_crunch_mode == CR_KEEP_SPACE && + word->word->space() > 0 && + !word->word->flag(W_FUZZY_NON) && + !word->word->flag(W_FUZZY_SP)))) { + if (!word->word->flag(W_BOL) && + word->word->space() > 0 && + !word->word->flag(W_FUZZY_NON) && + !word->word->flag(W_FUZZY_SP)) { + /* Write a space to separate from preceding good text */ + *ptr++ = ' '; + last_char_was_tilde = false; + } + if (!last_char_was_tilde) { + // Write a reject char. + last_char_was_tilde = true; + *ptr++ = kUNLVReject; + tilde_crunch_written = true; + last_char_was_newline = false; + } + } + } else { + // NORMAL PROCESSING of non tilde crunched words. + tilde_crunch_written = false; + tesseract_->set_unlv_suspects(word); + const char* wordstr = word->best_choice->unichar_string().string(); + const STRING& lengths = word->best_choice->unichar_lengths(); + int length = lengths.length(); + int i = 0; + int offset = 0; + + if (last_char_was_tilde && + word->word->space() == 0 && wordstr[offset] == ' ') { + // Prevent adjacent tilde across words - we know that adjacent tildes + // within words have been removed. + // Skip the first character. + offset = lengths[i++]; + } + if (i < length && wordstr[offset] != 0) { + if (!last_char_was_newline) + *ptr++ = ' '; + else + last_char_was_newline = false; + for (; i < length; offset += lengths[i++]) { + if (wordstr[offset] == ' ' || + wordstr[offset] == kTesseractReject) { + *ptr++ = kUNLVReject; + last_char_was_tilde = true; + } else { + if (word->reject_map[i].rejected()) + *ptr++ = kUNLVSuspect; + UNICHAR ch(wordstr + offset, lengths[i]); + int uni_ch = ch.first_uni(); + for (int j = 0; kUniChs[j] != 0; ++j) { + if (kUniChs[j] == uni_ch) { + uni_ch = kLatinChs[j]; + break; + } + } + if (uni_ch <= 0xff) { + *ptr++ = static_cast(uni_ch); + last_char_was_tilde = false; + } else { + *ptr++ = kUNLVReject; + last_char_was_tilde = true; + } + } + } + } + } + if (word->word->flag(W_EOL) && !last_char_was_newline) { + /* Add a new line output */ + *ptr++ = '\n'; + tilde_crunch_written = false; + last_char_was_newline = true; + last_char_was_tilde = false; + } + } + *ptr++ = '\n'; + *ptr = '\0'; + return result; +} + +#ifndef DISABLED_LEGACY_ENGINE + +/** + * Detect the orientation of the input image and apparent script (alphabet). + * orient_deg is the detected clockwise rotation of the input image in degrees + * (0, 90, 180, 270) + * orient_conf is the confidence (15.0 is reasonably confident) + * script_name is an ASCII string, the name of the script, e.g. "Latin" + * script_conf is confidence level in the script + * Returns true on success and writes values to each parameter as an output + */ +bool TessBaseAPI::DetectOrientationScript(int* orient_deg, float* orient_conf, + const char** script_name, + float* script_conf) { + OSResults osr; + + bool osd = DetectOS(&osr); + if (!osd) { + return false; + } + + int orient_id = osr.best_result.orientation_id; + int script_id = osr.get_best_script(orient_id); + if (orient_conf) *orient_conf = osr.best_result.oconfidence; + if (orient_deg) *orient_deg = orient_id * 90; // convert quadrant to degrees + + if (script_name) { + const char* script = osr.unicharset->get_script_from_script_id(script_id); + + *script_name = script; + } + + if (script_conf) *script_conf = osr.best_result.sconfidence; + + return true; +} + +/** + * The recognized text is returned as a char* which is coded + * as UTF8 and must be freed with the delete [] operator. + * page_number is a 0-based page index that will appear in the osd file. + */ +char* TessBaseAPI::GetOsdText(int page_number) { + int orient_deg; + float orient_conf; + const char* script_name; + float script_conf; + + if (!DetectOrientationScript(&orient_deg, &orient_conf, &script_name, + &script_conf)) + return nullptr; + + // clockwise rotation needed to make the page upright + int rotate = OrientationIdToValue(orient_deg / 90); + + std::stringstream stream; + // Use "C" locale (needed for float values orient_conf and script_conf). + stream.imbue(std::locale::classic()); + // Use fixed notation with 2 digits after the decimal point for float values. + stream.precision(2); + stream + << std::fixed + << "Page number: " << page_number << "\n" + << "Orientation in degrees: " << orient_deg << "\n" + << "Rotate: " << rotate << "\n" + << "Orientation confidence: " << orient_conf << "\n" + << "Script: " << script_name << "\n" + << "Script confidence: " << script_conf << "\n"; + const std::string& text = stream.str(); + char* result = new char[text.length() + 1]; + strcpy(result, text.c_str()); + return result; +} + +#endif // ndef DISABLED_LEGACY_ENGINE + +/** Returns the average word confidence for Tesseract page result. */ +int TessBaseAPI::MeanTextConf() { + int* conf = AllWordConfidences(); + if (!conf) return 0; + int sum = 0; + int *pt = conf; + while (*pt >= 0) sum += *pt++; + if (pt != conf) sum /= pt - conf; + delete [] conf; + return sum; +} + +/** Returns an array of all word confidences, terminated by -1. */ +int* TessBaseAPI::AllWordConfidences() { + if (tesseract_ == nullptr || + (!recognition_done_ && Recognize(nullptr) < 0)) + return nullptr; + int n_word = 0; + PAGE_RES_IT res_it(page_res_); + for (res_it.restart_page(); res_it.word() != nullptr; res_it.forward()) + n_word++; + + int* conf = new int[n_word+1]; + n_word = 0; + for (res_it.restart_page(); res_it.word() != nullptr; res_it.forward()) { + WERD_RES *word = res_it.word(); + WERD_CHOICE* choice = word->best_choice; + int w_conf = static_cast(100 + 5 * choice->certainty()); + // This is the eq for converting Tesseract confidence to 1..100 + if (w_conf < 0) w_conf = 0; + if (w_conf > 100) w_conf = 100; + conf[n_word++] = w_conf; + } + conf[n_word] = -1; + return conf; +} + +#ifndef DISABLED_LEGACY_ENGINE +/** + * Applies the given word to the adaptive classifier if possible. + * The word must be SPACE-DELIMITED UTF-8 - l i k e t h i s , so it can + * tell the boundaries of the graphemes. + * Assumes that SetImage/SetRectangle have been used to set the image + * to the given word. The mode arg should be PSM_SINGLE_WORD or + * PSM_CIRCLE_WORD, as that will be used to control layout analysis. + * The currently set PageSegMode is preserved. + * Returns false if adaption was not possible for some reason. + */ +bool TessBaseAPI::AdaptToWordStr(PageSegMode mode, const char* wordstr) { + int debug = 0; + GetIntVariable("applybox_debug", &debug); + bool success = true; + PageSegMode current_psm = GetPageSegMode(); + SetPageSegMode(mode); + SetVariable("classify_enable_learning", "0"); + const std::unique_ptr text(GetUTF8Text()); + if (debug) { + tprintf("Trying to adapt \"%s\" to \"%s\"\n", text.get(), wordstr); + } + if (text != nullptr) { + PAGE_RES_IT it(page_res_); + WERD_RES* word_res = it.word(); + if (word_res != nullptr) { + word_res->word->set_text(wordstr); + // Check to see if text matches wordstr. + int w = 0; + int t; + for (t = 0; text[t] != '\0'; ++t) { + if (text[t] == '\n' || text[t] == ' ') + continue; + while (wordstr[w] == ' ') ++w; + if (text[t] != wordstr[w]) + break; + ++w; + } + if (text[t] != '\0' || wordstr[w] != '\0') { + // No match. + delete page_res_; + GenericVector boxes; + page_res_ = tesseract_->SetupApplyBoxes(boxes, block_list_); + tesseract_->ReSegmentByClassification(page_res_); + tesseract_->TidyUp(page_res_); + PAGE_RES_IT pr_it(page_res_); + if (pr_it.word() == nullptr) + success = false; + else + word_res = pr_it.word(); + } else { + word_res->BestChoiceToCorrectText(); + } + if (success) { + tesseract_->EnableLearning = true; + tesseract_->LearnWord(nullptr, word_res); + } + } else { + success = false; + } + } else { + success = false; + } + SetPageSegMode(current_psm); + return success; +} +#endif // ndef DISABLED_LEGACY_ENGINE + +/** + * Free up recognition results and any stored image data, without actually + * freeing any recognition data that would be time-consuming to reload. + * Afterwards, you must call SetImage or TesseractRect before doing + * any Recognize or Get* operation. + */ +void TessBaseAPI::Clear() { + if (thresholder_ != nullptr) + thresholder_->Clear(); + ClearResults(); + if (tesseract_ != nullptr) SetInputImage(nullptr); +} + +/** + * Close down tesseract and free up all memory. End() is equivalent to + * destructing and reconstructing your TessBaseAPI. + * Once End() has been used, none of the other API functions may be used + * other than Init and anything declared above it in the class definition. + */ +void TessBaseAPI::End() { + Clear(); + delete thresholder_; + thresholder_ = nullptr; + delete page_res_; + page_res_ = nullptr; + delete block_list_; + block_list_ = nullptr; + if (paragraph_models_ != nullptr) { + paragraph_models_->delete_data_pointers(); + delete paragraph_models_; + paragraph_models_ = nullptr; + } + if (osd_tesseract_ == tesseract_) osd_tesseract_ = nullptr; + delete tesseract_; + tesseract_ = nullptr; + delete osd_tesseract_; + osd_tesseract_ = nullptr; + delete equ_detect_; + equ_detect_ = nullptr; + delete input_file_; + input_file_ = nullptr; + delete output_file_; + output_file_ = nullptr; + delete datapath_; + datapath_ = nullptr; + delete language_; + language_ = nullptr; +} + +// Clear any library-level memory caches. +// There are a variety of expensive-to-load constant data structures (mostly +// language dictionaries) that are cached globally -- surviving the Init() +// and End() of individual TessBaseAPI's. This function allows the clearing +// of these caches. +void TessBaseAPI::ClearPersistentCache() { + Dict::GlobalDawgCache()->DeleteUnusedDawgs(); +} + +/** + * Check whether a word is valid according to Tesseract's language model + * returns 0 if the word is invalid, non-zero if valid + */ +int TessBaseAPI::IsValidWord(const char *word) { + return tesseract_->getDict().valid_word(word); +} +// Returns true if utf8_character is defined in the UniCharset. +bool TessBaseAPI::IsValidCharacter(const char *utf8_character) { + return tesseract_->unicharset.contains_unichar(utf8_character); +} + + +// TODO(rays) Obsolete this function and replace with a more aptly named +// function that returns image coordinates rather than tesseract coordinates. +bool TessBaseAPI::GetTextDirection(int* out_offset, float* out_slope) { + PageIterator* it = AnalyseLayout(); + if (it == nullptr) { + return false; + } + int x1, x2, y1, y2; + it->Baseline(RIL_TEXTLINE, &x1, &y1, &x2, &y2); + // Calculate offset and slope (NOTE: Kind of ugly) + if (x2 <= x1) x2 = x1 + 1; + // Convert the point pair to slope/offset of the baseline (in image coords.) + *out_slope = static_cast(y2 - y1) / (x2 - x1); + *out_offset = static_cast(y1 - *out_slope * x1); + // Get the y-coord of the baseline at the left and right edges of the + // textline's bounding box. + int left, top, right, bottom; + if (!it->BoundingBox(RIL_TEXTLINE, &left, &top, &right, &bottom)) { + delete it; + return false; + } + int left_y = IntCastRounded(*out_slope * left + *out_offset); + int right_y = IntCastRounded(*out_slope * right + *out_offset); + // Shift the baseline down so it passes through the nearest bottom-corner + // of the textline's bounding box. This is the difference between the y + // at the lowest (max) edge of the box and the actual box bottom. + *out_offset += bottom - std::max(left_y, right_y); + // Switch back to bottom-up tesseract coordinates. Requires negation of + // the slope and height - offset for the offset. + *out_slope = -*out_slope; + *out_offset = rect_height_ - *out_offset; + delete it; + + return true; +} + +/** Sets Dict::letter_is_okay_ function to point to the given function. */ +void TessBaseAPI::SetDictFunc(DictFunc f) { + if (tesseract_ != nullptr) { + tesseract_->getDict().letter_is_okay_ = f; + } +} + +/** + * Sets Dict::probability_in_context_ function to point to the given + * function. + * + * @param f A single function that returns the probability of the current + * "character" (in general a utf-8 string), given the context of a previous + * utf-8 string. + */ +void TessBaseAPI::SetProbabilityInContextFunc(ProbabilityInContextFunc f) { + if (tesseract_ != nullptr) { + tesseract_->getDict().probability_in_context_ = f; + // Set it for the sublangs too. + int num_subs = tesseract_->num_sub_langs(); + for (int i = 0; i < num_subs; ++i) { + tesseract_->get_sub_lang(i)->getDict().probability_in_context_ = f; + } + } +} + +#ifndef DISABLED_LEGACY_ENGINE +/** Sets Wordrec::fill_lattice_ function to point to the given function. */ +void TessBaseAPI::SetFillLatticeFunc(FillLatticeFunc f) { + if (tesseract_ != nullptr) tesseract_->fill_lattice_ = f; +} +#endif // ndef DISABLED_LEGACY_ENGINE + +/** Common code for setting the image. */ +bool TessBaseAPI::InternalSetImage() { + if (tesseract_ == nullptr) { + tprintf("Please call Init before attempting to set an image.\n"); + return false; + } + if (thresholder_ == nullptr) + thresholder_ = new ImageThresholder; + ClearResults(); + return true; +} + +/** + * Run the thresholder to make the thresholded image, returned in pix, + * which must not be nullptr. *pix must be initialized to nullptr, or point + * to an existing pixDestroyable Pix. + * The usual argument to Threshold is Tesseract::mutable_pix_binary(). + */ +bool TessBaseAPI::Threshold(Pix** pix) { + ASSERT_HOST(pix != nullptr); + if (*pix != nullptr) + pixDestroy(pix); + // Zero resolution messes up the algorithms, so make sure it is credible. + int user_dpi = 0; + GetIntVariable("user_defined_dpi", &user_dpi); + int y_res = thresholder_->GetScaledYResolution(); + if (user_dpi && (user_dpi < kMinCredibleResolution || + user_dpi > kMaxCredibleResolution)) { + tprintf("Warning: User defined image dpi is outside of expected range " + "(%d - %d)!\n", + kMinCredibleResolution, kMaxCredibleResolution); + } + // Always use user defined dpi + if (user_dpi) { + thresholder_->SetSourceYResolution(user_dpi); + } else if (y_res < kMinCredibleResolution || + y_res > kMaxCredibleResolution) { + tprintf("Warning: Invalid resolution %d dpi. Using %d instead.\n", + y_res, kMinCredibleResolution); + thresholder_->SetSourceYResolution(kMinCredibleResolution); + } + auto pageseg_mode = + static_cast( + static_cast(tesseract_->tessedit_pageseg_mode)); + if (!thresholder_->ThresholdToPix(pageseg_mode, pix)) return false; + thresholder_->GetImageSizes(&rect_left_, &rect_top_, + &rect_width_, &rect_height_, + &image_width_, &image_height_); + if (!thresholder_->IsBinary()) { + tesseract_->set_pix_thresholds(thresholder_->GetPixRectThresholds()); + tesseract_->set_pix_grey(thresholder_->GetPixRectGrey()); + } else { + tesseract_->set_pix_thresholds(nullptr); + tesseract_->set_pix_grey(nullptr); + } + // Set the internal resolution that is used for layout parameters from the + // estimated resolution, rather than the image resolution, which may be + // fabricated, but we will use the image resolution, if there is one, to + // report output point sizes. + int estimated_res = ClipToRange(thresholder_->GetScaledEstimatedResolution(), + kMinCredibleResolution, + kMaxCredibleResolution); + if (estimated_res != thresholder_->GetScaledEstimatedResolution()) { + tprintf("Estimated internal resolution %d out of range! " + "Corrected to %d.\n", + thresholder_->GetScaledEstimatedResolution(), estimated_res); + } + tesseract_->set_source_resolution(estimated_res); + return true; +} + +/** Find lines from the image making the BLOCK_LIST. */ +int TessBaseAPI::FindLines() { + if (thresholder_ == nullptr || thresholder_->IsEmpty()) { + tprintf("Please call SetImage before attempting recognition.\n"); + return -1; + } + if (recognition_done_) + ClearResults(); + if (!block_list_->empty()) { + return 0; + } + if (tesseract_ == nullptr) { + tesseract_ = new Tesseract; + #ifndef DISABLED_LEGACY_ENGINE + tesseract_->InitAdaptiveClassifier(nullptr); + #endif + } + if (tesseract_->pix_binary() == nullptr && + !Threshold(tesseract_->mutable_pix_binary())) { + return -1; + } + + tesseract_->PrepareForPageseg(); + +#ifndef DISABLED_LEGACY_ENGINE + if (tesseract_->textord_equation_detect) { + if (equ_detect_ == nullptr && datapath_ != nullptr) { + equ_detect_ = new EquationDetect(datapath_->string(), nullptr); + } + if (equ_detect_ == nullptr) { + tprintf("Warning: Could not set equation detector\n"); + } else { + tesseract_->SetEquationDetect(equ_detect_); + } + } +#endif // ndef DISABLED_LEGACY_ENGINE + + Tesseract* osd_tess = osd_tesseract_; + OSResults osr; + if (PSM_OSD_ENABLED(tesseract_->tessedit_pageseg_mode) && + osd_tess == nullptr) { + if (strcmp(language_->string(), "osd") == 0) { + osd_tess = tesseract_; + } else { + osd_tesseract_ = new Tesseract; + TessdataManager mgr(reader_); + if (datapath_ == nullptr) { + tprintf("Warning: Auto orientation and script detection requested," + " but data path is undefined\n"); + delete osd_tesseract_; + osd_tesseract_ = nullptr; + } else if (osd_tesseract_->init_tesseract(datapath_->string(), nullptr, + "osd", OEM_TESSERACT_ONLY, + nullptr, 0, nullptr, nullptr, + false, &mgr) == 0) { + osd_tess = osd_tesseract_; + osd_tesseract_->set_source_resolution( + thresholder_->GetSourceYResolution()); + } else { + tprintf("Warning: Auto orientation and script detection requested," + " but osd language failed to load\n"); + delete osd_tesseract_; + osd_tesseract_ = nullptr; + } + } + } + + if (tesseract_->SegmentPage(input_file_, block_list_, osd_tess, &osr) < 0) + return -1; + + #if 1 + return osr.best_result.orientation_id; + #else + + // If Devanagari is being recognized, we use different images for page seg + // and for OCR. + tesseract_->PrepareForTessOCR(block_list_, osd_tess, &osr); + return 0; + #endif +} + +/** Delete the pageres and clear the block list ready for a new page. */ +void TessBaseAPI::ClearResults() { + if (tesseract_ != nullptr) { + tesseract_->Clear(); + } + delete page_res_; + page_res_ = nullptr; + recognition_done_ = false; + if (block_list_ == nullptr) + block_list_ = new BLOCK_LIST; + else + block_list_->clear(); + if (paragraph_models_ != nullptr) { + paragraph_models_->delete_data_pointers(); + delete paragraph_models_; + paragraph_models_ = nullptr; + } +} + +/** + * Return the length of the output text string, as UTF8, assuming + * liberally two spacing marks after each word (as paragraphs end with two + * newlines), and assuming a single character reject marker for each rejected + * character. + * Also return the number of recognized blobs in blob_count. + */ +int TessBaseAPI::TextLength(int* blob_count) { + if (tesseract_ == nullptr || page_res_ == nullptr) + return 0; + + PAGE_RES_IT page_res_it(page_res_); + int total_length = 2; + int total_blobs = 0; + // Iterate over the data structures to extract the recognition result. + for (page_res_it.restart_page(); page_res_it.word () != nullptr; + page_res_it.forward()) { + WERD_RES *word = page_res_it.word(); + WERD_CHOICE* choice = word->best_choice; + if (choice != nullptr) { + total_blobs += choice->length() + 2; + total_length += choice->unichar_string().length() + 2; + for (int i = 0; i < word->reject_map.length(); ++i) { + if (word->reject_map[i].rejected()) + ++total_length; + } + } + } + if (blob_count != nullptr) + *blob_count = total_blobs; + return total_length; +} + +#ifndef DISABLED_LEGACY_ENGINE +/** + * Estimates the Orientation And Script of the image. + * Returns true if the image was processed successfully. + */ +bool TessBaseAPI::DetectOS(OSResults* osr) { + if (tesseract_ == nullptr) + return false; + ClearResults(); + if (tesseract_->pix_binary() == nullptr && + !Threshold(tesseract_->mutable_pix_binary())) { + return false; + } + + if (input_file_ == nullptr) + input_file_ = new STRING(kInputFile); + return orientation_and_script_detection(*input_file_, osr, tesseract_) > 0; +} +#endif // ndef DISABLED_LEGACY_ENGINE + +void TessBaseAPI::set_min_orientation_margin(double margin) { + tesseract_->min_orientation_margin.set_value(margin); +} + +/** + * Return text orientation of each block as determined in an earlier page layout + * analysis operation. Orientation is returned as the number of ccw 90-degree + * rotations (in [0..3]) required to make the text in the block upright + * (readable). Note that this may not necessary be the block orientation + * preferred for recognition (such as the case of vertical CJK text). + * + * Also returns whether the text in the block is believed to have vertical + * writing direction (when in an upright page orientation). + * + * The returned array is of length equal to the number of text blocks, which may + * be less than the total number of blocks. The ordering is intended to be + * consistent with GetTextLines(). + */ +void TessBaseAPI::GetBlockTextOrientations(int** block_orientation, + bool** vertical_writing) { + delete[] *block_orientation; + *block_orientation = nullptr; + delete[] *vertical_writing; + *vertical_writing = nullptr; + BLOCK_IT block_it(block_list_); + + block_it.move_to_first(); + int num_blocks = 0; + for (block_it.mark_cycle_pt(); !block_it.cycled_list(); block_it.forward()) { + if (!block_it.data()->pdblk.poly_block()->IsText()) { + continue; + } + ++num_blocks; + } + if (!num_blocks) { + tprintf("WARNING: Found no blocks\n"); + return; + } + *block_orientation = new int[num_blocks]; + *vertical_writing = new bool[num_blocks]; + block_it.move_to_first(); + int i = 0; + for (block_it.mark_cycle_pt(); !block_it.cycled_list(); + block_it.forward()) { + if (!block_it.data()->pdblk.poly_block()->IsText()) { + continue; + } + FCOORD re_rotation = block_it.data()->re_rotation(); + float re_theta = re_rotation.angle(); + FCOORD classify_rotation = block_it.data()->classify_rotation(); + float classify_theta = classify_rotation.angle(); + double rot_theta = - (re_theta - classify_theta) * 2.0 / M_PI; + if (rot_theta < 0) rot_theta += 4; + int num_rotations = static_cast(rot_theta + 0.5); + (*block_orientation)[i] = num_rotations; + // The classify_rotation is non-zero only if the text has vertical + // writing direction. + (*vertical_writing)[i] = classify_rotation.y() != 0.0f; + ++i; + } +} + + +void TessBaseAPI::DetectParagraphs(bool after_text_recognition) { + int debug_level = 0; + GetIntVariable("paragraph_debug_level", &debug_level); + if (paragraph_models_ == nullptr) + paragraph_models_ = new GenericVector; + MutableIterator *result_it = GetMutableIterator(); + do { // Detect paragraphs for this block + GenericVector models; + ::tesseract::DetectParagraphs(debug_level, after_text_recognition, + result_it, &models); + *paragraph_models_ += models; + } while (result_it->Next(RIL_BLOCK)); + delete result_it; +} + +/** This method returns the string form of the specified unichar. */ +const char* TessBaseAPI::GetUnichar(int unichar_id) { + return tesseract_->unicharset.id_to_unichar(unichar_id); +} + +/** Return the pointer to the i-th dawg loaded into tesseract_ object. */ +const Dawg *TessBaseAPI::GetDawg(int i) const { + if (tesseract_ == nullptr || i >= NumDawgs()) return nullptr; + return tesseract_->getDict().GetDawg(i); +} + +/** Return the number of dawgs loaded into tesseract_ object. */ +int TessBaseAPI::NumDawgs() const { + return tesseract_ == nullptr ? 0 : tesseract_->getDict().NumDawgs(); +} + +/** Escape a char string - remove <>&"' with HTML codes. */ +STRING HOcrEscape(const char* text) { + STRING ret; + const char *ptr; + for (ptr = text; *ptr; ptr++) { + switch (*ptr) { + case '<': ret += "<"; break; + case '>': ret += ">"; break; + case '&': ret += "&"; break; + case '"': ret += """; break; + case '\'': ret += "'"; break; + default: ret += *ptr; + } + } + return ret; +} + + +#ifndef DISABLED_LEGACY_ENGINE + + +// ____________________________________________________________________________ +// Ocropus add-ons. + +/** Find lines from the image making the BLOCK_LIST. */ +BLOCK_LIST* TessBaseAPI::FindLinesCreateBlockList() { + ASSERT_HOST(FindLines() == 0); + BLOCK_LIST* result = block_list_; + block_list_ = nullptr; + return result; +} + +/** + * Delete a block list. + * This is to keep BLOCK_LIST pointer opaque + * and let go of including the other headers. + */ +void TessBaseAPI::DeleteBlockList(BLOCK_LIST *block_list) { + delete block_list; +} + + +ROW *TessBaseAPI::MakeTessOCRRow(float baseline, + float xheight, + float descender, + float ascender) { + int32_t xstarts[] = {-32000}; + double quad_coeffs[] = {0, 0, baseline}; + return new ROW(1, + xstarts, + quad_coeffs, + xheight, + ascender - (baseline + xheight), + descender - baseline, + 0, + 0); +} + +/** Creates a TBLOB* from the whole pix. */ +TBLOB *TessBaseAPI::MakeTBLOB(Pix *pix) { + int width = pixGetWidth(pix); + int height = pixGetHeight(pix); + BLOCK block("a character", true, 0, 0, 0, 0, width, height); + + // Create C_BLOBs from the page + extract_edges(pix, &block); + + // Merge all C_BLOBs + C_BLOB_LIST *list = block.blob_list(); + C_BLOB_IT c_blob_it(list); + if (c_blob_it.empty()) + return nullptr; + // Move all the outlines to the first blob. + C_OUTLINE_IT ol_it(c_blob_it.data()->out_list()); + for (c_blob_it.forward(); + !c_blob_it.at_first(); + c_blob_it.forward()) { + C_BLOB *c_blob = c_blob_it.data(); + ol_it.add_list_after(c_blob->out_list()); + } + // Convert the first blob to the output TBLOB. + return TBLOB::PolygonalCopy(false, c_blob_it.data()); +} + +/** + * This method baseline normalizes a TBLOB in-place. The input row is used + * for normalization. The denorm is an optional parameter in which the + * normalization-antidote is returned. + */ +void TessBaseAPI::NormalizeTBLOB(TBLOB *tblob, ROW *row, bool numeric_mode) { + TBOX box = tblob->bounding_box(); + float x_center = (box.left() + box.right()) / 2.0f; + float baseline = row->base_line(x_center); + float scale = kBlnXHeight / row->x_height(); + tblob->Normalize(nullptr, nullptr, nullptr, x_center, baseline, scale, scale, + 0.0f, static_cast(kBlnBaselineOffset), false, nullptr); +} + +/** + * Return a TBLOB * from the whole pix. + * To be freed later with delete. + */ +static TBLOB *make_tesseract_blob(float baseline, float xheight, + float descender, float ascender, + bool numeric_mode, Pix* pix) { + TBLOB *tblob = TessBaseAPI::MakeTBLOB(pix); + + // Normalize TBLOB + ROW *row = + TessBaseAPI::MakeTessOCRRow(baseline, xheight, descender, ascender); + TessBaseAPI::NormalizeTBLOB(tblob, row, numeric_mode); + delete row; + return tblob; +} + +/** + * Adapt to recognize the current image as the given character. + * The image must be preloaded into pix_binary_ and be just an image + * of a single character. + */ +void TessBaseAPI::AdaptToCharacter(const char *unichar_repr, + int length, + float baseline, + float xheight, + float descender, + float ascender) { + UNICHAR_ID id = tesseract_->unicharset.unichar_to_id(unichar_repr, length); + TBLOB *blob = make_tesseract_blob(baseline, xheight, descender, ascender, + tesseract_->classify_bln_numeric_mode, + tesseract_->pix_binary()); + float threshold; + float best_rating = -100; + + + // Classify to get a raw choice. + BLOB_CHOICE_LIST choices; + tesseract_->AdaptiveClassifier(blob, &choices); + BLOB_CHOICE_IT choice_it; + choice_it.set_to_list(&choices); + for (choice_it.mark_cycle_pt(); !choice_it.cycled_list(); + choice_it.forward()) { + if (choice_it.data()->rating() > best_rating) { + best_rating = choice_it.data()->rating(); + } + } + + threshold = tesseract_->matcher_good_threshold; + + if (blob->outlines) + tesseract_->AdaptToChar(blob, id, kUnknownFontinfoId, threshold, + tesseract_->AdaptedTemplates); + delete blob; +} + + +PAGE_RES* TessBaseAPI::RecognitionPass1(BLOCK_LIST* block_list) { + auto *page_res = new PAGE_RES(false, block_list, + &(tesseract_->prev_word_best_choice_)); + tesseract_->recog_all_words(page_res, nullptr, nullptr, nullptr, 1); + return page_res; +} + +PAGE_RES* TessBaseAPI::RecognitionPass2(BLOCK_LIST* block_list, + PAGE_RES* pass1_result) { + if (!pass1_result) + pass1_result = new PAGE_RES(false, block_list, + &(tesseract_->prev_word_best_choice_)); + tesseract_->recog_all_words(pass1_result, nullptr, nullptr, nullptr, 2); + return pass1_result; +} + +struct TESS_CHAR : ELIST_LINK { + char *unicode_repr; + int length; // of unicode_repr + float cost; + TBOX box; + + TESS_CHAR(float _cost, const char *repr, int len = -1) : cost(_cost) { + length = (len == -1 ? strlen(repr) : len); + unicode_repr = new char[length + 1]; + strncpy(unicode_repr, repr, length); + } + + TESS_CHAR() + : unicode_repr(nullptr), + length(0), + cost(0.0f) + { // Satisfies ELISTIZE. + } + ~TESS_CHAR() { + delete [] unicode_repr; + } +}; + +ELISTIZEH(TESS_CHAR) +ELISTIZE(TESS_CHAR) + +static void add_space(TESS_CHAR_IT* it) { + auto *t = new TESS_CHAR(0, " "); + it->add_after_then_move(t); +} + + +static float rating_to_cost(float rating) { + rating = 100 + rating; + // cuddled that to save from coverage profiler + // (I have never seen ratings worse than -100, + // but the check won't hurt) + if (rating < 0) rating = 0; + return rating; +} + +/** + * Extract the OCR results, costs (penalty points for uncertainty), + * and the bounding boxes of the characters. + */ +static void extract_result(TESS_CHAR_IT* out, + PAGE_RES* page_res) { + PAGE_RES_IT page_res_it(page_res); + int word_count = 0; + while (page_res_it.word() != nullptr) { + WERD_RES *word = page_res_it.word(); + const char *str = word->best_choice->unichar_string().string(); + const char *len = word->best_choice->unichar_lengths().string(); + TBOX real_rect = word->word->bounding_box(); + + if (word_count) + add_space(out); + int n = strlen(len); + for (int i = 0; i < n; i++) { + auto *tc = new TESS_CHAR(rating_to_cost(word->best_choice->rating()), + str, *len); + tc->box = real_rect.intersection(word->box_word->BlobBox(i)); + out->add_after_then_move(tc); + str += *len; + len++; + } + page_res_it.forward(); + word_count++; + } +} + +/** + * Extract the OCR results, costs (penalty points for uncertainty), + * and the bounding boxes of the characters. + */ +int TessBaseAPI::TesseractExtractResult(char** text, + int** lengths, + float** costs, + int** x0, + int** y0, + int** x1, + int** y1, + PAGE_RES* page_res) { + TESS_CHAR_LIST tess_chars; + TESS_CHAR_IT tess_chars_it(&tess_chars); + extract_result(&tess_chars_it, page_res); + tess_chars_it.move_to_first(); + int n = tess_chars.length(); + int text_len = 0; + *lengths = new int[n]; + *costs = new float[n]; + *x0 = new int[n]; + *y0 = new int[n]; + *x1 = new int[n]; + *y1 = new int[n]; + int i = 0; + for (tess_chars_it.mark_cycle_pt(); + !tess_chars_it.cycled_list(); + tess_chars_it.forward(), i++) { + TESS_CHAR *tc = tess_chars_it.data(); + text_len += (*lengths)[i] = tc->length; + (*costs)[i] = tc->cost; + (*x0)[i] = tc->box.left(); + (*y0)[i] = tc->box.bottom(); + (*x1)[i] = tc->box.right(); + (*y1)[i] = tc->box.top(); + } + char *p = *text = new char[text_len]; + + tess_chars_it.move_to_first(); + for (tess_chars_it.mark_cycle_pt(); + !tess_chars_it.cycled_list(); + tess_chars_it.forward()) { + TESS_CHAR *tc = tess_chars_it.data(); + strncpy(p, tc->unicode_repr, tc->length); + p += tc->length; + } + return n; +} + +/** This method returns the features associated with the input blob. */ +// The resulting features are returned in int_features, which must be +// of size MAX_NUM_INT_FEATURES. The number of features is returned in +// num_features (or 0 if there was a failure). +// On return feature_outline_index is filled with an index of the outline +// corresponding to each feature in int_features. +// TODO(rays) Fix the caller to out outline_counts instead. +void TessBaseAPI::GetFeaturesForBlob(TBLOB* blob, + INT_FEATURE_STRUCT* int_features, + int* num_features, + int* feature_outline_index) { + GenericVector outline_counts; + GenericVector bl_features; + GenericVector cn_features; + INT_FX_RESULT_STRUCT fx_info; + tesseract_->ExtractFeatures(*blob, false, &bl_features, + &cn_features, &fx_info, &outline_counts); + if (cn_features.empty() || cn_features.size() > MAX_NUM_INT_FEATURES) { + *num_features = 0; + return; // Feature extraction failed. + } + *num_features = cn_features.size(); + memcpy(int_features, &cn_features[0], *num_features * sizeof(cn_features[0])); + // TODO(rays) Pass outline_counts back and simplify the calling code. + if (feature_outline_index != nullptr) { + int f = 0; + for (int i = 0; i < outline_counts.size(); ++i) { + while (f < outline_counts[i]) + feature_outline_index[f++] = i; + } + } +} + +// This method returns the row to which a box of specified dimensions would +// belong. If no good match is found, it returns nullptr. +ROW* TessBaseAPI::FindRowForBox(BLOCK_LIST* blocks, + int left, int top, int right, int bottom) { + TBOX box(left, bottom, right, top); + BLOCK_IT b_it(blocks); + for (b_it.mark_cycle_pt(); !b_it.cycled_list(); b_it.forward()) { + BLOCK* block = b_it.data(); + if (!box.major_overlap(block->pdblk.bounding_box())) + continue; + ROW_IT r_it(block->row_list()); + for (r_it.mark_cycle_pt(); !r_it.cycled_list(); r_it.forward()) { + ROW* row = r_it.data(); + if (!box.major_overlap(row->bounding_box())) + continue; + WERD_IT w_it(row->word_list()); + for (w_it.mark_cycle_pt(); !w_it.cycled_list(); w_it.forward()) { + WERD* word = w_it.data(); + if (box.major_overlap(word->bounding_box())) + return row; + } + } + } + return nullptr; +} + +/** Method to run adaptive classifier on a blob. */ +void TessBaseAPI::RunAdaptiveClassifier(TBLOB* blob, + int num_max_matches, + int* unichar_ids, + float* ratings, + int* num_matches_returned) { + auto* choices = new BLOB_CHOICE_LIST; + tesseract_->AdaptiveClassifier(blob, choices); + BLOB_CHOICE_IT choices_it(choices); + int& index = *num_matches_returned; + index = 0; + for (choices_it.mark_cycle_pt(); + !choices_it.cycled_list() && index < num_max_matches; + choices_it.forward()) { + BLOB_CHOICE* choice = choices_it.data(); + unichar_ids[index] = choice->unichar_id(); + ratings[index] = choice->rating(); + ++index; + } + *num_matches_returned = index; + delete choices; +} +#endif // ndef DISABLED_LEGACY_ENGINE + +} // namespace tesseract. diff --git a/third_party/ocr/tesseract-ocr/src/baseapi.h b/third_party/ocr/tesseract-ocr/src/baseapi.h new file mode 100644 index 00000000..fe12351b --- /dev/null +++ b/third_party/ocr/tesseract-ocr/src/baseapi.h @@ -0,0 +1,946 @@ +/////////////////////////////////////////////////////////////////////// +// File: baseapi.h +// Description: Simple API for calling tesseract. +// Author: Ray Smith +// +// (C) Copyright 2006, Google Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +/////////////////////////////////////////////////////////////////////// + +#ifndef TESSERACT_API_BASEAPI_H_ +#define TESSERACT_API_BASEAPI_H_ + +#include +// To avoid collision with other typenames include the ABSOLUTE MINIMUM +// complexity of includes here. Use forward declarations wherever possible +// and hide includes of complex types in baseapi.cpp. +#include "apitypes.h" +#include "pageiterator.h" +#include "platform.h" +#include "publictypes.h" +#include "resultiterator.h" +#include "serialis.h" +#include "tess_version.h" +#include "tesscallback.h" +#include "thresholder.h" +#include "unichar.h" + +template class GenericVector; +class PAGE_RES; +class PAGE_RES_IT; +class ParagraphModel; +struct BlamerBundle; +class BLOCK_LIST; +class DENORM; +class MATRIX; +class ROW; +class STRING; +class WERD; +struct Pix; +struct Box; +struct Pixa; +struct Boxa; +class ETEXT_DESC; +struct OSResults; +class TBOX; +class UNICHARSET; +class WERD_CHOICE_LIST; + +struct INT_FEATURE_STRUCT; +using INT_FEATURE = INT_FEATURE_STRUCT *; +struct TBLOB; + +namespace tesseract { + +class Dawg; +class Dict; +class EquationDetect; +class PageIterator; +class LTRResultIterator; +class ResultIterator; +class MutableIterator; +class TessResultRenderer; +class Tesseract; +class Trie; +class Wordrec; + +using DictFunc = int (Dict::*)(void *, const UNICHARSET &, UNICHAR_ID, bool) const; +using ProbabilityInContextFunc = double (Dict::*)(const char *, const char *, int, const char *, int); +using ParamsModelClassifyFunc = float (Dict::*)(const char *, void *); +using FillLatticeFunc = void (Wordrec::*)(const MATRIX &, const WERD_CHOICE_LIST &, const UNICHARSET &, BlamerBundle *); +typedef TessCallback4 + TruthCallback; + +/** + * Base class for all tesseract APIs. + * Specific classes can add ability to work on different inputs or produce + * different outputs. + * This class is mostly an interface layer on top of the Tesseract instance + * class to hide the data types so that users of this class don't have to + * include any other Tesseract headers. + */ +class TESS_API TessBaseAPI { + public: + TessBaseAPI(); + virtual ~TessBaseAPI(); + + int MyOSD(); + + /** + * Returns the version identifier as a static string. Do not delete. + */ + static const char* Version(); + + /** + * If compiled with OpenCL AND an available OpenCL + * device is deemed faster than serial code, then + * "device" is populated with the cl_device_id + * and returns sizeof(cl_device_id) + * otherwise *device=nullptr and returns 0. + */ + static size_t getOpenCLDevice(void **device); + + /** + * Writes the thresholded image to stderr as a PBM file on receipt of a + * SIGSEGV, SIGFPE, or SIGBUS signal. (Linux/Unix only). + */ + static void CatchSignals(); + + /** + * Set the name of the input file. Needed for training and + * reading a UNLV zone file, and for searchable PDF output. + */ + void SetInputName(const char* name); + /** + * These functions are required for searchable PDF output. + * We need our hands on the input file so that we can include + * it in the PDF without transcoding. If that is not possible, + * we need the original image. Finally, resolution metadata + * is stored in the PDF so we need that as well. + */ + const char* GetInputName(); + // Takes ownership of the input pix. + void SetInputImage(Pix *pix); + Pix* GetInputImage(); + int GetSourceYResolution(); + const char* GetDatapath(); + + /** Set the name of the bonus output files. Needed only for debugging. */ + void SetOutputName(const char* name); + + /** + * Set the value of an internal "parameter." + * Supply the name of the parameter and the value as a string, just as + * you would in a config file. + * Returns false if the name lookup failed. + * Eg SetVariable("tessedit_char_blacklist", "xyz"); to ignore x, y and z. + * Or SetVariable("classify_bln_numeric_mode", "1"); to set numeric-only mode. + * SetVariable may be used before Init, but settings will revert to + * defaults on End(). + * + * Note: Must be called after Init(). Only works for non-init variables + * (init variables should be passed to Init()). + */ + bool SetVariable(const char* name, const char* value); + bool SetDebugVariable(const char* name, const char* value); + + /** + * Returns true if the parameter was found among Tesseract parameters. + * Fills in value with the value of the parameter. + */ + bool GetIntVariable(const char *name, int *value) const; + bool GetBoolVariable(const char *name, bool *value) const; + bool GetDoubleVariable(const char *name, double *value) const; + + /** + * Returns the pointer to the string that represents the value of the + * parameter if it was found among Tesseract parameters. + */ + const char *GetStringVariable(const char *name) const; + + /** + * Print Tesseract parameters to the given file. + */ + void PrintVariables(FILE *fp) const; + + /** + * Get value of named variable as a string, if it exists. + */ + bool GetVariableAsString(const char *name, STRING *val); + + /** + * Instances are now mostly thread-safe and totally independent, + * but some global parameters remain. Basically it is safe to use multiple + * TessBaseAPIs in different threads in parallel, UNLESS: + * you use SetVariable on some of the Params in classify and textord. + * If you do, then the effect will be to change it for all your instances. + * + * Start tesseract. Returns zero on success and -1 on failure. + * NOTE that the only members that may be called before Init are those + * listed above here in the class definition. + * + * The datapath must be the name of the tessdata directory. + * The language is (usually) an ISO 639-3 string or nullptr will default to eng. + * It is entirely safe (and eventually will be efficient too) to call + * Init multiple times on the same instance to change language, or just + * to reset the classifier. + * The language may be a string of the form [~][+[~]]* indicating + * that multiple languages are to be loaded. Eg hin+eng will load Hindi and + * English. Languages may specify internally that they want to be loaded + * with one or more other languages, so the ~ sign is available to override + * that. Eg if hin were set to load eng by default, then hin+~eng would force + * loading only hin. The number of loaded languages is limited only by + * memory, with the caveat that loading additional languages will impact + * both speed and accuracy, as there is more work to do to decide on the + * applicable language, and there is more chance of hallucinating incorrect + * words. + * WARNING: On changing languages, all Tesseract parameters are reset + * back to their default values. (Which may vary between languages.) + * If you have a rare need to set a Variable that controls + * initialization for a second call to Init you should explicitly + * call End() and then use SetVariable before Init. This is only a very + * rare use case, since there are very few uses that require any parameters + * to be set before Init. + * + * If set_only_non_debug_params is true, only params that do not contain + * "debug" in the name will be set. + */ + int Init(const char* datapath, const char* language, OcrEngineMode mode, + char **configs, int configs_size, + const GenericVector *vars_vec, + const GenericVector *vars_values, + bool set_only_non_debug_params); + int Init(const char* datapath, const char* language, OcrEngineMode oem) { + return Init(datapath, language, oem, nullptr, 0, nullptr, nullptr, false); + } + int Init(const char* datapath, const char* language) { + return Init(datapath, language, OEM_DEFAULT, nullptr, 0, nullptr, nullptr, false); + } + // In-memory version reads the traineddata file directly from the given + // data[data_size] array, and/or reads data via a FileReader. + int Init(const char* data, int data_size, const char* language, + OcrEngineMode mode, char** configs, int configs_size, + const GenericVector* vars_vec, + const GenericVector* vars_values, + bool set_only_non_debug_params, FileReader reader); + + /** + * Returns the languages string used in the last valid initialization. + * If the last initialization specified "deu+hin" then that will be + * returned. If hin loaded eng automatically as well, then that will + * not be included in this list. To find the languages actually + * loaded use GetLoadedLanguagesAsVector. + * The returned string should NOT be deleted. + */ + const char* GetInitLanguagesAsString() const; + + /** + * Returns the loaded languages in the vector of STRINGs. + * Includes all languages loaded by the last Init, including those loaded + * as dependencies of other loaded languages. + */ + void GetLoadedLanguagesAsVector(GenericVector* langs) const; + + /** + * Returns the available languages in the sorted vector of STRINGs. + */ + void GetAvailableLanguagesAsVector(GenericVector* langs) const; + + /** + * Init only the lang model component of Tesseract. The only functions + * that work after this init are SetVariable and IsValidWord. + * WARNING: temporary! This function will be removed from here and placed + * in a separate API at some future time. + */ + int InitLangMod(const char* datapath, const char* language); + + /** + * Init only for page layout analysis. Use only for calls to SetImage and + * AnalysePage. Calls that attempt recognition will generate an error. + */ + void InitForAnalysePage(); + + /** + * Read a "config" file containing a set of param, value pairs. + * Searches the standard places: tessdata/configs, tessdata/tessconfigs + * and also accepts a relative or absolute path name. + * Note: only non-init params will be set (init params are set by Init()). + */ + void ReadConfigFile(const char* filename); + /** Same as above, but only set debug params from the given config file. */ + void ReadDebugConfigFile(const char* filename); + + /** + * Set the current page segmentation mode. Defaults to PSM_SINGLE_BLOCK. + * The mode is stored as an IntParam so it can also be modified by + * ReadConfigFile or SetVariable("tessedit_pageseg_mode", mode as string). + */ + void SetPageSegMode(PageSegMode mode); + + /** Return the current page segmentation mode. */ + PageSegMode GetPageSegMode() const; + + /** + * Recognize a rectangle from an image and return the result as a string. + * May be called many times for a single Init. + * Currently has no error checking. + * Greyscale of 8 and color of 24 or 32 bits per pixel may be given. + * Palette color images will not work properly and must be converted to + * 24 bit. + * Binary images of 1 bit per pixel may also be given but they must be + * byte packed with the MSB of the first byte being the first pixel, and a + * 1 represents WHITE. For binary images set bytes_per_pixel=0. + * The recognized text is returned as a char* which is coded + * as UTF8 and must be freed with the delete [] operator. + * + * Note that TesseractRect is the simplified convenience interface. + * For advanced uses, use SetImage, (optionally) SetRectangle, Recognize, + * and one or more of the Get*Text functions below. + */ + char* TesseractRect(const unsigned char* imagedata, + int bytes_per_pixel, int bytes_per_line, + int left, int top, int width, int height); + + /** + * Call between pages or documents etc to free up memory and forget + * adaptive data. + */ + void ClearAdaptiveClassifier(); + + /** + * @defgroup AdvancedAPI Advanced API + * The following methods break TesseractRect into pieces, so you can + * get hold of the thresholded image, get the text in different formats, + * get bounding boxes, confidences etc. + */ + /* @{ */ + + /** + * Provide an image for Tesseract to recognize. Format is as + * TesseractRect above. Copies the image buffer and converts to Pix. + * SetImage clears all recognition results, and sets the rectangle to the + * full image, so it may be followed immediately by a GetUTF8Text, and it + * will automatically perform recognition. + */ + void SetImage(const unsigned char* imagedata, int width, int height, + int bytes_per_pixel, int bytes_per_line); + + /** + * Provide an image for Tesseract to recognize. As with SetImage above, + * Tesseract takes its own copy of the image, so it need not persist until + * after Recognize. + * Pix vs raw, which to use? + * Use Pix where possible. Tesseract uses Pix as its internal representation + * and it is therefore more efficient to provide a Pix directly. + */ + void SetImage(Pix* pix); + + /** + * Set the resolution of the source image in pixels per inch so font size + * information can be calculated in results. Call this after SetImage(). + */ + void SetSourceResolution(int ppi); + + /** + * Restrict recognition to a sub-rectangle of the image. Call after SetImage. + * Each SetRectangle clears the recogntion results so multiple rectangles + * can be recognized with the same image. + */ + void SetRectangle(int left, int top, int width, int height); + + /** + * In extreme cases only, usually with a subclass of Thresholder, it + * is possible to provide a different Thresholder. The Thresholder may + * be preloaded with an image, settings etc, or they may be set after. + * Note that Tesseract takes ownership of the Thresholder and will + * delete it when it it is replaced or the API is destructed. + */ + void SetThresholder(ImageThresholder* thresholder) { + delete thresholder_; + thresholder_ = thresholder; + ClearResults(); + } + + /** + * Get a copy of the internal thresholded image from Tesseract. + * Caller takes ownership of the Pix and must pixDestroy it. + * May be called any time after SetImage, or after TesseractRect. + */ + Pix* GetThresholdedImage(); + + /** + * Get the result of page layout analysis as a leptonica-style + * Boxa, Pixa pair, in reading order. + * Can be called before or after Recognize. + */ + Boxa* GetRegions(Pixa** pixa); + + /** + * Get the textlines as a leptonica-style + * Boxa, Pixa pair, in reading order. + * Can be called before or after Recognize. + * If raw_image is true, then extract from the original image instead of the + * thresholded image and pad by raw_padding pixels. + * If blockids is not nullptr, the block-id of each line is also returned as an + * array of one element per line. delete [] after use. + * If paraids is not nullptr, the paragraph-id of each line within its block is + * also returned as an array of one element per line. delete [] after use. + */ + Boxa* GetTextlines(bool raw_image, int raw_padding, + Pixa** pixa, int** blockids, int** paraids); + /* + Helper method to extract from the thresholded image. (most common usage) + */ + Boxa* GetTextlines(Pixa** pixa, int** blockids) { + return GetTextlines(false, 0, pixa, blockids, nullptr); + } + + /** + * Get textlines and strips of image regions as a leptonica-style Boxa, Pixa + * pair, in reading order. Enables downstream handling of non-rectangular + * regions. + * Can be called before or after Recognize. + * If blockids is not nullptr, the block-id of each line is also returned as an + * array of one element per line. delete [] after use. + */ + Boxa* GetStrips(Pixa** pixa, int** blockids); + + /** + * Get the words as a leptonica-style + * Boxa, Pixa pair, in reading order. + * Can be called before or after Recognize. + */ + Boxa* GetWords(Pixa** pixa); + + /** + * Gets the individual connected (text) components (created + * after pages segmentation step, but before recognition) + * as a leptonica-style Boxa, Pixa pair, in reading order. + * Can be called before or after Recognize. + * Note: the caller is responsible for calling boxaDestroy() + * on the returned Boxa array and pixaDestroy() on cc array. + */ + Boxa* GetConnectedComponents(Pixa** cc); + + /** + * Get the given level kind of components (block, textline, word etc.) as a + * leptonica-style Boxa, Pixa pair, in reading order. + * Can be called before or after Recognize. + * If blockids is not nullptr, the block-id of each component is also returned + * as an array of one element per component. delete [] after use. + * If blockids is not nullptr, the paragraph-id of each component with its block + * is also returned as an array of one element per component. delete [] after + * use. + * If raw_image is true, then portions of the original image are extracted + * instead of the thresholded image and padded with raw_padding. + * If text_only is true, then only text components are returned. + */ + Boxa* GetComponentImages(PageIteratorLevel level, + bool text_only, bool raw_image, + int raw_padding, + Pixa** pixa, int** blockids, int** paraids); + // Helper function to get binary images with no padding (most common usage). + Boxa* GetComponentImages(const PageIteratorLevel level, + const bool text_only, + Pixa** pixa, int** blockids) { + return GetComponentImages(level, text_only, false, 0, pixa, blockids, nullptr); + } + + /** + * Returns the scale factor of the thresholded image that would be returned by + * GetThresholdedImage() and the various GetX() methods that call + * GetComponentImages(). + * Returns 0 if no thresholder has been set. + */ + int GetThresholdedImageScaleFactor() const; + + /** + * Runs page layout analysis in the mode set by SetPageSegMode. + * May optionally be called prior to Recognize to get access to just + * the page layout results. Returns an iterator to the results. + * If merge_similar_words is true, words are combined where suitable for use + * with a line recognizer. Use if you want to use AnalyseLayout to find the + * textlines, and then want to process textline fragments with an external + * line recognizer. + * Returns nullptr on error or an empty page. + * The returned iterator must be deleted after use. + * WARNING! This class points to data held within the TessBaseAPI class, and + * therefore can only be used while the TessBaseAPI class still exists and + * has not been subjected to a call of Init, SetImage, Recognize, Clear, End + * DetectOS, or anything else that changes the internal PAGE_RES. + */ + PageIterator* AnalyseLayout(); + PageIterator* AnalyseLayout(bool merge_similar_words); + + /** + * Recognize the image from SetAndThresholdImage, generating Tesseract + * internal structures. Returns 0 on success. + * Optional. The Get*Text functions below will call Recognize if needed. + * After Recognize, the output is kept internally until the next SetImage. + */ + int Recognize(ETEXT_DESC* monitor); + + /** + * Methods to retrieve information after SetAndThresholdImage(), + * Recognize() or TesseractRect(). (Recognize is called implicitly if needed.) + */ + + #ifndef DISABLED_LEGACY_ENGINE + /** Variant on Recognize used for testing chopper. */ + int RecognizeForChopTest(ETEXT_DESC* monitor); + #endif + + /** + * Turns images into symbolic text. + * + * filename can point to a single image, a multi-page TIFF, + * or a plain text list of image filenames. + * + * retry_config is useful for debugging. If not nullptr, you can fall + * back to an alternate configuration if a page fails for some + * reason. + * + * timeout_millisec terminates processing if any single page + * takes too long. Set to 0 for unlimited time. + * + * renderer is responible for creating the output. For example, + * use the TessTextRenderer if you want plaintext output, or + * the TessPDFRender to produce searchable PDF. + * + * If tessedit_page_number is non-negative, will only process that + * single page. Works for multi-page tiff file, or filelist. + * + * Returns true if successful, false on error. + */ + bool ProcessPages(const char* filename, const char* retry_config, + int timeout_millisec, TessResultRenderer* renderer); + // Does the real work of ProcessPages. + bool ProcessPagesInternal(const char* filename, const char* retry_config, + int timeout_millisec, TessResultRenderer* renderer); + + /** + * Turn a single image into symbolic text. + * + * The pix is the image processed. filename and page_index are + * metadata used by side-effect processes, such as reading a box + * file or formatting as hOCR. + * + * See ProcessPages for desciptions of other parameters. + */ + bool ProcessPage(Pix* pix, int page_index, const char* filename, + const char* retry_config, int timeout_millisec, + TessResultRenderer* renderer); + + /** + * Get a reading-order iterator to the results of LayoutAnalysis and/or + * Recognize. The returned iterator must be deleted after use. + * WARNING! This class points to data held within the TessBaseAPI class, and + * therefore can only be used while the TessBaseAPI class still exists and + * has not been subjected to a call of Init, SetImage, Recognize, Clear, End + * DetectOS, or anything else that changes the internal PAGE_RES. + */ + ResultIterator* GetIterator(); + + /** + * Get a mutable iterator to the results of LayoutAnalysis and/or Recognize. + * The returned iterator must be deleted after use. + * WARNING! This class points to data held within the TessBaseAPI class, and + * therefore can only be used while the TessBaseAPI class still exists and + * has not been subjected to a call of Init, SetImage, Recognize, Clear, End + * DetectOS, or anything else that changes the internal PAGE_RES. + */ + MutableIterator* GetMutableIterator(); + + /** + * The recognized text is returned as a char* which is coded + * as UTF8 and must be freed with the delete [] operator. + */ + char* GetUTF8Text(); + + /** + * Make a HTML-formatted string with hOCR markup from the internal + * data structures. + * page_number is 0-based but will appear in the output as 1-based. + * monitor can be used to + * cancel the recognition + * receive progress callbacks + * Returned string must be freed with the delete [] operator. + */ + char* GetHOCRText(ETEXT_DESC* monitor, int page_number); + + /** + * Make a HTML-formatted string with hOCR markup from the internal + * data structures. + * page_number is 0-based but will appear in the output as 1-based. + * Returned string must be freed with the delete [] operator. + */ + char* GetHOCRText(int page_number); + + /** + * Make an XML-formatted string with Alto markup from the internal + * data structures. + */ + char* GetAltoText(ETEXT_DESC* monitor, int page_number); + + + /** + * Make an XML-formatted string with Alto markup from the internal + * data structures. + */ + char* GetAltoText(int page_number); + + /** + * Make a TSV-formatted string from the internal data structures. + * page_number is 0-based but will appear in the output as 1-based. + * Returned string must be freed with the delete [] operator. + */ + char* GetTSVText(int page_number); + + /** + * Make a box file for LSTM training from the internal data structures. + * Constructs coordinates in the original image - not just the rectangle. + * page_number is a 0-based page index that will appear in the box file. + * Returned string must be freed with the delete [] operator. + */ + char* GetLSTMBoxText(int page_number); + + /** + * The recognized text is returned as a char* which is coded in the same + * format as a box file used in training. + * Constructs coordinates in the original image - not just the rectangle. + * page_number is a 0-based page index that will appear in the box file. + * Returned string must be freed with the delete [] operator. + */ + char* GetBoxText(int page_number); + + /** + * The recognized text is returned as a char* which is coded in the same + * format as a WordStr box file used in training. + * page_number is a 0-based page index that will appear in the box file. + * Returned string must be freed with the delete [] operator. + */ + char* GetWordStrBoxText(int page_number); + + /** + * The recognized text is returned as a char* which is coded + * as UNLV format Latin-1 with specific reject and suspect codes. + * Returned string must be freed with the delete [] operator. + */ + char* GetUNLVText(); + + /** + * Detect the orientation of the input image and apparent script (alphabet). + * orient_deg is the detected clockwise rotation of the input image in degrees + * (0, 90, 180, 270) + * orient_conf is the confidence (15.0 is reasonably confident) + * script_name is an ASCII string, the name of the script, e.g. "Latin" + * script_conf is confidence level in the script + * Returns true on success and writes values to each parameter as an output + */ + bool DetectOrientationScript(int* orient_deg, float* orient_conf, + const char** script_name, float* script_conf); + + /** + * The recognized text is returned as a char* which is coded + * as UTF8 and must be freed with the delete [] operator. + * page_number is a 0-based page index that will appear in the osd file. + */ + char* GetOsdText(int page_number); + + /** Returns the (average) confidence value between 0 and 100. */ + int MeanTextConf(); + /** + * Returns all word confidences (between 0 and 100) in an array, terminated + * by -1. The calling function must delete [] after use. + * The number of confidences should correspond to the number of space- + * delimited words in GetUTF8Text. + */ + int* AllWordConfidences(); + +#ifndef DISABLED_LEGACY_ENGINE + /** + * Applies the given word to the adaptive classifier if possible. + * The word must be SPACE-DELIMITED UTF-8 - l i k e t h i s , so it can + * tell the boundaries of the graphemes. + * Assumes that SetImage/SetRectangle have been used to set the image + * to the given word. The mode arg should be PSM_SINGLE_WORD or + * PSM_CIRCLE_WORD, as that will be used to control layout analysis. + * The currently set PageSegMode is preserved. + * Returns false if adaption was not possible for some reason. + */ + bool AdaptToWordStr(PageSegMode mode, const char* wordstr); +#endif // ndef DISABLED_LEGACY_ENGINE + + /** + * Free up recognition results and any stored image data, without actually + * freeing any recognition data that would be time-consuming to reload. + * Afterwards, you must call SetImage or TesseractRect before doing + * any Recognize or Get* operation. + */ + void Clear(); + + /** + * Close down tesseract and free up all memory. End() is equivalent to + * destructing and reconstructing your TessBaseAPI. + * Once End() has been used, none of the other API functions may be used + * other than Init and anything declared above it in the class definition. + */ + void End(); + + /** + * Clear any library-level memory caches. + * There are a variety of expensive-to-load constant data structures (mostly + * language dictionaries) that are cached globally -- surviving the Init() + * and End() of individual TessBaseAPI's. This function allows the clearing + * of these caches. + **/ + static void ClearPersistentCache(); + + /** + * Check whether a word is valid according to Tesseract's language model + * @return 0 if the word is invalid, non-zero if valid. + * @warning temporary! This function will be removed from here and placed + * in a separate API at some future time. + */ + int IsValidWord(const char *word); + // Returns true if utf8_character is defined in the UniCharset. + bool IsValidCharacter(const char *utf8_character); + + + bool GetTextDirection(int* out_offset, float* out_slope); + + /** Sets Dict::letter_is_okay_ function to point to the given function. */ + void SetDictFunc(DictFunc f); + + /** Sets Dict::probability_in_context_ function to point to the given + * function. + */ + void SetProbabilityInContextFunc(ProbabilityInContextFunc f); + + /** + * Estimates the Orientation And Script of the image. + * @return true if the image was processed successfully. + */ + bool DetectOS(OSResults*); + + /** + * Return text orientation of each block as determined by an earlier run + * of layout analysis. + */ + void GetBlockTextOrientations(int** block_orientation, + bool** vertical_writing); + + + #ifndef DISABLED_LEGACY_ENGINE + + /** Sets Wordrec::fill_lattice_ function to point to the given function. */ + void SetFillLatticeFunc(FillLatticeFunc f); + + /** Find lines from the image making the BLOCK_LIST. */ + BLOCK_LIST* FindLinesCreateBlockList(); + + /** + * Delete a block list. + * This is to keep BLOCK_LIST pointer opaque + * and let go of including the other headers. + */ + static void DeleteBlockList(BLOCK_LIST* block_list); + + /** Returns a ROW object created from the input row specification. */ + static ROW *MakeTessOCRRow(float baseline, float xheight, + float descender, float ascender); + + /** Returns a TBLOB corresponding to the entire input image. */ + static TBLOB *MakeTBLOB(Pix *pix); + + /** + * This method baseline normalizes a TBLOB in-place. The input row is used + * for normalization. The denorm is an optional parameter in which the + * normalization-antidote is returned. + */ + static void NormalizeTBLOB(TBLOB *tblob, ROW *row, bool numeric_mode); + + /** This method returns the features associated with the input image. */ + void GetFeaturesForBlob(TBLOB* blob, INT_FEATURE_STRUCT* int_features, + int* num_features, int* feature_outline_index); + + /** + * This method returns the row to which a box of specified dimensions would + * belong. If no good match is found, it returns nullptr. + */ + static ROW* FindRowForBox(BLOCK_LIST* blocks, int left, int top, + int right, int bottom); + + /** + * Method to run adaptive classifier on a blob. + * It returns at max num_max_matches results. + */ + void RunAdaptiveClassifier(TBLOB* blob, + int num_max_matches, + int* unichar_ids, + float* ratings, + int* num_matches_returned); +#endif // ndef DISABLED_LEGACY_ENGINE + + /** This method returns the string form of the specified unichar. */ + const char* GetUnichar(int unichar_id); + + /** Return the pointer to the i-th dawg loaded into tesseract_ object. */ + const Dawg *GetDawg(int i) const; + + /** Return the number of dawgs loaded into tesseract_ object. */ + int NumDawgs() const; + + Tesseract* tesseract() const { return tesseract_; } + + OcrEngineMode oem() const { return last_oem_requested_; } + + void InitTruthCallback(TruthCallback *cb) { truth_cb_ = cb; } + + void set_min_orientation_margin(double margin); + /* @} */ + + protected: + + /** Common code for setting the image. Returns true if Init has been called. */ + TESS_LOCAL bool InternalSetImage(); + + /** + * Run the thresholder to make the thresholded image. If pix is not nullptr, + * the source is thresholded to pix instead of the internal IMAGE. + */ + TESS_LOCAL virtual bool Threshold(Pix** pix); + + /** + * Find lines from the image making the BLOCK_LIST. + * @return 0 on success. + */ + TESS_LOCAL int FindLines(); + + /** Delete the pageres and block list ready for a new page. */ + void ClearResults(); + + /** + * Return an LTR Result Iterator -- used only for training, as we really want + * to ignore all BiDi smarts at that point. + * delete once you're done with it. + */ + TESS_LOCAL LTRResultIterator* GetLTRIterator(); + + /** + * Return the length of the output text string, as UTF8, assuming + * one newline per line and one per block, with a terminator, + * and assuming a single character reject marker for each rejected character. + * Also return the number of recognized blobs in blob_count. + */ + TESS_LOCAL int TextLength(int* blob_count); + + //// paragraphs.cpp //////////////////////////////////////////////////// + TESS_LOCAL void DetectParagraphs(bool after_text_recognition); + + #ifndef DISABLED_LEGACY_ENGINE + + /** @defgroup ocropusAddOns ocropus add-ons */ + /* @{ */ + + /** + * Adapt to recognize the current image as the given character. + * The image must be preloaded and be just an image of a single character. + */ + TESS_LOCAL void AdaptToCharacter(const char *unichar_repr, + int length, + float baseline, + float xheight, + float descender, + float ascender); + + /** Recognize text doing one pass only, using settings for a given pass. */ + TESS_LOCAL PAGE_RES* RecognitionPass1(BLOCK_LIST* block_list); + + TESS_LOCAL PAGE_RES* RecognitionPass2(BLOCK_LIST* block_list, + PAGE_RES* pass1_result); + + /** + * Extract the OCR results, costs (penalty points for uncertainty), + * and the bounding boxes of the characters. + */ + TESS_LOCAL static int TesseractExtractResult(char** text, + int** lengths, + float** costs, + int** x0, + int** y0, + int** x1, + int** y1, + PAGE_RES* page_res); + + TESS_LOCAL const PAGE_RES* GetPageRes() const { return page_res_; } + /* @} */ +#endif // ndef DISABLED_LEGACY_ENGINE + + protected: + Tesseract* tesseract_; ///< The underlying data object. + Tesseract* osd_tesseract_; ///< For orientation & script detection. + EquationDetect* equ_detect_; ///* paragraph_models_; + BLOCK_LIST* block_list_; ///< The page layout. + PAGE_RES* page_res_; ///< The page-level data. + STRING* input_file_; ///< Name used by training code. + STRING* output_file_; ///< Name used by debug code. + STRING* datapath_; ///< Current location of tessdata. + STRING* language_; ///< Last initialized language. + OcrEngineMode last_oem_requested_; ///< Last ocr language mode requested. + bool recognition_done_; ///< page_res_ contains recognition data. + TruthCallback *truth_cb_; /// fxn for setting truth_* in WERD_RES + + /** + * @defgroup ThresholderParams Thresholder Parameters + * Parameters saved from the Thresholder. Needed to rebuild coordinates. + */ + /* @{ */ + int rect_left_; + int rect_top_; + int rect_width_; + int rect_height_; + int image_width_; + int image_height_; + /* @} */ + + private: + // A list of image filenames gets special consideration + bool ProcessPagesFileList(FILE *fp, + STRING *buf, + const char* retry_config, int timeout_millisec, + TessResultRenderer* renderer, + int tessedit_page_number); + // TIFF supports multipage so gets special consideration. + bool ProcessPagesMultipageTiff(const unsigned char *data, + size_t size, + const char* filename, + const char* retry_config, + int timeout_millisec, + TessResultRenderer* renderer, + int tessedit_page_number); + // There's currently no way to pass a document title from the + // Tesseract command line, and we have multiple places that choose + // to set the title to an empty string. Using a single named + // variable will hopefully reduce confusion if the situation changes + // in the future. + const char *unknown_title_ = ""; +}; // class TessBaseAPI. + +/** Escape a char string - remove &<>"' with HTML codes. */ +STRING HOcrEscape(const char* text); +} // namespace tesseract. + +#endif // TESSERACT_API_BASEAPI_H_ diff --git a/third_party/ocr/tesseract-ocr/src/capi.cpp b/third_party/ocr/tesseract-ocr/src/capi.cpp new file mode 100644 index 00000000..c57ab30a --- /dev/null +++ b/third_party/ocr/tesseract-ocr/src/capi.cpp @@ -0,0 +1,919 @@ +/////////////////////////////////////////////////////////////////////// +// File: capi.cpp +// Description: C-API TessBaseAPI +// +// (C) Copyright 2012, Google Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +/////////////////////////////////////////////////////////////////////// + +#ifndef TESS_CAPI_INCLUDE_BASEAPI +# define TESS_CAPI_INCLUDE_BASEAPI +#endif +#include "capi.h" +#include "genericvector.h" +#include "strngs.h" + +TESS_API int MyOSD(TessBaseAPI* api) { + return api->MyOSD(); +} + +TESS_API const char* TESS_CALL TessVersion() { + return TessBaseAPI::Version(); +} + +TESS_API void TESS_CALL TessDeleteText(const char* text) { + delete[] text; +} + +TESS_API void TESS_CALL TessDeleteTextArray(char** arr) { + for (char** pos = arr; *pos != nullptr; ++pos) { + delete[] * pos; + } + delete[] arr; +} + +TESS_API void TESS_CALL TessDeleteIntArray(const int* arr) { + delete[] arr; +} + +#ifndef DISABLED_LEGACY_ENGINE +TESS_API void TESS_CALL TessDeleteBlockList(BLOCK_LIST* block_list) { + TessBaseAPI::DeleteBlockList(block_list); +} +#endif + +TESS_API TessResultRenderer* TESS_CALL +TessTextRendererCreate(const char* outputbase) { + return new TessTextRenderer(outputbase); +} + +TESS_API TessResultRenderer* TESS_CALL +TessHOcrRendererCreate(const char* outputbase) { + return new TessHOcrRenderer(outputbase); +} + +TESS_API TessResultRenderer* TESS_CALL +TessHOcrRendererCreate2(const char* outputbase, BOOL font_info) { + return new TessHOcrRenderer(outputbase, font_info != 0); +} + +TESS_API TessResultRenderer* TESS_CALL +TessAltoRendererCreate(const char* outputbase) { + return new TessAltoRenderer(outputbase); +} + +TESS_API TessResultRenderer* TESS_CALL +TessTsvRendererCreate(const char* outputbase) { + return new TessTsvRenderer(outputbase); +} + +TESS_API TessResultRenderer* TESS_CALL TessPDFRendererCreate( + const char* outputbase, const char* datadir, BOOL textonly) { + return new TessPDFRenderer(outputbase, datadir, textonly != 0); +} + +TESS_API TessResultRenderer* TESS_CALL +TessUnlvRendererCreate(const char* outputbase) { + return new TessUnlvRenderer(outputbase); +} + +TESS_API TessResultRenderer* TESS_CALL +TessBoxTextRendererCreate(const char* outputbase) { + return new TessBoxTextRenderer(outputbase); +} + +TESS_API TessResultRenderer* TESS_CALL +TessWordStrBoxRendererCreate(const char* outputbase) { + return new TessWordStrBoxRenderer(outputbase); +} + +TESS_API TessResultRenderer* TESS_CALL +TessLSTMBoxRendererCreate(const char* outputbase) { + return new TessLSTMBoxRenderer(outputbase); +} + +TESS_API void TESS_CALL TessDeleteResultRenderer(TessResultRenderer* renderer) { + delete renderer; +} + +TESS_API void TESS_CALL TessResultRendererInsert(TessResultRenderer* renderer, + TessResultRenderer* next) { + renderer->insert(next); +} + +TESS_API TessResultRenderer* TESS_CALL +TessResultRendererNext(TessResultRenderer* renderer) { + return renderer->next(); +} + +TESS_API BOOL TESS_CALL TessResultRendererBeginDocument( + TessResultRenderer* renderer, const char* title) { + return static_cast(renderer->BeginDocument(title)); +} + +TESS_API BOOL TESS_CALL TessResultRendererAddImage(TessResultRenderer* renderer, + TessBaseAPI* api) { + return static_cast(renderer->AddImage(api)); +} + +TESS_API BOOL TESS_CALL +TessResultRendererEndDocument(TessResultRenderer* renderer) { + return static_cast(renderer->EndDocument()); +} + +TESS_API const char* TESS_CALL +TessResultRendererExtention(TessResultRenderer* renderer) { + return renderer->file_extension(); +} + +TESS_API const char* TESS_CALL +TessResultRendererTitle(TessResultRenderer* renderer) { + return renderer->title(); +} + +TESS_API int TESS_CALL +TessResultRendererImageNum(TessResultRenderer* renderer) { + return renderer->imagenum(); +} + +TESS_API TessBaseAPI* TESS_CALL TessBaseAPICreate() { + return new TessBaseAPI; +} + +TESS_API void TESS_CALL TessBaseAPIDelete(TessBaseAPI* handle) { + delete handle; +} + +TESS_API size_t TESS_CALL TessBaseAPIGetOpenCLDevice(TessBaseAPI* /*handle*/, + void** device) { + return TessBaseAPI::getOpenCLDevice(device); +} + +TESS_API void TESS_CALL TessBaseAPISetInputName(TessBaseAPI* handle, + const char* name) { + handle->SetInputName(name); +} + +TESS_API const char* TESS_CALL TessBaseAPIGetInputName(TessBaseAPI* handle) { + return handle->GetInputName(); +} + +TESS_API void TESS_CALL TessBaseAPISetInputImage(TessBaseAPI* handle, + Pix* pix) { + handle->SetInputImage(pix); +} + +TESS_API Pix* TESS_CALL TessBaseAPIGetInputImage(TessBaseAPI* handle) { + return handle->GetInputImage(); +} + +TESS_API int TESS_CALL TessBaseAPIGetSourceYResolution(TessBaseAPI* handle) { + return handle->GetSourceYResolution(); +} + +TESS_API const char* TESS_CALL TessBaseAPIGetDatapath(TessBaseAPI* handle) { + return handle->GetDatapath(); +} + +TESS_API void TESS_CALL TessBaseAPISetOutputName(TessBaseAPI* handle, + const char* name) { + handle->SetOutputName(name); +} + +TESS_API BOOL TESS_CALL TessBaseAPISetVariable(TessBaseAPI* handle, + const char* name, + const char* value) { + return static_cast(handle->SetVariable(name, value)); +} + +TESS_API BOOL TESS_CALL TessBaseAPISetDebugVariable(TessBaseAPI* handle, + const char* name, + const char* value) { + return static_cast(handle->SetDebugVariable(name, value)); +} + +TESS_API BOOL TESS_CALL TessBaseAPIGetIntVariable(const TessBaseAPI* handle, + const char* name, + int* value) { + return static_cast(handle->GetIntVariable(name, value)); +} + +TESS_API BOOL TESS_CALL TessBaseAPIGetBoolVariable(const TessBaseAPI* handle, + const char* name, + BOOL* value) { + bool boolValue; + bool result = handle->GetBoolVariable(name, &boolValue); + if (result) { + *value = static_cast(boolValue); + } + return static_cast(result); +} + +TESS_API BOOL TESS_CALL TessBaseAPIGetDoubleVariable(const TessBaseAPI* handle, + const char* name, + double* value) { + return static_cast(handle->GetDoubleVariable(name, value)); +} + +TESS_API const char* TESS_CALL +TessBaseAPIGetStringVariable(const TessBaseAPI* handle, const char* name) { + return handle->GetStringVariable(name); +} + +TESS_API void TESS_CALL TessBaseAPIPrintVariables(const TessBaseAPI* handle, + FILE* fp) { + handle->PrintVariables(fp); +} + +TESS_API BOOL TESS_CALL TessBaseAPIPrintVariablesToFile( + const TessBaseAPI* handle, const char* filename) { + FILE* fp = fopen(filename, "w"); + if (fp != nullptr) { + handle->PrintVariables(fp); + fclose(fp); + return TRUE; + } + return FALSE; +} + +TESS_API BOOL TESS_CALL TessBaseAPIGetVariableAsString(TessBaseAPI* handle, + const char* name, + STRING* val) { + return static_cast(handle->GetVariableAsString(name, val)); +} + +TESS_API int TESS_CALL TessBaseAPIInit4( + TessBaseAPI* handle, const char* datapath, const char* language, + TessOcrEngineMode mode, char** configs, int configs_size, char** vars_vec, + char** vars_values, size_t vars_vec_size, BOOL set_only_non_debug_params) { + GenericVector varNames; + GenericVector varValues; + if (vars_vec != nullptr && vars_values != nullptr) { + for (size_t i = 0; i < vars_vec_size; i++) { + varNames.push_back(STRING(vars_vec[i])); + varValues.push_back(STRING(vars_values[i])); + } + } + + return handle->Init(datapath, language, mode, configs, configs_size, + &varNames, &varValues, set_only_non_debug_params != 0); +} + +TESS_API int TESS_CALL TessBaseAPIInit1(TessBaseAPI* handle, + const char* datapath, + const char* language, + TessOcrEngineMode oem, char** configs, + int configs_size) { + return handle->Init(datapath, language, oem, configs, configs_size, nullptr, + nullptr, false); +} + +TESS_API int TESS_CALL TessBaseAPIInit2(TessBaseAPI* handle, + const char* datapath, + const char* language, + TessOcrEngineMode oem) { + return handle->Init(datapath, language, oem); +} + +TESS_API int TESS_CALL TessBaseAPIInit3(TessBaseAPI* handle, + const char* datapath, + const char* language) { + return handle->Init(datapath, language); +} + +TESS_API const char* TESS_CALL +TessBaseAPIGetInitLanguagesAsString(const TessBaseAPI* handle) { + return handle->GetInitLanguagesAsString(); +} + +TESS_API char** TESS_CALL +TessBaseAPIGetLoadedLanguagesAsVector(const TessBaseAPI* handle) { + GenericVector languages; + handle->GetLoadedLanguagesAsVector(&languages); + char** arr = new char*[languages.size() + 1]; + for (int index = 0; index < languages.size(); ++index) { + arr[index] = languages[index].strdup(); + } + arr[languages.size()] = nullptr; + return arr; +} + +TESS_API char** TESS_CALL +TessBaseAPIGetAvailableLanguagesAsVector(const TessBaseAPI* handle) { + GenericVector languages; + handle->GetAvailableLanguagesAsVector(&languages); + char** arr = new char*[languages.size() + 1]; + for (int index = 0; index < languages.size(); ++index) { + arr[index] = languages[index].strdup(); + } + arr[languages.size()] = nullptr; + return arr; +} + +#ifndef DISABLED_LEGACY_ENGINE +TESS_API int TESS_CALL TessBaseAPIInitLangMod(TessBaseAPI* handle, + const char* datapath, + const char* language) { + return handle->InitLangMod(datapath, language); +} +#endif + +TESS_API void TESS_CALL TessBaseAPIInitForAnalysePage(TessBaseAPI* handle) { + handle->InitForAnalysePage(); +} + +TESS_API void TESS_CALL TessBaseAPIReadConfigFile(TessBaseAPI* handle, + const char* filename) { + handle->ReadConfigFile(filename); +} + +TESS_API void TESS_CALL TessBaseAPIReadDebugConfigFile(TessBaseAPI* handle, + const char* filename) { + handle->ReadDebugConfigFile(filename); +} + +TESS_API void TESS_CALL TessBaseAPISetPageSegMode(TessBaseAPI* handle, + TessPageSegMode mode) { + handle->SetPageSegMode(mode); +} + +TESS_API TessPageSegMode TESS_CALL +TessBaseAPIGetPageSegMode(const TessBaseAPI* handle) { + return handle->GetPageSegMode(); +} + +TESS_API char* TESS_CALL TessBaseAPIRect(TessBaseAPI* handle, + const unsigned char* imagedata, + int bytes_per_pixel, + int bytes_per_line, int left, int top, + int width, int height) { + return handle->TesseractRect(imagedata, bytes_per_pixel, bytes_per_line, left, + top, width, height); +} + +#ifndef DISABLED_LEGACY_ENGINE +TESS_API void TESS_CALL +TessBaseAPIClearAdaptiveClassifier(TessBaseAPI* handle) { + handle->ClearAdaptiveClassifier(); +} +#endif + +TESS_API void TESS_CALL TessBaseAPISetImage(TessBaseAPI* handle, + const unsigned char* imagedata, + int width, int height, + int bytes_per_pixel, + int bytes_per_line) { + handle->SetImage(imagedata, width, height, bytes_per_pixel, bytes_per_line); +} + +TESS_API void TESS_CALL TessBaseAPISetImage2(TessBaseAPI* handle, + struct Pix* pix) { + return handle->SetImage(pix); +} + +TESS_API void TESS_CALL TessBaseAPISetSourceResolution(TessBaseAPI* handle, + int ppi) { + handle->SetSourceResolution(ppi); +} + +TESS_API void TESS_CALL TessBaseAPISetRectangle(TessBaseAPI* handle, int left, + int top, int width, + int height) { + handle->SetRectangle(left, top, width, height); +} + +TESS_API void TESS_CALL TessBaseAPISetThresholder( + TessBaseAPI* handle, TessImageThresholder* thresholder) { + handle->SetThresholder(thresholder); +} + +TESS_API struct Pix* TESS_CALL +TessBaseAPIGetThresholdedImage(TessBaseAPI* handle) { + return handle->GetThresholdedImage(); +} + +TESS_API struct Boxa* TESS_CALL TessBaseAPIGetRegions(TessBaseAPI* handle, + struct Pixa** pixa) { + return handle->GetRegions(pixa); +} + +TESS_API struct Boxa* TESS_CALL TessBaseAPIGetTextlines(TessBaseAPI* handle, + struct Pixa** pixa, + int** blockids) { + return handle->GetTextlines(pixa, blockids); +} + +TESS_API struct Boxa* TESS_CALL TessBaseAPIGetTextlines1( + TessBaseAPI* handle, const BOOL raw_image, const int raw_padding, + struct Pixa** pixa, int** blockids, int** paraids) { + return handle->GetTextlines(raw_image != 0, raw_padding, pixa, blockids, + paraids); +} + +TESS_API struct Boxa* TESS_CALL TessBaseAPIGetStrips(TessBaseAPI* handle, + struct Pixa** pixa, + int** blockids) { + return handle->GetStrips(pixa, blockids); +} + +TESS_API struct Boxa* TESS_CALL TessBaseAPIGetWords(TessBaseAPI* handle, + struct Pixa** pixa) { + return handle->GetWords(pixa); +} + +TESS_API struct Boxa* TESS_CALL +TessBaseAPIGetConnectedComponents(TessBaseAPI* handle, struct Pixa** cc) { + return handle->GetConnectedComponents(cc); +} + +TESS_API struct Boxa* TESS_CALL TessBaseAPIGetComponentImages( + TessBaseAPI* handle, TessPageIteratorLevel level, BOOL text_only, + struct Pixa** pixa, int** blockids) { + return handle->GetComponentImages(level, static_cast(text_only), pixa, + blockids); +} + +TESS_API struct Boxa* TESS_CALL TessBaseAPIGetComponentImages1( + TessBaseAPI* handle, const TessPageIteratorLevel level, + const BOOL text_only, const BOOL raw_image, const int raw_padding, + struct Pixa** pixa, int** blockids, int** paraids) { + return handle->GetComponentImages(level, static_cast(text_only), + raw_image != 0, raw_padding, pixa, blockids, + paraids); +} + +TESS_API int TESS_CALL +TessBaseAPIGetThresholdedImageScaleFactor(const TessBaseAPI* handle) { + return handle->GetThresholdedImageScaleFactor(); +} + +TESS_API TessPageIterator* TESS_CALL +TessBaseAPIAnalyseLayout(TessBaseAPI* handle) { + return handle->AnalyseLayout(); +} + + + +TESS_API int TESS_CALL TessBaseAPIRecognize(TessBaseAPI* handle, + ETEXT_DESC* monitor) { + return handle->Recognize(monitor); +} + +#ifndef DISABLED_LEGACY_ENGINE +TESS_API int TESS_CALL TessBaseAPIRecognizeForChopTest(TessBaseAPI* handle, + ETEXT_DESC* monitor) { + return handle->RecognizeForChopTest(monitor); +} +#endif + +TESS_API BOOL TESS_CALL TessBaseAPIProcessPages(TessBaseAPI* handle, + const char* filename, + const char* retry_config, + int timeout_millisec, + TessResultRenderer* renderer) { + return static_cast( + handle->ProcessPages(filename, retry_config, timeout_millisec, renderer)); +} + +TESS_API BOOL TESS_CALL TessBaseAPIProcessPage(TessBaseAPI* handle, + struct Pix* pix, int page_index, + const char* filename, + const char* retry_config, + int timeout_millisec, + TessResultRenderer* renderer) { + return static_cast(handle->ProcessPage( + pix, page_index, filename, retry_config, timeout_millisec, renderer)); +} + +TESS_API TessResultIterator* TESS_CALL +TessBaseAPIGetIterator(TessBaseAPI* handle) { + return handle->GetIterator(); +} + +TESS_API TessMutableIterator* TESS_CALL +TessBaseAPIGetMutableIterator(TessBaseAPI* handle) { + return handle->GetMutableIterator(); +} + +TESS_API char* TESS_CALL TessBaseAPIGetUTF8Text(TessBaseAPI* handle) { + return handle->GetUTF8Text(); +} + +TESS_API char* TESS_CALL TessBaseAPIGetHOCRText(TessBaseAPI* handle, + int page_number) { + return handle->GetHOCRText(nullptr, page_number); +} + +TESS_API char* TESS_CALL TessBaseAPIGetAltoText(TessBaseAPI* handle, + int page_number) { + return handle->GetAltoText(page_number); +} + +TESS_API char* TESS_CALL TessBaseAPIGetTsvText(TessBaseAPI* handle, + int page_number) { + return handle->GetTSVText(page_number); +} + +TESS_API char* TESS_CALL TessBaseAPIGetBoxText(TessBaseAPI* handle, + int page_number) { + return handle->GetBoxText(page_number); +} + +TESS_API char* TESS_CALL TessBaseAPIGetWordStrBoxText(TessBaseAPI* handle, + int page_number) { + return handle->GetWordStrBoxText(page_number); +} + +TESS_API char* TESS_CALL TessBaseAPIGetLSTMBoxText(TessBaseAPI* handle, + int page_number) { + return handle->GetLSTMBoxText(page_number); +} + +TESS_API char* TESS_CALL TessBaseAPIGetUNLVText(TessBaseAPI* handle) { + return handle->GetUNLVText(); +} + +TESS_API int TESS_CALL TessBaseAPIMeanTextConf(TessBaseAPI* handle) { + return handle->MeanTextConf(); +} + +TESS_API int* TESS_CALL TessBaseAPIAllWordConfidences(TessBaseAPI* handle) { + return handle->AllWordConfidences(); +} + +#ifndef DISABLED_LEGACY_ENGINE +TESS_API BOOL TESS_CALL TessBaseAPIAdaptToWordStr(TessBaseAPI* handle, + TessPageSegMode mode, + const char* wordstr) { + return static_cast(handle->AdaptToWordStr(mode, wordstr)); +} +#endif + +TESS_API void TESS_CALL TessBaseAPIClear(TessBaseAPI* handle) { + handle->Clear(); +} + +TESS_API void TESS_CALL TessBaseAPIEnd(TessBaseAPI* handle) { + handle->End(); +} + +TESS_API int TESS_CALL TessBaseAPIIsValidWord(TessBaseAPI* handle, + const char* word) { + return handle->IsValidWord(word); +} + +TESS_API BOOL TESS_CALL TessBaseAPIGetTextDirection(TessBaseAPI* handle, + int* out_offset, + float* out_slope) { + return static_cast(handle->GetTextDirection(out_offset, out_slope)); +} + +TESS_API void TESS_CALL TessBaseAPISetDictFunc(TessBaseAPI* handle, + TessDictFunc f) { + handle->SetDictFunc(f); +} + +TESS_API void TESS_CALL +TessBaseAPIClearPersistentCache(TessBaseAPI* /*handle*/) { + TessBaseAPI::ClearPersistentCache(); +} + +TESS_API void TESS_CALL TessBaseAPISetProbabilityInContextFunc( + TessBaseAPI* handle, TessProbabilityInContextFunc f) { + handle->SetProbabilityInContextFunc(f); +} + +#ifndef DISABLED_LEGACY_ENGINE + +TESS_API BOOL TESS_CALL TessBaseAPIDetectOrientationScript( + TessBaseAPI* handle, int* orient_deg, float* orient_conf, + const char** script_name, float* script_conf) { + bool success; + success = handle->DetectOrientationScript(orient_deg, orient_conf, + script_name, script_conf); + return static_cast(success); +} + +TESS_API void TESS_CALL TessBaseAPIGetFeaturesForBlob( + TessBaseAPI* handle, TBLOB* blob, INT_FEATURE_STRUCT* int_features, + int* num_features, int* FeatureOutlineIndex) { + handle->GetFeaturesForBlob(blob, int_features, num_features, + FeatureOutlineIndex); +} + +TESS_API ROW* TESS_CALL TessFindRowForBox(BLOCK_LIST* blocks, int left, int top, + int right, int bottom) { + return TessBaseAPI::FindRowForBox(blocks, left, top, right, bottom); +} + +TESS_API void TESS_CALL TessBaseAPIRunAdaptiveClassifier( + TessBaseAPI* handle, TBLOB* blob, int num_max_matches, int* unichar_ids, + float* ratings, int* num_matches_returned) { + handle->RunAdaptiveClassifier(blob, num_max_matches, unichar_ids, ratings, + num_matches_returned); +} + +#endif // ndef DISABLED_LEGACY_ENGINE + +TESS_API const char* TESS_CALL TessBaseAPIGetUnichar(TessBaseAPI* handle, + int unichar_id) { + return handle->GetUnichar(unichar_id); +} + +TESS_API const TessDawg* TESS_CALL TessBaseAPIGetDawg(const TessBaseAPI* handle, + int i) { + return handle->GetDawg(i); +} + +TESS_API int TESS_CALL TessBaseAPINumDawgs(const TessBaseAPI* handle) { + return handle->NumDawgs(); +} + +#ifndef DISABLED_LEGACY_ENGINE +TESS_API ROW* TESS_CALL TessMakeTessOCRRow(float baseline, float xheight, + float descender, float ascender) { + return TessBaseAPI::MakeTessOCRRow(baseline, xheight, descender, ascender); +} + +TESS_API TBLOB* TESS_CALL TessMakeTBLOB(struct Pix* pix) { + return TessBaseAPI::MakeTBLOB(pix); +} + +TESS_API void TESS_CALL TessNormalizeTBLOB(TBLOB* tblob, ROW* row, + BOOL numeric_mode) { + TessBaseAPI::NormalizeTBLOB(tblob, row, static_cast(numeric_mode)); +} +#endif // ndef DISABLED_LEGACY_ENGINE + +TESS_API TessOcrEngineMode TESS_CALL TessBaseAPIOem(const TessBaseAPI* handle) { + return handle->oem(); +} + +TESS_API void TESS_CALL TessBaseAPIInitTruthCallback(TessBaseAPI* handle, + TessTruthCallback* cb) { + handle->InitTruthCallback(cb); +} + +TESS_API void TESS_CALL TessBaseAPISetMinOrientationMargin(TessBaseAPI* handle, + double margin) { + handle->set_min_orientation_margin(margin); +} + +TESS_API void TESS_CALL TessBaseGetBlockTextOrientations( + TessBaseAPI* handle, int** block_orientation, bool** vertical_writing) { + handle->GetBlockTextOrientations(block_orientation, vertical_writing); +} + +#ifndef DISABLED_LEGACY_ENGINE +TESS_API BLOCK_LIST* TESS_CALL +TessBaseAPIFindLinesCreateBlockList(TessBaseAPI* handle) { + return handle->FindLinesCreateBlockList(); +} +#endif + +TESS_API void TESS_CALL TessPageIteratorDelete(TessPageIterator* handle) { + delete handle; +} + +TESS_API TessPageIterator* TESS_CALL +TessPageIteratorCopy(const TessPageIterator* handle) { + return new TessPageIterator(*handle); +} + +TESS_API void TESS_CALL TessPageIteratorBegin(TessPageIterator* handle) { + handle->Begin(); +} + +TESS_API BOOL TESS_CALL TessPageIteratorNext(TessPageIterator* handle, + TessPageIteratorLevel level) { + return static_cast(handle->Next(level)); +} + +TESS_API BOOL TESS_CALL TessPageIteratorIsAtBeginningOf( + const TessPageIterator* handle, TessPageIteratorLevel level) { + return static_cast(handle->IsAtBeginningOf(level)); +} + +TESS_API BOOL TESS_CALL TessPageIteratorIsAtFinalElement( + const TessPageIterator* handle, TessPageIteratorLevel level, + TessPageIteratorLevel element) { + return static_cast(handle->IsAtFinalElement(level, element)); +} + +TESS_API BOOL TESS_CALL TessPageIteratorBoundingBox( + const TessPageIterator* handle, TessPageIteratorLevel level, int* left, + int* top, int* right, int* bottom) { + return static_cast(handle->BoundingBox(level, left, top, right, bottom)); +} + +TESS_API TessPolyBlockType TESS_CALL +TessPageIteratorBlockType(const TessPageIterator* handle) { + return handle->BlockType(); +} + +TESS_API struct Pix* TESS_CALL TessPageIteratorGetBinaryImage( + const TessPageIterator* handle, TessPageIteratorLevel level) { + return handle->GetBinaryImage(level); +} + +TESS_API struct Pix* TESS_CALL TessPageIteratorGetImage( + const TessPageIterator* handle, TessPageIteratorLevel level, int padding, + struct Pix* original_image, int* left, int* top) { + return handle->GetImage(level, padding, original_image, left, top); +} + +TESS_API BOOL TESS_CALL TessPageIteratorBaseline(const TessPageIterator* handle, + TessPageIteratorLevel level, + int* x1, int* y1, int* x2, + int* y2) { + return static_cast(handle->Baseline(level, x1, y1, x2, y2)); +} + +TESS_API void TESS_CALL TessPageIteratorOrientation( + TessPageIterator* handle, TessOrientation* orientation, + TessWritingDirection* writing_direction, TessTextlineOrder* textline_order, + float* deskew_angle) { + handle->Orientation(orientation, writing_direction, textline_order, + deskew_angle); +} + +TESS_API void TESS_CALL TessPageIteratorParagraphInfo( + TessPageIterator* handle, TessParagraphJustification* justification, + BOOL* is_list_item, BOOL* is_crown, int* first_line_indent) { + bool bool_is_list_item; + bool bool_is_crown; + handle->ParagraphInfo(justification, &bool_is_list_item, &bool_is_crown, + first_line_indent); + if (is_list_item != nullptr) { + *is_list_item = static_cast(bool_is_list_item); + } + if (is_crown != nullptr) { + *is_crown = static_cast(bool_is_crown); + } +} + +TESS_API void TESS_CALL TessResultIteratorDelete(TessResultIterator* handle) { + delete handle; +} + +TESS_API TessResultIterator* TESS_CALL +TessResultIteratorCopy(const TessResultIterator* handle) { + return new TessResultIterator(*handle); +} + +TESS_API TessPageIterator* TESS_CALL +TessResultIteratorGetPageIterator(TessResultIterator* handle) { + return handle; +} + +TESS_API const TessPageIterator* TESS_CALL +TessResultIteratorGetPageIteratorConst(const TessResultIterator* handle) { + return handle; +} + +TESS_API TessChoiceIterator* TESS_CALL +TessResultIteratorGetChoiceIterator(const TessResultIterator* handle) { + return new TessChoiceIterator(*handle); +} + +TESS_API BOOL TESS_CALL TessResultIteratorNext(TessResultIterator* handle, + TessPageIteratorLevel level) { + return static_cast(handle->Next(level)); +} + +TESS_API char* TESS_CALL TessResultIteratorGetUTF8Text( + const TessResultIterator* handle, TessPageIteratorLevel level) { + return handle->GetUTF8Text(level); +} + +TESS_API float TESS_CALL TessResultIteratorConfidence( + const TessResultIterator* handle, TessPageIteratorLevel level) { + return handle->Confidence(level); +} + +TESS_API const char* TESS_CALL +TessResultIteratorWordRecognitionLanguage(const TessResultIterator* handle) { + return handle->WordRecognitionLanguage(); +} + +TESS_API const char* TESS_CALL TessResultIteratorWordFontAttributes( + const TessResultIterator* handle, BOOL* is_bold, BOOL* is_italic, + BOOL* is_underlined, BOOL* is_monospace, BOOL* is_serif, BOOL* is_smallcaps, + int* pointsize, int* font_id) { + bool bool_is_bold; + bool bool_is_italic; + bool bool_is_underlined; + bool bool_is_monospace; + bool bool_is_serif; + bool bool_is_smallcaps; + const char* ret = handle->WordFontAttributes( + &bool_is_bold, &bool_is_italic, &bool_is_underlined, &bool_is_monospace, + &bool_is_serif, &bool_is_smallcaps, pointsize, font_id); + if (is_bold != nullptr) { + *is_bold = static_cast(bool_is_bold); + } + if (is_italic != nullptr) { + *is_italic = static_cast(bool_is_italic); + } + if (is_underlined != nullptr) { + *is_underlined = static_cast(bool_is_underlined); + } + if (is_monospace != nullptr) { + *is_monospace = static_cast(bool_is_monospace); + } + if (is_serif != nullptr) { + *is_serif = static_cast(bool_is_serif); + } + if (is_smallcaps != nullptr) { + *is_smallcaps = static_cast(bool_is_smallcaps); + } + return ret; +} + +TESS_API BOOL TESS_CALL +TessResultIteratorWordIsFromDictionary(const TessResultIterator* handle) { + return static_cast(handle->WordIsFromDictionary()); +} + +TESS_API BOOL TESS_CALL +TessResultIteratorWordIsNumeric(const TessResultIterator* handle) { + return static_cast(handle->WordIsNumeric()); +} + +TESS_API BOOL TESS_CALL +TessResultIteratorSymbolIsSuperscript(const TessResultIterator* handle) { + return static_cast(handle->SymbolIsSuperscript()); +} + +TESS_API BOOL TESS_CALL +TessResultIteratorSymbolIsSubscript(const TessResultIterator* handle) { + return static_cast(handle->SymbolIsSubscript()); +} + +TESS_API BOOL TESS_CALL +TessResultIteratorSymbolIsDropcap(const TessResultIterator* handle) { + return static_cast(handle->SymbolIsDropcap()); +} + +TESS_API void TESS_CALL TessChoiceIteratorDelete(TessChoiceIterator* handle) { + delete handle; +} + +TESS_API BOOL TESS_CALL TessChoiceIteratorNext(TessChoiceIterator* handle) { + return static_cast(handle->Next()); +} + +TESS_API const char* TESS_CALL +TessChoiceIteratorGetUTF8Text(const TessChoiceIterator* handle) { + return handle->GetUTF8Text(); +} + +TESS_API float TESS_CALL +TessChoiceIteratorConfidence(const TessChoiceIterator* handle) { + return handle->Confidence(); +} + +TESS_API ETEXT_DESC* TESS_CALL TessMonitorCreate() { + return new ETEXT_DESC(); +} + +TESS_API void TESS_CALL TessMonitorDelete(ETEXT_DESC* monitor) { + delete monitor; +} + +TESS_API void TESS_CALL TessMonitorSetCancelFunc(ETEXT_DESC* monitor, + TessCancelFunc cancelFunc) { + monitor->cancel = cancelFunc; +} + +TESS_API void TESS_CALL TessMonitorSetCancelThis(ETEXT_DESC* monitor, + void* cancelThis) { + monitor->cancel_this = cancelThis; +} + +TESS_API void* TESS_CALL TessMonitorGetCancelThis(ETEXT_DESC* monitor) { + return monitor->cancel_this; +} + +TESS_API void TESS_CALL +TessMonitorSetProgressFunc(ETEXT_DESC* monitor, TessProgressFunc progressFunc) { + monitor->progress_callback2 = progressFunc; +} + +TESS_API int TESS_CALL TessMonitorGetProgress(ETEXT_DESC* monitor) { + return monitor->progress; +} + +TESS_API void TESS_CALL TessMonitorSetDeadlineMSecs(ETEXT_DESC* monitor, + int deadline) { + monitor->set_deadline_msecs(deadline); +} diff --git a/third_party/ocr/tesseract-ocr/src/capi.h b/third_party/ocr/tesseract-ocr/src/capi.h new file mode 100644 index 00000000..8752816a --- /dev/null +++ b/third_party/ocr/tesseract-ocr/src/capi.h @@ -0,0 +1,630 @@ +/////////////////////////////////////////////////////////////////////// +// File: capi.h +// Description: C-API TessBaseAPI +// +// (C) Copyright 2012, Google Inc. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +/////////////////////////////////////////////////////////////////////// + +#ifndef API_CAPI_H_ +#define API_CAPI_H_ + +#if defined(TESSERACT_API_BASEAPI_H_) && !defined(TESS_CAPI_INCLUDE_BASEAPI) +# define TESS_CAPI_INCLUDE_BASEAPI +#endif + +#ifdef TESS_CAPI_INCLUDE_BASEAPI +# include "baseapi.h" +# include "ocrclass.h" +# include "pageiterator.h" +# include "renderer.h" +# include "resultiterator.h" +#else +# include +# include +# include "platform.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef TESS_CALL +# if defined(WIN32) +# define TESS_CALL __cdecl +# else +# define TESS_CALL +# endif +#endif + +#ifndef BOOL +# define BOOL int +# define TRUE 1 +# define FALSE 0 +#endif + +#ifdef TESS_CAPI_INCLUDE_BASEAPI +typedef tesseract::TessResultRenderer TessResultRenderer; +typedef tesseract::TessTextRenderer TessTextRenderer; +typedef tesseract::TessHOcrRenderer TessHOcrRenderer; +typedef tesseract::TessAltoRenderer TessAltoRenderer; +typedef tesseract::TessTsvRenderer TessTsvRenderer; +typedef tesseract::TessPDFRenderer TessPDFRenderer; +typedef tesseract::TessUnlvRenderer TessUnlvRenderer; +typedef tesseract::TessBoxTextRenderer TessBoxTextRenderer; +typedef tesseract::TessWordStrBoxRenderer TessWordStrBoxRenderer; +typedef tesseract::TessLSTMBoxRenderer TessLSTMBoxRenderer; +typedef tesseract::TessBaseAPI TessBaseAPI; +typedef tesseract::PageIterator TessPageIterator; +typedef tesseract::ResultIterator TessResultIterator; +typedef tesseract::MutableIterator TessMutableIterator; +typedef tesseract::ChoiceIterator TessChoiceIterator; +typedef tesseract::OcrEngineMode TessOcrEngineMode; +typedef tesseract::PageSegMode TessPageSegMode; +typedef tesseract::ImageThresholder TessImageThresholder; +typedef tesseract::PageIteratorLevel TessPageIteratorLevel; +typedef tesseract::DictFunc TessDictFunc; +typedef tesseract::ProbabilityInContextFunc TessProbabilityInContextFunc; +// typedef tesseract::ParamsModelClassifyFunc TessParamsModelClassifyFunc; +typedef tesseract::FillLatticeFunc TessFillLatticeFunc; +typedef tesseract::Dawg TessDawg; +typedef tesseract::TruthCallback TessTruthCallback; +typedef tesseract::Orientation TessOrientation; +typedef tesseract::ParagraphJustification TessParagraphJustification; +typedef tesseract::WritingDirection TessWritingDirection; +typedef tesseract::TextlineOrder TessTextlineOrder; +typedef PolyBlockType TessPolyBlockType; +#else +typedef struct TessResultRenderer TessResultRenderer; +typedef struct TessTextRenderer TessTextRenderer; +typedef struct TessHOcrRenderer TessHOcrRenderer; +typedef struct TessPDFRenderer TessPDFRenderer; +typedef struct TessUnlvRenderer TessUnlvRenderer; +typedef struct TessBoxTextRenderer TessBoxTextRenderer; +typedef struct TessBaseAPI TessBaseAPI; +typedef struct TessPageIterator TessPageIterator; +typedef struct TessResultIterator TessResultIterator; +typedef struct TessMutableIterator TessMutableIterator; +typedef struct TessChoiceIterator TessChoiceIterator; +typedef enum TessOcrEngineMode { + OEM_TESSERACT_ONLY, + OEM_LSTM_ONLY, + OEM_TESSERACT_LSTM_COMBINED, + OEM_DEFAULT +} TessOcrEngineMode; +typedef enum TessPageSegMode { + PSM_OSD_ONLY, + PSM_AUTO_OSD, + PSM_AUTO_ONLY, + PSM_AUTO, + PSM_SINGLE_COLUMN, + PSM_SINGLE_BLOCK_VERT_TEXT, + PSM_SINGLE_BLOCK, + PSM_SINGLE_LINE, + PSM_SINGLE_WORD, + PSM_CIRCLE_WORD, + PSM_SINGLE_CHAR, + PSM_SPARSE_TEXT, + PSM_SPARSE_TEXT_OSD, + PSM_RAW_LINE, + PSM_COUNT +} TessPageSegMode; +typedef enum TessPageIteratorLevel { + RIL_BLOCK, + RIL_PARA, + RIL_TEXTLINE, + RIL_WORD, + RIL_SYMBOL +} TessPageIteratorLevel; +typedef enum TessPolyBlockType { + PT_UNKNOWN, + PT_FLOWING_TEXT, + PT_HEADING_TEXT, + PT_PULLOUT_TEXT, + PT_EQUATION, + PT_INLINE_EQUATION, + PT_TABLE, + PT_VERTICAL_TEXT, + PT_CAPTION_TEXT, + PT_FLOWING_IMAGE, + PT_HEADING_IMAGE, + PT_PULLOUT_IMAGE, + PT_HORZ_LINE, + PT_VERT_LINE, + PT_NOISE, + PT_COUNT +} TessPolyBlockType; +typedef enum TessOrientation { + ORIENTATION_PAGE_UP, + ORIENTATION_PAGE_RIGHT, + ORIENTATION_PAGE_DOWN, + ORIENTATION_PAGE_LEFT +} TessOrientation; +typedef enum TessParagraphJustification { + JUSTIFICATION_UNKNOWN, + JUSTIFICATION_LEFT, + JUSTIFICATION_CENTER, + JUSTIFICATION_RIGHT +} TessParagraphJustification; +typedef enum TessWritingDirection { + WRITING_DIRECTION_LEFT_TO_RIGHT, + WRITING_DIRECTION_RIGHT_TO_LEFT, + WRITING_DIRECTION_TOP_TO_BOTTOM +} TessWritingDirection; +typedef enum TessTextlineOrder { + TEXTLINE_ORDER_LEFT_TO_RIGHT, + TEXTLINE_ORDER_RIGHT_TO_LEFT, + TEXTLINE_ORDER_TOP_TO_BOTTOM +} TessTextlineOrder; +typedef struct ETEXT_DESC ETEXT_DESC; +#endif + +typedef bool (*TessCancelFunc)(void* cancel_this, int words); +typedef bool (*TessProgressFunc)(ETEXT_DESC* ths, int left, int right, int top, + int bottom); + +struct Pix; +struct Boxa; +struct Pixa; + +TESS_API int MyOSD(TessBaseAPI* api); + +/* General free functions */ + +TESS_API const char* TESS_CALL TessVersion(); +TESS_API void TESS_CALL TessDeleteText(const char* text); +TESS_API void TESS_CALL TessDeleteTextArray(char** arr); +TESS_API void TESS_CALL TessDeleteIntArray(const int* arr); + +/* Renderer API */ +TESS_API TessResultRenderer* TESS_CALL +TessTextRendererCreate(const char* outputbase); +TESS_API TessResultRenderer* TESS_CALL +TessHOcrRendererCreate(const char* outputbase); +TESS_API TessResultRenderer* TESS_CALL +TessHOcrRendererCreate2(const char* outputbase, BOOL font_info); +TESS_API TessResultRenderer* TESS_CALL +TessAltoRendererCreate(const char* outputbase); +TESS_API TessResultRenderer* TESS_CALL +TessTsvRendererCreate(const char* outputbase); +TESS_API TessResultRenderer* TESS_CALL TessPDFRendererCreate( + const char* outputbase, const char* datadir, BOOL textonly); +TESS_API TessResultRenderer* TESS_CALL +TessUnlvRendererCreate(const char* outputbase); +TESS_API TessResultRenderer* TESS_CALL +TessBoxTextRendererCreate(const char* outputbase); +TESS_API TessResultRenderer* TESS_CALL +TessLSTMBoxRendererCreate(const char* outputbase); +TESS_API TessResultRenderer* TESS_CALL +TessWordStrBoxRendererCreate(const char* outputbase); + +TESS_API void TESS_CALL TessDeleteResultRenderer(TessResultRenderer* renderer); +TESS_API void TESS_CALL TessResultRendererInsert(TessResultRenderer* renderer, + TessResultRenderer* next); +TESS_API TessResultRenderer* TESS_CALL +TessResultRendererNext(TessResultRenderer* renderer); +TESS_API BOOL TESS_CALL TessResultRendererBeginDocument( + TessResultRenderer* renderer, const char* title); +TESS_API BOOL TESS_CALL TessResultRendererAddImage(TessResultRenderer* renderer, + TessBaseAPI* api); +TESS_API BOOL TESS_CALL +TessResultRendererEndDocument(TessResultRenderer* renderer); + +TESS_API const char* TESS_CALL +TessResultRendererExtention(TessResultRenderer* renderer); +TESS_API const char* TESS_CALL +TessResultRendererTitle(TessResultRenderer* renderer); +TESS_API int TESS_CALL TessResultRendererImageNum(TessResultRenderer* renderer); + +/* Base API */ + +TESS_API TessBaseAPI* TESS_CALL TessBaseAPICreate(); +TESS_API void TESS_CALL TessBaseAPIDelete(TessBaseAPI* handle); + +TESS_API size_t TESS_CALL TessBaseAPIGetOpenCLDevice(TessBaseAPI* handle, + void** device); + +TESS_API void TESS_CALL TessBaseAPISetInputName(TessBaseAPI* handle, + const char* name); +TESS_API const char* TESS_CALL TessBaseAPIGetInputName(TessBaseAPI* handle); + +TESS_API void TESS_CALL TessBaseAPISetInputImage(TessBaseAPI* handle, + struct Pix* pix); +TESS_API struct Pix* TESS_CALL TessBaseAPIGetInputImage(TessBaseAPI* handle); + +TESS_API int TESS_CALL TessBaseAPIGetSourceYResolution(TessBaseAPI* handle); +TESS_API const char* TESS_CALL TessBaseAPIGetDatapath(TessBaseAPI* handle); + +TESS_API void TESS_CALL TessBaseAPISetOutputName(TessBaseAPI* handle, + const char* name); + +TESS_API BOOL TESS_CALL TessBaseAPISetVariable(TessBaseAPI* handle, + const char* name, + const char* value); +TESS_API BOOL TESS_CALL TessBaseAPISetDebugVariable(TessBaseAPI* handle, + const char* name, + const char* value); + +TESS_API BOOL TESS_CALL TessBaseAPIGetIntVariable(const TessBaseAPI* handle, + const char* name, int* value); +TESS_API BOOL TESS_CALL TessBaseAPIGetBoolVariable(const TessBaseAPI* handle, + const char* name, + BOOL* value); +TESS_API BOOL TESS_CALL TessBaseAPIGetDoubleVariable(const TessBaseAPI* handle, + const char* name, + double* value); +TESS_API const char* TESS_CALL +TessBaseAPIGetStringVariable(const TessBaseAPI* handle, const char* name); + +TESS_API void TESS_CALL TessBaseAPIPrintVariables(const TessBaseAPI* handle, + FILE* fp); +TESS_API BOOL TESS_CALL TessBaseAPIPrintVariablesToFile( + const TessBaseAPI* handle, const char* filename); + +#ifdef TESS_CAPI_INCLUDE_BASEAPI + +TESS_API BOOL TESS_CALL TessBaseAPIGetVariableAsString(TessBaseAPI* handle, + const char* name, + STRING* val); + +TESS_API int TESS_CALL TessBaseAPIInit( + TessBaseAPI* handle, const char* datapath, const char* language, + TessOcrEngineMode mode, char** configs, int configs_size, + const STRING* vars_vec, size_t vars_vec_size, const STRING* vars_values, + size_t vars_values_size, BOOL set_only_init_params); + +#endif // def TESS_CAPI_INCLUDE_BASEAPI + +TESS_API int TESS_CALL TessBaseAPIInit1(TessBaseAPI* handle, + const char* datapath, + const char* language, + TessOcrEngineMode oem, char** configs, + int configs_size); +TESS_API int TESS_CALL TessBaseAPIInit2(TessBaseAPI* handle, + const char* datapath, + const char* language, + TessOcrEngineMode oem); +TESS_API int TESS_CALL TessBaseAPIInit3(TessBaseAPI* handle, + const char* datapath, + const char* language); + +TESS_API int TESS_CALL TessBaseAPIInit4( + TessBaseAPI* handle, const char* datapath, const char* language, + TessOcrEngineMode mode, char** configs, int configs_size, char** vars_vec, + char** vars_values, size_t vars_vec_size, BOOL set_only_non_debug_params); + +TESS_API const char* TESS_CALL +TessBaseAPIGetInitLanguagesAsString(const TessBaseAPI* handle); +TESS_API char** TESS_CALL +TessBaseAPIGetLoadedLanguagesAsVector(const TessBaseAPI* handle); +TESS_API char** TESS_CALL +TessBaseAPIGetAvailableLanguagesAsVector(const TessBaseAPI* handle); + +TESS_API int TESS_CALL TessBaseAPIInitLangMod(TessBaseAPI* handle, + const char* datapath, + const char* language); +TESS_API void TESS_CALL TessBaseAPIInitForAnalysePage(TessBaseAPI* handle); + +TESS_API void TESS_CALL TessBaseAPIReadConfigFile(TessBaseAPI* handle, + const char* filename); +TESS_API void TESS_CALL TessBaseAPIReadDebugConfigFile(TessBaseAPI* handle, + const char* filename); + +TESS_API void TESS_CALL TessBaseAPISetPageSegMode(TessBaseAPI* handle, + TessPageSegMode mode); +TESS_API TessPageSegMode TESS_CALL +TessBaseAPIGetPageSegMode(const TessBaseAPI* handle); + +TESS_API char* TESS_CALL TessBaseAPIRect(TessBaseAPI* handle, + const unsigned char* imagedata, + int bytes_per_pixel, + int bytes_per_line, int left, int top, + int width, int height); + +TESS_API void TESS_CALL TessBaseAPIClearAdaptiveClassifier(TessBaseAPI* handle); + +TESS_API void TESS_CALL TessBaseAPISetImage(TessBaseAPI* handle, + const unsigned char* imagedata, + int width, int height, + int bytes_per_pixel, + int bytes_per_line); +TESS_API void TESS_CALL TessBaseAPISetImage2(TessBaseAPI* handle, + struct Pix* pix); + +TESS_API void TESS_CALL TessBaseAPISetSourceResolution(TessBaseAPI* handle, + int ppi); + +TESS_API void TESS_CALL TessBaseAPISetRectangle(TessBaseAPI* handle, int left, + int top, int width, int height); + +#ifdef TESS_CAPI_INCLUDE_BASEAPI +TESS_API void TESS_CALL TessBaseAPISetThresholder( + TessBaseAPI* handle, TessImageThresholder* thresholder); +#endif + +TESS_API struct Pix* TESS_CALL +TessBaseAPIGetThresholdedImage(TessBaseAPI* handle); +TESS_API struct Boxa* TESS_CALL TessBaseAPIGetRegions(TessBaseAPI* handle, + struct Pixa** pixa); +TESS_API struct Boxa* TESS_CALL TessBaseAPIGetTextlines(TessBaseAPI* handle, + struct Pixa** pixa, + int** blockids); +TESS_API struct Boxa* TESS_CALL +TessBaseAPIGetTextlines1(TessBaseAPI* handle, BOOL raw_image, int raw_padding, + struct Pixa** pixa, int** blockids, int** paraids); +TESS_API struct Boxa* TESS_CALL TessBaseAPIGetStrips(TessBaseAPI* handle, + struct Pixa** pixa, + int** blockids); +TESS_API struct Boxa* TESS_CALL TessBaseAPIGetWords(TessBaseAPI* handle, + struct Pixa** pixa); +TESS_API struct Boxa* TESS_CALL +TessBaseAPIGetConnectedComponents(TessBaseAPI* handle, struct Pixa** cc); +TESS_API struct Boxa* TESS_CALL TessBaseAPIGetComponentImages( + TessBaseAPI* handle, TessPageIteratorLevel level, BOOL text_only, + struct Pixa** pixa, int** blockids); +TESS_API struct Boxa* TESS_CALL TessBaseAPIGetComponentImages1( + TessBaseAPI* handle, TessPageIteratorLevel level, BOOL text_only, + BOOL raw_image, int raw_padding, struct Pixa** pixa, int** blockids, + int** paraids); + +TESS_API int TESS_CALL +TessBaseAPIGetThresholdedImageScaleFactor(const TessBaseAPI* handle); + +TESS_API TessPageIterator* TESS_CALL +TessBaseAPIAnalyseLayout(TessBaseAPI* handle); + +TESS_API int TESS_CALL TessBaseAPIRecognize(TessBaseAPI* handle, + ETEXT_DESC* monitor); + +#ifndef DISABLED_LEGACY_ENGINE +TESS_API int TESS_CALL TessBaseAPIRecognizeForChopTest(TessBaseAPI* handle, + ETEXT_DESC* monitor); +#endif + +TESS_API BOOL TESS_CALL TessBaseAPIProcessPages(TessBaseAPI* handle, + const char* filename, + const char* retry_config, + int timeout_millisec, + TessResultRenderer* renderer); +TESS_API BOOL TESS_CALL TessBaseAPIProcessPage(TessBaseAPI* handle, + struct Pix* pix, int page_index, + const char* filename, + const char* retry_config, + int timeout_millisec, + TessResultRenderer* renderer); + +TESS_API TessResultIterator* TESS_CALL +TessBaseAPIGetIterator(TessBaseAPI* handle); +TESS_API TessMutableIterator* TESS_CALL +TessBaseAPIGetMutableIterator(TessBaseAPI* handle); + +TESS_API char* TESS_CALL TessBaseAPIGetUTF8Text(TessBaseAPI* handle); +TESS_API char* TESS_CALL TessBaseAPIGetHOCRText(TessBaseAPI* handle, + int page_number); + +TESS_API char* TESS_CALL TessBaseAPIGetAltoText(TessBaseAPI* handle, + int page_number); +TESS_API char* TESS_CALL TessBaseAPIGetTsvText(TessBaseAPI* handle, + int page_number); + +TESS_API char* TESS_CALL TessBaseAPIGetBoxText(TessBaseAPI* handle, + int page_number); +TESS_API char* TESS_CALL TessBaseAPIGetLSTMBoxText(TessBaseAPI* handle, + int page_number); +TESS_API char* TESS_CALL TessBaseAPIGetWordStrBoxText(TessBaseAPI* handle, + int page_number); + +TESS_API char* TESS_CALL TessBaseAPIGetUNLVText(TessBaseAPI* handle); +TESS_API int TESS_CALL TessBaseAPIMeanTextConf(TessBaseAPI* handle); + +TESS_API int* TESS_CALL TessBaseAPIAllWordConfidences(TessBaseAPI* handle); + +#ifndef DISABLED_LEGACY_ENGINE +TESS_API BOOL TESS_CALL TessBaseAPIAdaptToWordStr(TessBaseAPI* handle, + TessPageSegMode mode, + const char* wordstr); +#endif // ndef DISABLED_LEGACY_ENGINE + +TESS_API void TESS_CALL TessBaseAPIClear(TessBaseAPI* handle); +TESS_API void TESS_CALL TessBaseAPIEnd(TessBaseAPI* handle); + +TESS_API int TESS_CALL TessBaseAPIIsValidWord(TessBaseAPI* handle, + const char* word); +TESS_API BOOL TESS_CALL TessBaseAPIGetTextDirection(TessBaseAPI* handle, + int* out_offset, + float* out_slope); + +#ifdef TESS_CAPI_INCLUDE_BASEAPI + +TESS_API void TESS_CALL TessBaseAPISetDictFunc(TessBaseAPI* handle, + TessDictFunc f); + +TESS_API void TESS_CALL TessBaseAPIClearPersistentCache(TessBaseAPI* handle); + +TESS_API void TESS_CALL TessBaseAPISetProbabilityInContextFunc( + TessBaseAPI* handle, TessProbabilityInContextFunc f); + +// Call TessDeleteText(*best_script_name) to free memory allocated by this +// function +TESS_API BOOL TESS_CALL TessBaseAPIDetectOrientationScript( + TessBaseAPI* handle, int* orient_deg, float* orient_conf, + const char** script_name, float* script_conf); + +#endif // def TESS_CAPI_INCLUDE_BASEAPI + +TESS_API const char* TESS_CALL TessBaseAPIGetUnichar(TessBaseAPI* handle, + int unichar_id); + +TESS_API void TESS_CALL TessBaseAPISetMinOrientationMargin(TessBaseAPI* handle, + double margin); + +#ifdef TESS_CAPI_INCLUDE_BASEAPI + +TESS_API const TessDawg* TESS_CALL TessBaseAPIGetDawg(const TessBaseAPI* handle, + int i); + +TESS_API int TESS_CALL TessBaseAPINumDawgs(const TessBaseAPI* handle); + +TESS_API TessOcrEngineMode TESS_CALL TessBaseAPIOem(const TessBaseAPI* handle); + +TESS_API void TESS_CALL TessBaseAPIInitTruthCallback(TessBaseAPI* handle, + TessTruthCallback* cb); + +TESS_API void TESS_CALL TessBaseGetBlockTextOrientations( + TessBaseAPI* handle, int** block_orientation, bool** vertical_writing); + +#endif + +/* Page iterator */ + +TESS_API void TESS_CALL TessPageIteratorDelete(TessPageIterator* handle); + +TESS_API TessPageIterator* TESS_CALL +TessPageIteratorCopy(const TessPageIterator* handle); + +TESS_API void TESS_CALL TessPageIteratorBegin(TessPageIterator* handle); + +TESS_API BOOL TESS_CALL TessPageIteratorNext(TessPageIterator* handle, + TessPageIteratorLevel level); + +TESS_API BOOL TESS_CALL TessPageIteratorIsAtBeginningOf( + const TessPageIterator* handle, TessPageIteratorLevel level); + +TESS_API BOOL TESS_CALL TessPageIteratorIsAtFinalElement( + const TessPageIterator* handle, TessPageIteratorLevel level, + TessPageIteratorLevel element); + +TESS_API BOOL TESS_CALL TessPageIteratorBoundingBox( + const TessPageIterator* handle, TessPageIteratorLevel level, int* left, + int* top, int* right, int* bottom); + +TESS_API TessPolyBlockType TESS_CALL +TessPageIteratorBlockType(const TessPageIterator* handle); + +TESS_API struct Pix* TESS_CALL TessPageIteratorGetBinaryImage( + const TessPageIterator* handle, TessPageIteratorLevel level); + +TESS_API struct Pix* TESS_CALL TessPageIteratorGetImage( + const TessPageIterator* handle, TessPageIteratorLevel level, int padding, + struct Pix* original_image, int* left, int* top); + +TESS_API BOOL TESS_CALL TessPageIteratorBaseline(const TessPageIterator* handle, + TessPageIteratorLevel level, + int* x1, int* y1, int* x2, + int* y2); + +TESS_API void TESS_CALL TessPageIteratorOrientation( + TessPageIterator* handle, TessOrientation* orientation, + TessWritingDirection* writing_direction, TessTextlineOrder* textline_order, + float* deskew_angle); + +TESS_API void TESS_CALL TessPageIteratorParagraphInfo( + TessPageIterator* handle, TessParagraphJustification* justification, + BOOL* is_list_item, BOOL* is_crown, int* first_line_indent); + +/* Result iterator */ + +TESS_API void TESS_CALL TessResultIteratorDelete(TessResultIterator* handle); +TESS_API TessResultIterator* TESS_CALL +TessResultIteratorCopy(const TessResultIterator* handle); +TESS_API TessPageIterator* TESS_CALL +TessResultIteratorGetPageIterator(TessResultIterator* handle); +TESS_API const TessPageIterator* TESS_CALL +TessResultIteratorGetPageIteratorConst(const TessResultIterator* handle); +TESS_API TessChoiceIterator* TESS_CALL +TessResultIteratorGetChoiceIterator(const TessResultIterator* handle); + +TESS_API BOOL TESS_CALL TessResultIteratorNext(TessResultIterator* handle, + TessPageIteratorLevel level); +TESS_API char* TESS_CALL TessResultIteratorGetUTF8Text( + const TessResultIterator* handle, TessPageIteratorLevel level); +TESS_API float TESS_CALL TessResultIteratorConfidence( + const TessResultIterator* handle, TessPageIteratorLevel level); +TESS_API const char* TESS_CALL +TessResultIteratorWordRecognitionLanguage(const TessResultIterator* handle); +TESS_API const char* TESS_CALL TessResultIteratorWordFontAttributes( + const TessResultIterator* handle, BOOL* is_bold, BOOL* is_italic, + BOOL* is_underlined, BOOL* is_monospace, BOOL* is_serif, BOOL* is_smallcaps, + int* pointsize, int* font_id); + +TESS_API BOOL TESS_CALL +TessResultIteratorWordIsFromDictionary(const TessResultIterator* handle); +TESS_API BOOL TESS_CALL +TessResultIteratorWordIsNumeric(const TessResultIterator* handle); +TESS_API BOOL TESS_CALL +TessResultIteratorSymbolIsSuperscript(const TessResultIterator* handle); +TESS_API BOOL TESS_CALL +TessResultIteratorSymbolIsSubscript(const TessResultIterator* handle); +TESS_API BOOL TESS_CALL +TessResultIteratorSymbolIsDropcap(const TessResultIterator* handle); + +TESS_API void TESS_CALL TessChoiceIteratorDelete(TessChoiceIterator* handle); +TESS_API BOOL TESS_CALL TessChoiceIteratorNext(TessChoiceIterator* handle); +TESS_API const char* TESS_CALL +TessChoiceIteratorGetUTF8Text(const TessChoiceIterator* handle); +TESS_API float TESS_CALL +TessChoiceIteratorConfidence(const TessChoiceIterator* handle); + +/* Progress monitor */ + +TESS_API ETEXT_DESC* TESS_CALL TessMonitorCreate(); +TESS_API void TESS_CALL TessMonitorDelete(ETEXT_DESC* monitor); +TESS_API void TESS_CALL TessMonitorSetCancelFunc(ETEXT_DESC* monitor, + TessCancelFunc cancelFunc); +TESS_API void TESS_CALL TessMonitorSetCancelThis(ETEXT_DESC* monitor, + void* cancelThis); +TESS_API void* TESS_CALL TessMonitorGetCancelThis(ETEXT_DESC* monitor); +TESS_API void TESS_CALL +TessMonitorSetProgressFunc(ETEXT_DESC* monitor, TessProgressFunc progressFunc); +TESS_API int TESS_CALL TessMonitorGetProgress(ETEXT_DESC* monitor); +TESS_API void TESS_CALL TessMonitorSetDeadlineMSecs(ETEXT_DESC* monitor, + int deadline); + +#ifndef DISABLED_LEGACY_ENGINE + +# ifdef TESS_CAPI_INCLUDE_BASEAPI +TESS_API void TESS_CALL TessBaseAPISetFillLatticeFunc(TessBaseAPI* handle, + TessFillLatticeFunc f); + +TESS_API void TESS_CALL TessBaseAPIGetFeaturesForBlob( + TessBaseAPI* handle, TBLOB* blob, INT_FEATURE_STRUCT* int_features, + int* num_features, int* FeatureOutlineIndex); + +TESS_API ROW* TESS_CALL TessFindRowForBox(BLOCK_LIST* blocks, int left, int top, + int right, int bottom); + +TESS_API void TESS_CALL TessBaseAPIRunAdaptiveClassifier( + TessBaseAPI* handle, TBLOB* blob, int num_max_matches, int* unichar_ids, + float* ratings, int* num_matches_returned); + +TESS_API ROW* TESS_CALL TessMakeTessOCRRow(float baseline, float xheight, + float descender, float ascender); + +TESS_API TBLOB* TESS_CALL TessMakeTBLOB(Pix* pix); + +TESS_API void TESS_CALL TessNormalizeTBLOB(TBLOB* tblob, ROW* row, + BOOL numeric_mode); + +TESS_API BLOCK_LIST* TESS_CALL +TessBaseAPIFindLinesCreateBlockList(TessBaseAPI* handle); + +TESS_API void TESS_CALL TessDeleteBlockList(BLOCK_LIST* block_list); + +# endif // def TESS_CAPI_INCLUDE_BASEAPI + +#endif // ndef DISABLED_LEGACY_ENGINE + +#ifdef __cplusplus +} +#endif + +#endif // API_CAPI_H_ diff --git a/third_party/ocr/tesseract-ocr/uos/aarch64/include/tesseract/baseapi.h b/third_party/ocr/tesseract-ocr/uos/aarch64/include/tesseract/baseapi.h index 3724dd92..fe12351b 100644 --- a/third_party/ocr/tesseract-ocr/uos/aarch64/include/tesseract/baseapi.h +++ b/third_party/ocr/tesseract-ocr/uos/aarch64/include/tesseract/baseapi.h @@ -93,6 +93,8 @@ class TESS_API TessBaseAPI { TessBaseAPI(); virtual ~TessBaseAPI(); + int MyOSD(); + /** * Returns the version identifier as a static string. Do not delete. */ diff --git a/third_party/ocr/tesseract-ocr/uos/aarch64/include/tesseract/capi.h b/third_party/ocr/tesseract-ocr/uos/aarch64/include/tesseract/capi.h index 7ed64ef4..8752816a 100644 --- a/third_party/ocr/tesseract-ocr/uos/aarch64/include/tesseract/capi.h +++ b/third_party/ocr/tesseract-ocr/uos/aarch64/include/tesseract/capi.h @@ -176,6 +176,8 @@ struct Pix; struct Boxa; struct Pixa; +TESS_API int MyOSD(TessBaseAPI* api); + /* General free functions */ TESS_API const char* TESS_CALL TessVersion(); diff --git a/third_party/ocr/tesseract-ocr/uos/aarch64/lib/libtesseract.a b/third_party/ocr/tesseract-ocr/uos/aarch64/lib/libtesseract.a index 355edfb7..9d5a9047 100644 Binary files a/third_party/ocr/tesseract-ocr/uos/aarch64/lib/libtesseract.a and b/third_party/ocr/tesseract-ocr/uos/aarch64/lib/libtesseract.a differ diff --git a/third_party/ocr/tesseract-ocr/uos/amd64/include/tesseract/baseapi.h b/third_party/ocr/tesseract-ocr/uos/amd64/include/tesseract/baseapi.h index 3724dd92..fe12351b 100644 --- a/third_party/ocr/tesseract-ocr/uos/amd64/include/tesseract/baseapi.h +++ b/third_party/ocr/tesseract-ocr/uos/amd64/include/tesseract/baseapi.h @@ -93,6 +93,8 @@ class TESS_API TessBaseAPI { TessBaseAPI(); virtual ~TessBaseAPI(); + int MyOSD(); + /** * Returns the version identifier as a static string. Do not delete. */ diff --git a/third_party/ocr/tesseract-ocr/uos/amd64/include/tesseract/capi.h b/third_party/ocr/tesseract-ocr/uos/amd64/include/tesseract/capi.h index 7ed64ef4..8752816a 100644 --- a/third_party/ocr/tesseract-ocr/uos/amd64/include/tesseract/capi.h +++ b/third_party/ocr/tesseract-ocr/uos/amd64/include/tesseract/capi.h @@ -176,6 +176,8 @@ struct Pix; struct Boxa; struct Pixa; +TESS_API int MyOSD(TessBaseAPI* api); + /* General free functions */ TESS_API const char* TESS_CALL TessVersion(); diff --git a/third_party/ocr/tesseract-ocr/uos/amd64/lib/libtesseract.a b/third_party/ocr/tesseract-ocr/uos/amd64/lib/libtesseract.a index 3075cb7a..e2a2d25f 100644 Binary files a/third_party/ocr/tesseract-ocr/uos/amd64/lib/libtesseract.a and b/third_party/ocr/tesseract-ocr/uos/amd64/lib/libtesseract.a differ diff --git a/third_party/ocr/tesseract-ocr/uos/loongarch64/include/tesseract/baseapi.h b/third_party/ocr/tesseract-ocr/uos/loongarch64/include/tesseract/baseapi.h index 3724dd92..fe12351b 100644 --- a/third_party/ocr/tesseract-ocr/uos/loongarch64/include/tesseract/baseapi.h +++ b/third_party/ocr/tesseract-ocr/uos/loongarch64/include/tesseract/baseapi.h @@ -93,6 +93,8 @@ class TESS_API TessBaseAPI { TessBaseAPI(); virtual ~TessBaseAPI(); + int MyOSD(); + /** * Returns the version identifier as a static string. Do not delete. */ diff --git a/third_party/ocr/tesseract-ocr/uos/loongarch64/include/tesseract/capi.h b/third_party/ocr/tesseract-ocr/uos/loongarch64/include/tesseract/capi.h index 7ed64ef4..8752816a 100644 --- a/third_party/ocr/tesseract-ocr/uos/loongarch64/include/tesseract/capi.h +++ b/third_party/ocr/tesseract-ocr/uos/loongarch64/include/tesseract/capi.h @@ -176,6 +176,8 @@ struct Pix; struct Boxa; struct Pixa; +TESS_API int MyOSD(TessBaseAPI* api); + /* General free functions */ TESS_API const char* TESS_CALL TessVersion(); diff --git a/third_party/ocr/tesseract-ocr/uos/loongarch64/lib/libtesseract.a b/third_party/ocr/tesseract-ocr/uos/loongarch64/lib/libtesseract.a index 866ad476..2d3370f7 100644 Binary files a/third_party/ocr/tesseract-ocr/uos/loongarch64/lib/libtesseract.a and b/third_party/ocr/tesseract-ocr/uos/loongarch64/lib/libtesseract.a differ diff --git a/third_party/ocr/tesseract-ocr/uos/mips64/include/tesseract/baseapi.h b/third_party/ocr/tesseract-ocr/uos/mips64/include/tesseract/baseapi.h index 3724dd92..fe12351b 100644 --- a/third_party/ocr/tesseract-ocr/uos/mips64/include/tesseract/baseapi.h +++ b/third_party/ocr/tesseract-ocr/uos/mips64/include/tesseract/baseapi.h @@ -93,6 +93,8 @@ class TESS_API TessBaseAPI { TessBaseAPI(); virtual ~TessBaseAPI(); + int MyOSD(); + /** * Returns the version identifier as a static string. Do not delete. */ diff --git a/third_party/ocr/tesseract-ocr/uos/mips64/include/tesseract/capi.h b/third_party/ocr/tesseract-ocr/uos/mips64/include/tesseract/capi.h index 7ed64ef4..8752816a 100644 --- a/third_party/ocr/tesseract-ocr/uos/mips64/include/tesseract/capi.h +++ b/third_party/ocr/tesseract-ocr/uos/mips64/include/tesseract/capi.h @@ -176,6 +176,8 @@ struct Pix; struct Boxa; struct Pixa; +TESS_API int MyOSD(TessBaseAPI* api); + /* General free functions */ TESS_API const char* TESS_CALL TessVersion(); diff --git a/third_party/ocr/tesseract-ocr/uos/mips64/lib/libtesseract.a b/third_party/ocr/tesseract-ocr/uos/mips64/lib/libtesseract.a index 28e0c5f6..1e740828 100644 Binary files a/third_party/ocr/tesseract-ocr/uos/mips64/lib/libtesseract.a and b/third_party/ocr/tesseract-ocr/uos/mips64/lib/libtesseract.a differ diff --git a/third_party/ocr/tesseract-ocr/windows/include/tesseract/baseapi.h b/third_party/ocr/tesseract-ocr/windows/include/tesseract/baseapi.h index 3724dd92..fe12351b 100644 --- a/third_party/ocr/tesseract-ocr/windows/include/tesseract/baseapi.h +++ b/third_party/ocr/tesseract-ocr/windows/include/tesseract/baseapi.h @@ -93,6 +93,8 @@ class TESS_API TessBaseAPI { TessBaseAPI(); virtual ~TessBaseAPI(); + int MyOSD(); + /** * Returns the version identifier as a static string. Do not delete. */ diff --git a/third_party/ocr/tesseract-ocr/windows/include/tesseract/capi.h b/third_party/ocr/tesseract-ocr/windows/include/tesseract/capi.h index 7ed64ef4..8752816a 100644 --- a/third_party/ocr/tesseract-ocr/windows/include/tesseract/capi.h +++ b/third_party/ocr/tesseract-ocr/windows/include/tesseract/capi.h @@ -176,6 +176,8 @@ struct Pix; struct Boxa; struct Pixa; +TESS_API int MyOSD(TessBaseAPI* api); + /* General free functions */ TESS_API const char* TESS_CALL TessVersion(); diff --git a/third_party/ocr/tesseract-ocr/windows/lib/x64/tesseract41.lib b/third_party/ocr/tesseract-ocr/windows/lib/x64/tesseract41.lib index 4ea7b753..1d15d743 100644 Binary files a/third_party/ocr/tesseract-ocr/windows/lib/x64/tesseract41.lib and b/third_party/ocr/tesseract-ocr/windows/lib/x64/tesseract41.lib differ diff --git a/third_party/ocr/tesseract-ocr/windows/lib/x64/tesseract41d.lib b/third_party/ocr/tesseract-ocr/windows/lib/x64/tesseract41d.lib index 8b04c12f..2f30a783 100644 Binary files a/third_party/ocr/tesseract-ocr/windows/lib/x64/tesseract41d.lib and b/third_party/ocr/tesseract-ocr/windows/lib/x64/tesseract41d.lib differ diff --git a/third_party/ocr/tesseract-ocr/windows/lib/x86/tesseract41.lib b/third_party/ocr/tesseract-ocr/windows/lib/x86/tesseract41.lib index af246396..f2c49d6f 100644 Binary files a/third_party/ocr/tesseract-ocr/windows/lib/x86/tesseract41.lib and b/third_party/ocr/tesseract-ocr/windows/lib/x86/tesseract41.lib differ diff --git a/third_party/ocr/tesseract-ocr/windows/lib/x86/tesseract41d.lib b/third_party/ocr/tesseract-ocr/windows/lib/x86/tesseract41d.lib index 74cecdeb..ce9be4a0 100644 Binary files a/third_party/ocr/tesseract-ocr/windows/lib/x86/tesseract41d.lib and b/third_party/ocr/tesseract-ocr/windows/lib/x86/tesseract41d.lib differ