Python:使用 WIA API 扫描 Windows 下的文档

出于我当前正在进行的项目的目的,我需要访问扫描仪 扫描文件 从脚本 Python 在不同的平台上(主要是 Windows 和 macOS)。

今天我要和大家谈谈文档扫描 视窗 远离API威亚Windows图像采集),使用库 pywin32

安装依赖项

在开始编码之前,您当然需要在计算机上安装一些小东西,从最新版本的 Python 3 开始,您可以从 python.org。 安装Python时,记得勾选此框 « 将 python.exe 添加到路径 » 以便可以从终端访问该程序:

可能需要重新启动会话才能使 PATH 更新生效。

接下来我们需要安装 pywin32。 为此,请打开您的终端(执行 窗口>+R”,然后输入 “CMD.EXE”),然后输入以下命令:

pip install pywin32

笔记

笔记 : 如果您对 Python 有一定了解,最好将依赖项安装在 虚拟环境,但在本文中我们将坚持使用最简单的过程。 😉️

就这样,你就准备好了!

列出扫描仪

首先,我们将了解如何列出机器上可用的不同扫描仪。

为此,我们将创建一个小型 Python 脚本,我将其命名为 “列表扫描仪.py” 我将把它放在文件夹中 “扫描仪示例” 它在我的桌子上。 以下是脚本的内容以及适当的注释:

#!/usr/bin/env python3

# On charge la bibliothèque cliente pour les API Win32/COM
import win32com.client

# On charge et on instancie la classe qui permet de lister et manipuler les
# scanners
device_manager = win32com.client.Dispatch("WIA.DeviceManager")

# On parcourt tous les scanners dispo. Le "DeviceManager" va nous retourner
# des objets "DeviceInfo" qui nous permettront de récupérer les propriétés
# des périphériques et de nous y connecter par la suite.
for device_info in device_manager.DeviceInfos:
    print("-------------------------------------")
    # On affiche une à une les propriétés du scanner
    for prop in device_info.Properties:
        print("%s: %s" % (prop.Name, str(prop.Value)))

要运行此脚本,

  • 我们打开一个终端: 窗口> + R”,
  • 我们转到包含脚本的文件夹: “光盘 C:UsersFabienDesktopScannerExamples” (1),
  • 然后我们启动Python脚本: “python list_scanners.py” (5)。

如果一切顺利,您应该会看到显示的扫描仪列表及其所有属性 (5):

CMD.exe 中结果的屏幕截图

在此屏幕截图中,您可以看到我所做的比之前告诉您的多一点,但不要惊慌,我会快速向您解释这一切:

  1. 我转到包含脚本的文件夹。
  2. 我创建并激活一个 虚拟环境 因为我不想直接在系统上安装我的 Python 库,所以我更喜欢限制它(但您不必这样做)。
  3. 我安装库 “pywin32” 如前所述。
  4. 我列出了该文件夹的内容以表明该脚本 “列表扫描仪.py” 存在。
  5. 我运行我的脚本,如上所示。 我们可以看到扫描仪连接到我的机器(我审查了允许识别确切型号的信息)。

一切正常工作并能够运行脚本真正需要的唯一步骤是 1、3 和 5。

扫描文档

现在我们知道如何列出扫描仪,让我们看看如何扫描文档并将结果保存到文件中。

这是我的脚本 “扫描.py” 评论应该是这样的:

#!/usr/bin/env python3

import win32com.client

device_manager = win32com.client.Dispatch("WIA.DeviceManager")

# On prend le premier scanner disponible
#
# ATTENTION : contrairement aux listes Python, les listes Win32/COM
#             commencent à 1 et non à 0.
device_info = device_manager.DeviceInfos(1)

# On se connecte au scanner
device = device_info.Connect()

# On récupère le premier "élément" du périphérique (le scanner à plat pour
# moi). Il est possible qu'il y en ait plusieurs sur un scanner plus
# complexe, mais tous les scanners que j'ai utilisés n'en avait qu'un...
scan_source = device.Items(1)

# On numérise le document en sélectionnant au passage le format de l'image
# souhaité.
#
# NOTE¹ : À priori WIA semble supporter du BMP, du PNG, du JPEG etc. mais
#         je n'ai jamais réussi à obtenir autre chose que du BMP (c'est
#         peut-être dépendant des drivers ?). Je vous recommande donc de
#         choisir BMP et de convertir vous-même l'image dans un autre
#         format après coup, en utilisant la bibliothèque PIL par exemple.
#
# NOTE² : la constante « win32com.client.constants.wiaFormatBMP » n'existe
#         qu'après avoir exécuté « win32com.client.Dispatch("WIA.DeviceManager") »
#         dans le script.
#
#         Si jamais cette constante n'était pas disponible pour une raison
#         ou pour une autre, sachez que vous pouvez la remplacer par la
#         string suivante : "{B96B3CAB-0728-11D3-9D7B-0000F81EF32E}".
wia_image = scan_source.Transfer(win32com.client.constants.wiaFormatBMP)

