Differenze tra le versioni di "Eseguire una scansione e riconoscimento caratteri (OCR) con l'API di Sane, Tesseract e Leptonica"

Da Gambas-it.org - Wikipedia.
(Creata pagina con "Usando le risorse esterne del API di ''Sane'', ''Tesseract'' e ''Leptonica'' è possibile eseguire una scansione con la Scanner e il successivo riconoscimento caratteri (OCR)...")
 
 
(11 versioni intermedie di uno stesso utente non sono mostrate)
Riga 4: Riga 4:
  
 
E' necessario avere installate nel sistema e richiamare in Gambas le seguenti librerie condivise:
 
E' necessario avere installate nel sistema e richiamare in Gambas le seguenti librerie condivise:
<BR>"''libsane.so.1.0.27''", "''libtesseract.so.4.0.0''" e "''liblept.so.5.0.2''"
+
<BR>"''libsane.so.1.2.1'' ", "''libtesseract.so.4.0.1'' " e "''liblept.so.5.0.4'' "
 
 
  
 
Mostriamo un esempio pratico:
 
Mostriamo un esempio pratico:
 
  Private Const BUFFER As Integer = 65536
 
  Private Const BUFFER As Integer = 65536
  Private Const MODUS As String = "Color"  <FONT Color=Gray>'' Color  -  Gray  -  Lineart''</font>
+
  Private Const MODUS As String = "Color"  <FONT Color=Gray>' ''Color  -  Gray  -  Lineart''</font>
 
  Private RISOLUZIONE As Integer = 300
 
  Private RISOLUZIONE As Integer = 300
 
  Private Const OCR_BOOL As Boolean = True
 
  Private Const OCR_BOOL As Boolean = True
 
   
 
   
  Library "libsane:1.0.27"
+
  Library "libsane:1.2.1"
 
   
 
   
 
  Public Struct SANE_Option_Descriptor
 
  Public Struct SANE_Option_Descriptor
Riga 28: Riga 27:
 
   
 
   
 
  Public Struct SANE_Parameters
 
  Public Struct SANE_Parameters
   sformat As Byte
+
   sformat As Integer
   last_frame As Byte
+
   last_frame As Integer
 
   bytes_per_line As Integer
 
   bytes_per_line As Integer
 
   pixels_per_line As Integer
 
   pixels_per_line As Integer
Riga 66: Riga 65:
 
  Private Extern sane_start(handle As Pointer) As Integer
 
  Private Extern sane_start(handle As Pointer) As Integer
 
   
 
   
  <FONT Color=Gray>' ''SANE_Status sane_read (SANE_Handle handle, SANE_Byte * data, SANE_Int max_length, SANE_Int * length)''
+
  <FONT Color=gray>' ''SANE_Status sane_read (SANE_Handle handle, SANE_Byte * data, SANE_Int max_length, SANE_Int * length)''
  ' ''To read image data from the device represented by handle h.''</font>
+
  ' ''Reads image data from the device represented by handle h.''</font>
 
  Private Extern sane_read(handle As Pointer, data As Pointer, max_length As Integer, length As Pointer) As Integer
 
  Private Extern sane_read(handle As Pointer, data As Pointer, max_length As Integer, length As Pointer) As Integer
 
   
 
   
  <FONT Color=Gray>' ''void sane_cancel (SANE_Handle handle)''
+
  <FONT Color=gray>' ''void sane_cancel (SANE_Handle handle)''
  ' ''To immediately or as quickly as possible cancel the currently pending operation of the device.''</font>
+
  ' ''Cancels the currently pending operation of the device.''</font>
 
  Private Extern sane_cancel(handle As Pointer)
 
  Private Extern sane_cancel(handle As Pointer)
 
   
 
   
  <FONT Color=Gray>' ''void sane_close (SANE_Handle handle)''
+
  <FONT Color=gray>' ''void sane_close (SANE_Handle h)''
  ' ''Terminates the association between the device handle and the device it represents.''</font>
+
  ' ''Terminates the association between the device handle passed in argument h and the device it represents.''</font>
  Private Extern sane_close(handle As Pointer)
+
  Private Extern sane_close(h As Pointer)
 
   
 
   
 
  <FONT Color=Gray>' ''void sane_exit (void)''
 
  <FONT Color=Gray>' ''void sane_exit (void)''
Riga 83: Riga 82:
 
   
 
   
 
   
 
   
  '''Public''' Sub Main()
