1

Тема: VBS, Jscript: объект типа OCR для чтения и распознавания PDF

Добрый день, коллеги.

Постановка задачи: на входе PDF-файл, в котором много разных документов.
Документы разделены любым способом - например, пустой страницей.
По хорошему хотелось бы, конечно, на странице-разделителе указаны атрибуты документа - например, номер, исполнитель и т.д.
В последнем случае разделитель имеет любую фиксированную структуру - типа начинается с фразы "Это новый документ".

Скрипт открывает этот PDF и делит один файл на то количество файлов, сколько документов было отсканировано.
Делает он это - как вы догадываетесь - по тем страницам-разделителям, которые были заложены при сканировании.
Хорошо бы файлы называть осмысленно - именно для этого и хотелось бы не пустышку-разделитель, а разделитель с некой инфой, например номер документа.

Т.е. на разделителе сразу печатается, например:
Это новый документ
Файл: 123456.pdf

Пока вижу одно решение - найти какой-нибудь OCR-объект, который понимает PDF.
Порекомендуйте, пожалуйста, какие есть?

Любые альтернативные идеи приветствуются.
Спасибо.

2

Re: VBS, Jscript: объект типа OCR для чтения и распознавания PDF

Сформулирую вопрос по другому:

кто работал с объектом AcroExch.PDDoc ?

Я открываю PDF-файл этим объектом - как с его помощью пройтись по всем картинкам, которые в нем?
Т.е. найти первую, затем цикл по всем остальным?

Рою в направлении метода GetJSObject() - но пока не получается.

3

Re: VBS, Jscript: объект типа OCR для чтения и распознавания PDF

Slav пишет:

кто работал с объектом AcroExch.PDDoc ?

Для него, наверное, Acrobat нужен, не Reader?

4

Re: VBS, Jscript: объект типа OCR для чтения и распознавания PDF

GetJSObject() возвращает данные о PDF-яваскриптe. К получению данных извне он не имеет никакого отношения.

5 (изменено: Slav, 2012-03-25 09:07:19)

Re: VBS, Jscript: объект типа OCR для чтения и распознавания PDF

alexii пишет:

Для него, наверное, Acrobat нужен, не Reader?

alexii,

да, нужен полный Acrobat - только Reader это объект не ставит.

6

Re: VBS, Jscript: объект типа OCR для чтения и распознавания PDF

JSman пишет:

GetJSObject() возвращает данные о PDF-яваскриптe. К получению данных извне он не имеет никакого отношения.

JSman,

вероятно, я не очень точно сформулировал задачу.
Никаких внешних данных мне получать не нужно.

Есть готовый многостраничный PDF - по большому счету как он получен вообще не важно (в моем случае он отсканирован с МФУ).
Весь этот файл состоит только из графических объектов - результатов сканирования.
На первом этапе мне просто надо пройтись по всем этим графическим объектам.
А уже на втором - передать каждый из них в OCR, проанализировать и если это страница-разделитель то предпринять соответствующие действия.

Вот с первым этапом пока проблема.
Аналог из VBA.
Откройте, например, WORD, вставьте туда пару картинок и запустите макро:

Sub Test01()
  MsgBox ActiveDocument.InlineShapes.Count
End Sub

Понятно - есть коллекция графических объектов, по этой коллекции можно пройтись, каждый элемент можно передать в OCR и т.д.

Есть ли что-то похожее в Acrobate?

7

Re: VBS, Jscript: объект типа OCR для чтения и распознавания PDF

1.PDF можно разложить на Tiff если установлен  Ghostscript
  1.1 Используя ImageMagick-6.7.4-Q16 :

Set img = CreateObject("ImageMagickObject.MagickImage.1")
myarray(0)="8BIM:"
msgs = img.Convert("null:","-profile","8BIMTEXT:iptctext.txt",myarray)
....

Основной недостаток умирает на PDF больших файлах ( >30 страниц)

1.2 Использовать конвертер nconvert.exe XnView
Пример: обрабатываем файлы рамером  меньше <100 страниц

@echo off
cscript step1.js
SET DIR_IN=.\image\
SET DIR_OUT=.\tif\
if not exist %DIR_IN% mkdir %DIR_IN%
if not exist %DIR_OUT% mkdir %DIR_OUT%

FOR %%i IN (%DIR_IN%*) DO CALL :0 %%i  
:0

for /f " tokens=2 delims=:" %%a in ('""C:\Program Files\XnView\nconvert.exe" -info %1 | findstr  /R /C:"Page.s.*:""') do  Set /A  nPage = %%a
if %nPage% GTR 100 goto xDel:
"C:\Program Files\XnView\nconvert.exe" -out tiff -xall -dpi 300  -o %DIR_OUT%%~nx1.####.jpg %1  

:xDel
if %ERRORLEVEL% NEQ 0 GOTO EOF
DEL %1 /Q
goto EOF
:EOF