# On sauvegarde l'image dans le fichier "out.bmp" dans le dossier courant
wia_image.SaveFile("out.bmp")

我们可以使用与之前相同的方式启动脚本,使用命令 “Python扫描.py”

在CMD.exe中运行scan.py的屏幕截图

在上面的截图中,我们可以看到该文件 “输出.bmp” 已根据我们的命令调用创建。 😃️

更改扫描设置

WIA API允许我们在扫描仪上配置一些参数,例如清晰度、对比度、亮度等。

这是一个显示可用选项的小脚本:

#!/usr/bin/env python3

import win32com.client

device_manager = win32com.client.Dispatch("WIA.DeviceManager")
device_info = device_manager.DeviceInfos(1)
device = device_info.Connect()
scan_source = device.Items(1)

# On liste les différents réglages du scanner
for prop in scan_source.Properties:
    print("%s: %s" % (prop.Name, str(prop.Value)))

这是执行上面的脚本后扫描仪给我的结果:

Item Name: Scan
Full Item Name: 0000RootScan
Item Flags: 532483
Color Profile Name: C:Windowssystem32spooldriverscolorsRGB Color Space Profile.icm
Access Rights: 1
Lamp Warm up Time: 120
Current Intent: 0
Horizontal Resolution: 200
Vertical Resolution: 200
Horizontal Start Position: 0
Vertical Start Position: 0
Horizontal Extent: 1700
Vertical Extent: 2340
Rotation: 0
Brightness: 0
Contrast: 0
Item Size: 0
Data Type: 3
Bits Per Pixel: 24
Compression: 0
Channels Per Pixel: 3
Bits Per Channel: 8
Photometric Interpretation: 0
Planar: 0
Buffer Size: 27262976
Threshold: 128
Filename extension: BMP
Media Type: 2
Preferred Format: {B96B3CAB-0728-11D3-9D7B-0000F81EF32E}  # <= GUID correspondant à BMP
Format: {B96B3CAB-0728-11D3-9D7B-0000F81EF32E}            # <= GUID correspondant à BMP
Pixels Per Line: 1700
Bytes Per Line: 5100
Number of Lines: 2340

在这里我们可以看到 API 使我们能够访问相当多的参数。 我们还可以看到参数的名称可以包含空格,所以稍后你必须小心这一点......🙃️

笔记

笔记 : 在下面的示例中,我将使用Python的REPL(命令行界面)语法:

  • 以三个 V 字形开头的线条 (>>>) 是 Python 指令,因为它们可以写在脚本中,
  • 以及以三个小点开头的行(...)允许他们显示上一条指令的结果。

现在我们已经列出了可用参数,我们将了解如何修改它们。 以参数为例 “对比”

要读取此参数的值,您可以按如下方式查询 API:

>>> scan_source.Properties("Contrast").Value
... 0

如果您想更改此值,只需分配一个新值即可:

>>> scan_source.Properties("Contrast").Value = 1000  # +100% de contraste

我们可以验证我们的更改是否已被考虑在内:

>>> scan_source.Properties("Contrast").Value
... 1000

这里我们可能会感到惊讶的是,有必要定义这个参数来 1000 增加对比度 100%...这是 API 的任意选择(并且可能取决于 司机 对于某些参数)。 幸运的是,可以知道每个参数的最小值和最大值,以及它们的“粒度”:

>>> scan_source.Properties("Contrast").SubTypeMin
... -1000
>>> scan_source.Properties("Contrast").SubTypeMax
... 1000
>>> scan_source.Properties("Contrast").SubTypeStep
... 1

为了将各个部分放在一起,这里有一个脚本,它可以扫描文档,并与 +50% 在第一个可用的扫描仪上:

#!/usr/bin/env python3

import win32com.client

device_manager = win32com.client.Dispatch("WIA.DeviceManager")
device_info = device_manager.DeviceInfos(1)
device = device_info.Connect()
scan_source = device.Items(1)
scan_source.Properties("Contrast").Value = scan_source.Properties("Contrast").SubTypeMax // 2
wia_image = scan_source.Transfer(win32com.client.constants.wiaFormatBMP)
wia_image.SaveFile("out.bmp")

事情并没有那么复杂

最后我们可以看到这个API非常容易使用,唯一的困难来自于微软的文档,它过于理论和冗长,并且来自于 pywin32 / 蟒蛇com 这可能缺乏有针对性的例子。

如果您想深入研究该主题,我将为您提供以下各种有用文档的链接:

以后的文章再见! 😉️

Leave a Reply

Your email address will not be published. Required fields are marked *

近期新闻​

编辑精选​