+
  Public Sub Main()
 
    
 
    
   Dim err, j, maxlun, lun As Integer
+
   Dim i, n, maxlun, lun As Integer
   Dim p, dev, hnd, vl, md, buf, plun As Pointer
+
   Dim dev, hnd, md, buf, plun As Pointer
 
   Dim nom As String
 
   Dim nom As String
 
   Dim sod As SANE_Option_Descriptor
 
   Dim sod As SANE_Option_Descriptor
Riga 95: Riga 94:
 
   Flush
 
   Flush
 
    
 
    
   err = sane_init(0, 0)
+
   i = sane_init(0, 0)
   If err > 0 Then GestErrore()
+
   If i > 0 Then GestErrore("sane_init()")
 +
 +
  i = sane_get_devices(VarPtr(dev), False)
 +
  If i > 0 Then GestErrore("sane_get_devices()")
 
    
 
    
   dev = VarPtr(p)
+
   While Pointer@(dev + i) > 0
    
+
    nom = String@(Pointer@(Pointer@(dev + i)))
   err = sane_get_devices(VarPtr(dev), False)
+
    i += 8
   If err > 0 Then GestErrore()
+
   Wend
    
+
   Write "\rDispositivo:    \e[31m" & nom
   nom = String@(Pointer@(Pointer@(dev)))
+
   Write "\rDispositivo:    " & nom
+
  i = sane_open(nom, VarPtr(hnd))
 +
   If i > 0 Then
 +
    GestErrore("sane_open()")
 +
    saneUscita(hnd)
 +
   Endif
 +
 +
   i = sane_control_option(hnd, 0, SANE_ACTION_GET_VALUE, VarPtr(n), 0)
 +
  If i > 0 Then
 +
    GestErrore("sane_control_option()")
 +
    saneUscita(hnd)
 +
   Endif
 
    
 
    
   hnd = Alloc(SizeOf(gb.Pointer), 8)
+
   Print "\n\n\e[0mPossibili opzioni:\e[32m"
 
+
   For i = 0 To n - 1
  err = sane_open(nom, VarPtr(hnd))
+
     sod = sane_get_option_descriptor(hnd, i)
  If err > 0 Then GestErrore()
 
 
 
  vl = Alloc(SizeOf(gb.Integer), 1)
 
   
 
  err = sane_control_option(hnd, 0, SANE_ACTION_GET_VALUE, vl, 0)
 
  If err > 0 Then GestErrore()
 
 
 
   For j = 0 To Int@(vl) - 1
 
     sod = sane_get_option_descriptor(hnd, j)
 
 
     If IsNull(String@(sod.name)) Then Continue
 
     If IsNull(String@(sod.name)) Then Continue
 +
    Print "  " & String@(sod.name)
 
     Select Case String@(sod.name)
 
     Select Case String@(sod.name)
       Case "mode"                   '' Color  -  Gray  -  Lineart
+
       Case "mode"                   <FONT Color=Gray>' ''Color  -  Gray  -  Lineart''</font>
 
         md = Alloc(MODUS)
 
         md = Alloc(MODUS)
         sane_control_option(hnd, j, SANE_ACTION_SET_VALUE, md, 0)
+
         sane_control_option(hnd, i, SANE_ACTION_SET_VALUE, md, 0)
 
       Case "resolution"
 
       Case "resolution"
         sane_control_option(hnd, j, SANE_ACTION_SET_VALUE, VarPtr(RISOLUZIONE), 0)
+
         sane_control_option(hnd, i, SANE_ACTION_SET_VALUE, VarPtr(RISOLUZIONE), 0)
 
     End Select
 
     End Select
 
   Next
 
   Next
 
+
   err = sane_get_parameters(hnd, par)
+
   i = sane_get_parameters(hnd, par)
   If err > 0 Then GestErrore()
+
   If i > 0 Then
 +
    GestErrore("sane_get_parameters()")
 +
    saneUscita(hnd)
 +
  Endif
 +
 
   With par
 
   With par
     Print "\nPixels per line: "; .pixels_per_line
+
    Dim px As Byte = .bytes_per_line / .pixels_per_line
     Print "Colonne:         "; .lines
+
    Dim rgb As String = " byte)"
     Print "Righe:           "; .depth
+
    If px == 3 Then rgb = " byte = RGB)"
     Print "Bytes per line: "; .bytes_per_line