2. Для распознования  можно использовать OCR  MS Office  (версии меньше 2010) MODI.Document
При распозновании многстраничного TIF  MODI.Document часто сваливается в ошибку и вылетает из скрипта.
При распозновании отдельных страниц возникает исключение всегда на пустых страницах.
На заполненых страницах иногда (повторная обработка)

Скрипт предназначен для получения текстовой информации из графических файлов для системы полнотекстового поиска.
Графические файлы разбиты на страницы батником из пп 1.2.
Контроль за повторной обработкой через списки lgood_jpg,lbad_jpg.
порядок следования распознанных страниц из-за исключения может быть произвольным.

var FolderIMG=".\\tif\\"
var FolderTXT=".\\txt_jpg\\"

var fso = new ActiveXObject("Scripting.FileSystemObject")
var Document = WScript.CreateObject ("MODI.Document");

function CopyTextFromTIF(PathIn,PathOut)
{
    Document.Create(PathIn);
WScript.Sleep(250)
    Document.OCR(25,true,true);
WScript.Sleep(100)
//    Document.Save()
    var iFile=fso.OpenTextFile(PathOut,8,true)
    iFile.WriteLine(PathIn)
    for (var j=0; j< Document.Images.Count; j++)
    {
    iFile.WriteLine(Document.Images.item(j).Layout.Text)
    WScript.Sleep(100)
    }
    iFile.Close()
    Document.Close(false);
WScript.Sleep(100)
this.CollectGarbage();
WScript.Sleep(250)
}
var k=0
var 
oTif ={}
try
{
var a = fso.OpenTextFile("lgood_jpg", 1).ReadAll().split(/(\r\n)|(\n)/)
for (var i=1; i <a.length;i++)
oTif[a[i]]=1
}
catch (e){}

var oBad ={}
try
{
var a = fso.OpenTextFile("lbad_jpg", 1,true).ReadAll().split(/(\r\n)|(\n)/)
for (var i=1; i <a.length;i++)
{
var x=a[i]
if (oBad[x]==null)
oBad[x]=0
oBad[x]++
}
}
catch (e){}

var vDir=fso.GetFolder(FolderIMG)
for(var lSub= new Enumerator(vDir.files);!lSub.atEnd();lSub.moveNext())
{
var n=lSub.item()
try
{
if (oTif[n.path]==null && (oBad[n.path]==null ||  oBad[n.path]<4))
{
WScript.Echo(n.path)

var fln=fso.OpenTextFile("lbad_jpg", 8,true)
fln.WriteLine(n.path)
fln.Close()

var aX=n.Name.split('.')
CopyTextFromTIF(n.path,".\\txt_jpg\\"+aX[0]+"."+aX[1]+"."+aX[2]+".txt")
var fln=fso.OpenTextFile("lgood_jpg", 8,true)
fln.WriteLine(n.path)
fln.Close()
} else{
WScript.Echo("-"+n.path)
if (oTif[n.path]  || (oBad[n.path] &&  oBad[n.path]>=4))
n.Delete(true)
}
}
catch(e)
{
WScript.Echo("?" + e.number + " " + e.description)
}
WScript.Sleep(50)
}

Скрипт необходимо запускается несколько раз подряд из батника из-за возможных ошибок с вылетом из скрипта объект MODI.Document

SET DIR_OUT=.\tif\
:modi
cscript modi_pdf.js
if  exist %DIR_OUT%*.jpg goto :modi

8

Re: VBS, Jscript: объект типа OCR для чтения и распознавания PDF

badik,

спасибо за практически готовое решение.

Задачу решил, скрипт выложу чуть позже.

Пока хочу задать дополнительный вопрос - кто-нибудь может посоветовать библиотеку для распознавания штрих-кодов?
Для начала хотелось бы бесплатную...

9

Re: VBS, Jscript: объект типа OCR для чтения и распознавания PDF

Slav пишет:

кто-нибудь может посоветовать библиотеку для распознавания штрих-кодов?
Для начала хотелось бы бесплатную...

штрих-код - это же шрифт, устанавливай и "распознавай"

10

Re: VBS, Jscript: объект типа OCR для чтения и распознавания PDF

Извините, раньше не мог.

Работает так.
У каждого делопроизводителя есть обычные листки, на которых четко указана его фамилия - обычная распечатка.
Регистрируя документ, он кладет его оригинал в стопку таких же, а сверху кладет этот самый листочек со своей фамилией.
Перед тем как пойти попить чайку, делопроизводитель берет свою пачку, а заодно и такие же пачки со столов своих коллег.
Все это соединяется в одну общую пачку и закладывается в сетевой сканер.
Тот сканирует эту пачку, выдавая один большой PDF-файл.
Мой скрипт разбирает этот PDF и по листкам-закладкам рассылает каждый по адресу соответствующего делопроизводителя.
Разбирает так:
Проходит по каждой странице исходного PDF, каждую страницу сохраняет отдельно в виде PDF.
Если PDF с одной страницей "большой" (в моем случае >10 Кбайт) - он тут же удаляется.
Если PDF с одной страницей "маленький" (<10 Кбайт) - он тут же средствами объекта AcroExch.PDDoc пересохраняется как TIF.
И этот TIF поступает в OCR (MODI).
Если в распознанном тексте находится фамилия одного из делопроизводителей - страница признается разделителем.
В этом случае происходит вырезание в исходном PDF соответствующего диапазона страниц, сохранение в формате PDF, отсылки этого документа по почте соответствующему делопроизводителю.