+
     Print "\n\e[0mColonne:         "; .pixels_per_line; " (1 colonna = 1 pixel = "; px; RGB
 +
     Print "Righe:           "; .lines
 +
     Print "Byte per riga:   "; .bytes_per_line; " (colonne x "; px; Left(rgb, 5); ")"
 +
     Print "Bit per campione: "; .depth
 
     Print "Modalità:        "; MODUS
 
     Print "Modalità:        "; MODUS
 
     Print "Risoluzione:    "; RISOLUZIONE; " dpi\n"
 
     Print "Risoluzione:    "; RISOLUZIONE; " dpi\n"
 
   End With
 
   End With
  Wait 1
 
  err = sane_start(hnd)
 
  If err > 0 Then GestErrore()
 
 
    
 
    
 +
  i = sane_start(hnd)
 +
  If i > 0 Then
 +
    GestErrore(hnd, "sane_start()")
 +
    saneUscita(hnd)
 +
  Endif
 +
 
   buf = Alloc(SizeOf(gb.Byte), BUFFER)
 
   buf = Alloc(SizeOf(gb.Byte), BUFFER)
 
   plun = Alloc(SizeOf(gb.Integer), 1)
 
   plun = Alloc(SizeOf(gb.Integer), 1)
 
   maxlun = BUFFER
 
   maxlun = BUFFER
 
+
  If Exist("/tmp/imm") Then Kill "/tmp/imm"
+
   fl = Open "/tmp/imm" For Create
   fl = Open "/tmp/imm" For Write Append
+
 
 
 
   Repeat
 
   Repeat
     err = sane_read(hnd, buf, maxlun, plun)
+
     i = sane_read(hnd, buf, maxlun, plun)
     Select Case err
+
     Select Case i
 
       Case 1
 
       Case 1
         GestErrore()
+
         GestErrore("sane_read()")
 +
        saneUscita(hnd)
 
       Case 3 To 4
 
       Case 3 To 4
         GestErrore()
+
         GestErrore("sane_read()")
 +
        saneUscita(hnd)
 
       Case 6 To 11
 
       Case 6 To 11
         GestErrore()
+
         GestErrore("sane_read()")
 +
        saneUscita(hnd)
 
     End Select
 
     End Select
 
     lun = Int@(plun)
 
     lun = Int@(plun)
 
     Write #fl, buf, lun
 
     Write #fl, buf, lun
 
   Until lun = 0
 
   Until lun = 0
 
+
  sane_cancel(hnd)
 
 
 
 
   CreaFileImmagine(par)
 
   CreaFileImmagine(par)
 
    
 
    
Riga 170: Riga 184:
 
   fl.Close
 
   fl.Close
 
   Free(md)
 
   Free(md)
  Free(vl)
 
 
   Free(plun)
 
   Free(plun)
 
   Free(buf)
 
   Free(buf)
   sane_close(hnd)
+
   saneUscita(hnd)
  Free(hnd + (SizeOf(gb.Pointer) * 3))
+
  hnd = 0
 
  saneUscita()
 
 
 
 
  <FONT Color=Gray>' ''Chiama la funzione per il riconoscimento OCR:''</font>
 
  <FONT Color=Gray>' ''Chiama la funzione per il riconoscimento OCR:''</font>
 
   If OCR_BOOL = True Then Ocr()
 
   If OCR_BOOL = True Then Ocr()
 
    
 
    
  '''End'''
+
  End
 +
 
    
 
    
  '''Private''' Procedure GestErrore()
+
  Private Procedure GestErrore(fnz As String)
 
+
  saneUscita()
+
   Error.Raise("Errore alla funzione: " & fnz)
   Error.Raise("Errore !")
+
 
+
  End
  '''End'''
+
 
   
 
   
 +
Private Procedure saneUscita(handle As Pointer)
 
   
 
   
'''Private''' Procedure saneUscita()
+
  sane_cancel(handle)
    
+
   sane_close(handle)
 
   sane_exit()
 
   sane_exit()
 
 
'''End'''
 
 
   
 
   
  '''Private''' Procedure CreaFileImmagine(prmt As SANE_Parameters)
+
  End
 
+
 +
Private Procedure CreaFileImmagine(prmt As SANE_Parameters)
 +
 
   Dim s, finale, mg As String
 
   Dim s, finale, mg As String
   Dim pro, p4, lns, dep As Integer
+
   Dim pro, p4, colonne, righe As Integer
   Dim aBN As Byte
+
   Dim bBN As Byte
 
+
   pro = prmt.lines * prmt.depth
+
   pro = prmt.lines * prmt.bytes_per_line
 
   s = File.Load("/tmp/imm")
 
   s = File.Load("/tmp/imm")
 
+
   Print "\nDati grezzi:     "; Len(s); " byte"
+
   Print "Dati grezzi: "; Len(s); " byte (Colonne x Righe x 3 byte_RGB)"
  Print "Colonne x Righe: "; pro; " pixel\n"
+
 
+
   colonne = prmt.pixels_per_line
   lns = prmt.lines
+
   righe = prmt.lines
   dep = prmt.depth
+
 
 
 
   Select Case MODUS
 
   Select Case MODUS
 
     Case "Color"
 
     Case "Color"
Riga 234: Riga 245:
 
  <FONT Color=Gray>' ''Se il numero dei dati grezzi è maggiore di (Colonne x Righe) / 8, allora colma la differenza:''</font>
 
  <FONT Color=Gray>' ''Se il numero dei dati grezzi è maggiore di (Colonne x Righe) / 8, allora colma la differenza:''</font>
 
       If Len(s) > (pro / 8) Then
 
       If Len(s) > (pro / 8) Then
         For aBN = 1 To 8
+
         For bBN = 1 To 8
           If (Len(s) * 8) Mod (prmt.lines + aBN) == 0
+
           If (Len(s) * 8) Mod (prmt.lines + bBN) == 0
             lns = prmt.lines + aBN
+
             colonne = prmt.lines + bBN
             dep = Len(s) * 8 / prmt.lines
+
             righe = Len(s) * 8 / prmt.lines
 
           Endif
 
           Endif
 
         Next
 
         Next
Riga 253: Riga 264:
 
  ' ''i dati grezzi dell'immagine scansita;''
 
  ' ''i dati grezzi dell'immagine scansita;''
 
  ' ''le informazioni e commento finale:''</font>
 
  ' ''le informazioni e commento finale:''</font>
   finale = mg & lns & Chr(&20) & dep & " 255" & Chr(10) & s & Chr(10) &
+
   finale = mg & CStr(colonne) & Chr(&20) & CStr(righe) & " 255" & Chr(10) & s & Chr(10) &
 
           "# file creato da " & Application.Name & " - " & CStr(Now)
 
           "# file creato da " & Application.Name & " - " & CStr(Now)
 
  <FONT Color=Gray>' ''...e lo salva:''</font>
 
  <FONT Color=Gray>' ''...e lo salva:''</font>
 
   File.Save("/tmp/scansione.pnm", finale)
 
   File.Save("/tmp/scansione.pnm", finale)
 
    
 
    
  '''End'''
+
  End
 
   
 
   
 
   
 
   
Riga 275: Riga 286:
 
  End Struct
 
  End Struct
 
   
 
   
  Library "libtesseract:4.0.0"
+
  Library "libtesseract:4.0.1"
 
   
 
   
 
  <FONT Color=Gray>' ''TessBaseAPI* TessBaseAPICreate()''</font>
 
  <FONT Color=Gray>' ''TessBaseAPI* TessBaseAPICreate()''</font>
Riga 302: Riga 313:
 
   
 
   
 
   
 
   
  Library "liblept:5.0.2"
+
  Library "liblept:5.0.4"
 
   
 
   
 
  <FONT Color=Gray>' ''PIX * pixRead (const char *filename)''</font>
 
  <FONT Color=Gray>' ''PIX * pixRead (const char *filename)''</font>
Riga 311: Riga 322:
 
    
 
    
 
    
 
    
  '''Public''' Sub Ocr()
+
  Private Procedure Ocr()
 
    
 
    
 
   Dim err As Integer
 
   Dim err As Integer
Riga 345: Riga 356:
 
   pixDestroy(Object.Address(pis) + (SizeOf(gb.Pointer) * 3))
 
   pixDestroy(Object.Address(pis) + (SizeOf(gb.Pointer) * 3))
 
    
 
    
  '''End'''
+
  End

Versione attuale delle 19:24, 1 gen 2024

Usando le risorse esterne del API di Sane, Tesseract e Leptonica è possibile eseguire una scansione con la Scanner e il successivo riconoscimento caratteri (OCR) di un documento testuale.