Для работы требуется полноценный ACROBAT (объекта AcroExch.PDDoc) и MS Office не ниже 2003 (объект MODI).


'
' 1) разделить PDF постранично
' 2) страницу-разделитель сохранить как TIF
' 3) TIF передать в OCR MS MODI
'

  rootDir = Left(WScript.ScriptFullName, instrrev(WScript.ScriptFullName,"\"))

  FileName = rootDir + "Scan002.pdf"

' открыть PDF
  Set oPDFDoc = CreateObject("AcroExch.PDDoc")

  If (Not oPDFDoc.Open(FileName)) Then
    Set oPDFDoc = Nothing
    WScript.Echo "Файл не найден : " & FileName
    WScript.Quit 1
  End If

' сохранить как TIF
  Set oTIFDoc = CreateObject("AcroExch.PDDoc")
' OCR MODI
  Set ocrMODI = CreateObject("MODI.Document")

  Set JSO = oPDFDoc.GetJSObject

  x_start = -1
  for x = 0 to JSO.numPages - 1
    FLNew = rootDir & "temp" & right(x + 1001,3) &".pdf"
    JSO.extractPages x, x, FLNew

' размер файла
    Set tmpPDF = objFSO.GetFile(FLNew)
      theSize = tmpPDF.Size

' проверить - закладка или нет
    flZakladka = False
    if (theSize < 10000) then  '  10000 - максимальный размер файла закладки
       ' сохранить как TIF
       retCod = oTIFDoc.Open(FLNew)
         Set JSTif = oTIFDoc.GetJSObject
           FLTif = rootDir & "temp" & right(x + 1001,3) & ".tif"
           retCod = JSTif.SaveAs(FLTif, "com.adobe.acrobat.tiff")
         Set JSTif = Nothing
       oTIFDoc.Close
       ' OCR MODI
       ocrMODI.Create(FLTif)
          ocrMODI.Images.item(0).OCR
          strResult = ocrMODI.Images.item(0).Layout.Text
          strResult = Replace(strResult, vbCrLf, "")
       ocrMODI.Close()
       ' удаляем временный TIF
       Set tmpTIF = objFSO.GetFile(FLTif)
         tmpTIF.Delete(true)
       Set tmpTIF = Nothing

       flZakladka = True
    end if

' удаляем временный PDF
      tmpPDF.Delete(true)
    Set tmpPDF = Nothing

' закладка
    if (flZakladka) then
       if (x_start >= 0) then
          x1 = x - 1
          FLPart = rootDir & strSave & "_Документ_" & right(x_start+1001, 3) & "_" & right(x1+1001,3) & ".pdf"
          JSO.extractPages x_start, x1, FLPart
            currFile = FLPart
            Call SendEmail
       end if
       x_start = x + 1
       strSave = strResult

       if (strSave = "ИВАНОВ")  then SendToAddr = "ivanov@domen.ru"
       if (strSave = "ПЕТРОВ")  then SendToAddr = "petrov@domen.ru"
       if (strSave = "СИДОРОВ") then SendToAddr = "sidorov@domen.ru"
    end if

  next

' последний документ
          x1 = x - 1
          FLPart = rootDir & strSave & "_Документ_" & right(x_start+1001, 3) & "_" & right(x1+1001,3) & ".pdf"
          JSO.extractPages x_start, x1, FLPart
            currFile = FLPart
            Call SendEmail

  oPDFDoc.Close

  Set JSO = Nothing
  Set ocrMODI = Nothing
  Set oTIFDoc = Nothing
  Set oPDFDoc = Nothing

  Set objFSO = Nothing

WScript.Echo "The End"

WScript.Quit 0


' *** отправка по почте

Sub SendEmail
...
 здесь используем SendToAddr
...
End Sub

11

Re: VBS, Jscript: объект типа OCR для чтения и распознавания PDF

dab00 пишет:

штрих-код - это же шрифт, устанавливай и "распознавай"

dab00,

а Вы сами-то пробовали так сделать?

12

Re: VBS, Jscript: объект типа OCR для чтения и распознавания PDF

ghostscript -pDEVICE=tifflzw -pOutputFile=file.tif < file.pdf + modi.document

Я конечно далек от мысли... (с)