In particolare con le funzioni esterne della libreria libsane si eseguirà la scansione attraverso uno scanner; con le funzioni esterne della libreria liblept si caricherà l'immagine ottenuta dalla scansione del documento, e con le funzioni esterne della libreria libtesseract si eseguirà il riconoscimento ottico dei caratteri presenti nell'immagine caricata.

E' necessario avere installate nel sistema e richiamare in Gambas le seguenti librerie condivise:
"libsane.so.1.2.1 ", "libtesseract.so.4.0.1 " e "liblept.so.5.0.4 "

Mostriamo un esempio pratico:

Private Const BUFFER As Integer = 65536
Private Const MODUS As String = "Color"   ' Color  -  Gray  -  Lineart
Private RISOLUZIONE As Integer = 300
Private Const OCR_BOOL As Boolean = True

Library "libsane:1.2.1"

Public Struct SANE_Option_Descriptor
  name As Pointer
  title As Pointer
  desc As Pointer
  type As Integer
  unit As Integer
  size As Integer
  cap As Integer
  constraint_type As Integer
  union As Pointer
End Struct

Public Struct SANE_Parameters
  sformat As Integer
  last_frame As Integer
  bytes_per_line As Integer
  pixels_per_line As Integer
  lines As Integer
  depth As Integer
End Struct

Private Enum SANE_ACTION_GET_VALUE = 0, SANE_ACTION_SET_VALUE, SANE_ACTION_SET_AUTO

' SANE_Status sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
' This function must be called before any other SANE function can be called.
Private Extern sane_init(version_code As Pointer, authorize As Pointer) As Integer

' SANE_Status sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
' To query the list of devices that are available.
Private Extern sane_get_devices(device_list As Pointer, local_only As Boolean) As Integer

' SANE_Status sane_open (SANE_String_Const devicename, SANE_Handle * handle)
' To establish a connection to a particular device.
Private Extern sane_open(devicename As String, handle As Pointer) As Integer

' SANE_Status sane_control_option (SANE_Handle handle, SANE_Int option, SANE_Action action, void *value, SANE_Int * info)
' To set or inquire the current value of option number n of the device represented by handle h.
Private Extern sane_control_option(handle As Pointer, option As Integer, action As Integer, value As Pointer, info As Pointer) As Integer

' const SANE_Option_Descriptor * sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
' To access option descriptors.
Private Extern sane_get_option_descriptor(handle As Pointer, option As Integer) As Pointer

' SANE_Status sane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
' To obtain the current scan parameters.
Private Extern sane_get_parameters(handle As Pointer, params As SANE_Parameters) As Integer

' SANE_Status sane_start (SANE_Handle handle)
' Initiates aquisition of an image from the device represented by handle h.
Private Extern sane_start(handle As Pointer) As Integer

' SANE_Status sane_read (SANE_Handle handle, SANE_Byte * data, SANE_Int max_length, SANE_Int * length)
' Reads image data from the device represented by handle h.
Private Extern sane_read(handle As Pointer, data As Pointer, max_length As Integer, length As Pointer) As Integer

' void sane_cancel (SANE_Handle handle)
' Cancels the currently pending operation of the device.
Private Extern sane_cancel(handle As Pointer)

' void sane_close (SANE_Handle h)
' Terminates the association between the device handle passed in argument h and the device it represents.
Private Extern sane_close(h As Pointer)

' void sane_exit (void)
' To terminate use of a backend.
Private Extern sane_exit()


Public Sub Main()
 
 Dim i, n, maxlun, lun As Integer
 Dim dev, hnd, md, buf, plun As Pointer
 Dim nom As String
 Dim sod As SANE_Option_Descriptor
 Dim par As New SANE_Parameters
 Dim fl As File
 
 Write "\e[5mRestare in attesa...\e[0m"
 Flush
 
 i = sane_init(0, 0)
 If i > 0 Then GestErrore("sane_init()")

 i = sane_get_devices(VarPtr(dev), False)
 If i > 0 Then GestErrore("sane_get_devices()")
 
 While Pointer@(dev + i) > 0
   nom = String@(Pointer@(Pointer@(dev + i)))
   i += 8
 Wend
 Write "\rDispositivo:     \e[31m" & nom

 i = sane_open(nom, VarPtr(hnd))
 If i > 0 Then
   GestErrore("sane_open()")
   saneUscita(hnd)
 Endif

 i = sane_control_option(hnd, 0, SANE_ACTION_GET_VALUE, VarPtr(n), 0)
 If i > 0 Then
   GestErrore("sane_control_option()")
   saneUscita(hnd)
 Endif
 
 Print "\n\n\e[0mPossibili opzioni:\e[32m"
 For i = 0 To n - 1
   sod = sane_get_option_descriptor(hnd, i)
   If IsNull(String@(sod.name)) Then Continue
   Print "   " & String@(sod.name)
   Select Case String@(sod.name)
     Case "mode"                    ' Color  -  Gray  -  Lineart
       md = Alloc(MODUS)
       sane_control_option(hnd, i, SANE_ACTION_SET_VALUE, md, 0)
     Case "resolution"
       sane_control_option(hnd, i, SANE_ACTION_SET_VALUE, VarPtr(RISOLUZIONE), 0)
   End Select
 Next

 i = sane_get_parameters(hnd, par)
 If i > 0 Then
   GestErrore("sane_get_parameters()")
   saneUscita(hnd)
 Endif

 With par
   Dim px As Byte = .bytes_per_line / .pixels_per_line
   Dim rgb As String = " byte)"
   If px == 3 Then rgb = " byte = RGB)"
   Print "\n\e[0mColonne:          "; .pixels_per_line; " (1 colonna = 1 pixel = "; px; RGB
   Print "Righe:            "; .lines
   Print "Byte per riga:    "; .bytes_per_line; " (colonne x "; px; Left(rgb, 5); ")"
   Print "Bit per campione: "; .depth
   Print "Modalità:        "; MODUS
   Print "Risoluzione:     "; RISOLUZIONE; " dpi\n"
 End With
 
 i = sane_start(hnd)
 If i > 0 Then
   GestErrore(hnd, "sane_start()")
   saneUscita(hnd)
 Endif

 buf = Alloc(SizeOf(gb.Byte), BUFFER)
 plun = Alloc(SizeOf(gb.Integer), 1)
 maxlun = BUFFER

 fl = Open "/tmp/imm" For Create

 Repeat
   i = sane_read(hnd, buf, maxlun, plun)
   Select Case i
     Case 1
       GestErrore("sane_read()")
       saneUscita(hnd)
     Case 3 To 4
       GestErrore("sane_read()")
       saneUscita(hnd)
     Case 6 To 11
       GestErrore("sane_read()")
       saneUscita(hnd)
   End Select
   lun = Int@(plun)
   Write #fl, buf, lun
 Until lun = 0

 CreaFileImmagine(par)
 
' Libera la memoria precedentemente allocata:
 fl.Close
 Free(md)
 Free(plun)
 Free(buf)
 saneUscita(hnd)

' Chiama la funzione per il riconoscimento OCR:
 If OCR_BOOL = True Then Ocr()
 
End

 
Private Procedure GestErrore(fnz As String)

 Error.Raise("Errore alla funzione: " & fnz)

End


Private Procedure saneUscita(handle As Pointer)

 sane_cancel(handle)
 sane_close(handle)
 sane_exit()

End

Private Procedure CreaFileImmagine(prmt As SANE_Parameters)

 Dim s, finale, mg As String
 Dim pro, p4, colonne, righe As Integer
 Dim bBN As Byte

 pro = prmt.lines * prmt.bytes_per_line
 s = File.Load("/tmp/imm")

 Print "Dati grezzi: "; Len(s); " byte (Colonne x Righe x 3 byte_RGB)"

 colonne = prmt.pixels_per_line
 righe = prmt.lines

 Select Case MODUS
   Case "Color"
     mg = "P6 "
' Se il numero dei dati grezzi è inferiore a (Colonne x Righe) x 3, allora colma la differenza:
     If Len(s) < ((pro / 8) * 3) Then s = s & String(((pro) * 3) - Len(s), Chr(255))
' Se invece il numero dei dati grezzi è maggiore di (Colonne x Righe) x 3, allora colma la differenza, ma tagliando i dati grezzi dalla fine:
     If Len(s) > ((pro) * 3) Then s = Left(s, pro * 3)
   Case "Gray"
     mg = "P5 "
' Se il numero dei dati grezzi è inferiore a Colonne x Righe, allora colma la differenza:
     If Len(s) < (pro) Then s = s & String((pro) - Len(s), Chr(255))
' Se invece il numero dei dati grezzi è maggiore di Colonne x Righe, allora colma la differenza, ma tagliando i dati grezzi dalla fine:
     If Len(s) > (pro) Then s = Left(s, pro)
   Case "Lineart"
     mg = "P4 "
' Se il numero dei dati grezzi è inferiore a (Colonne x Righe) / 8, allora colma la differenza:
     If Len(s) < (pro / 8) Then
       p4 = pro \ 8
       s = s & String$(p4 - Len(s), Chr(255))
     Endif
' Se il numero dei dati grezzi è maggiore di (Colonne x Righe) / 8, allora colma la differenza:
     If Len(s) > (pro / 8) Then
       For bBN = 1 To 8
         If (Len(s) * 8) Mod (prmt.lines + bBN) == 0
           colonne = prmt.lines + bBN
           righe = Len(s) * 8 / prmt.lines
         Endif
       Next
     Endif
 End Select
' Quindi, crea l'intero file .PNM finale, costituito da:
' l'header:
'   - numero Magico + spazio;
'   - numero colonne;
'   - spazio;
'   - numero righe;
'   - spazio;
'   - profondità colore;
'   - chiusura con "salto di riga";
' i dati grezzi dell'immagine scansita;
' le informazioni e commento finale:
 finale = mg & CStr(colonne) & Chr(&20) & CStr(righe) & " 255" & Chr(10) & s & Chr(10) &
          "# file creato da " & Application.Name & " - " & CStr(Now)
' ...e lo salva:
 File.Save("/tmp/scansione.pnm", finale)
 
End


Public Struct Pix
  w As Integer
  h As Integer
  d As Integer
  wpl As Integer
  refcount As Integer
  xres As Integer
  yres As Integer
  informat As Integer
  text As Pointer
  colormap As Pointer
  data As Pointer
End Struct

Library "libtesseract:4.0.1"

' TessBaseAPI* TessBaseAPICreate()
Private Extern TessBaseAPICreate() As Pointer

' int TessBaseAPIInit3(TessBaseAPI* handle, const char* datapath, const char* language)
Private Extern TessBaseAPIInit3(handle As Pointer, datapath As String, language As String) As Integer

' void TessBaseAPISetImage2(TessBaseAPI* handle, struct Pix* pix)
Private Extern TessBaseAPISetImage2(handle As Pointer, pix As Pix)

' void TessBaseAPISetSourceResolution(TessBaseAPI* handle, int ppi)
Private Extern TessBaseAPISetSourceResolution(handle As Pointer, ppi As Integer)

' int TessBaseAPIRecognize(TessBaseAPI* handle, ETEXT_DESC* monitor)
Private Extern TessBaseAPIRecognize(handle As Pointer, monitor As Pointer) As Integer

' char* TessBaseAPIGetUTF8Text(TessBaseAPI* handle)
Private Extern TessBaseAPIGetUTF8Text(handle As Pointer) As String

' void TessBaseAPIEnd(TessBaseAPI* handle)
Private Extern TessBaseAPIEnd(handle As Pointer)

' void TessBaseAPIDelete(TessBaseAPI* handle)
Private Extern TessBaseAPIDelete(handle As Pointer)


Library "liblept:5.0.4"

' PIX * pixRead (const char *filename)
Private Extern pixRead(filename As String) As Pix

' void pixDestroy (PIX **ppix)
Private Extern pixDestroy(ppix As Pointer)
 
 
Private Procedure Ocr()
 
 Dim err As Integer
 Dim tes, p As Pointer 
 Dim pis As Pix
 Dim s As String
 
 pis = pixRead("/tmp/scansione.pnm")
 
 tes = TessBaseAPICreate()
 If tes == 0 Then Error.Raise("Errore !")
 
 err = TessBaseAPIInit3(tes, Null, "eng")
 If err <> 0 Then Error.Raise("Errore !")
 
 TessBaseAPISetImage2(tes, pis)
 Write "Riconoscimento caratteri.\n\e[5m  Restare in attesa...\e[0m\r"
 Flush
 
 TessBaseAPISetSourceResolution(tes, RISOLUZIONE)
 
 err = TessBaseAPIRecognize(tes, 0)
 If err <> 0 Then Error.Raise("Errore !")
 
' Scansione OCR:
 s = TessBaseAPIGetUTF8Text(tes)
 Print Space(Len("  Restare in attesa..."))
 Print
 Print s
 
 TessBaseAPIEnd(tes)
 TessBaseAPIDelete(tes)
 pixDestroy(Object.Address(pis) + (SizeOf(gb.Pointer) * 3))
 
End