Wednesday, February 21, 2024

长图片分割器

文字长图片在手机上有时不得不切割。

+++++

等分切割

将一个长图片直接水平或者垂直等分切割成多个图片,这十分容易,Irfanview 就可以实现。点击 Options 主菜单,再点 Export image tiles (split images)...,然后设定如何等分,再切割。但是,这个方法不理想。

+++++

衔接等分切割(有重叠)

首先,手机图片的最佳显示比例是 4:3 或者 16:9。16:9 的图片拉得更长一些,是我倾向的选择。

以我的 iPhone 手机为例,手机截屏的图片的顶部和底部的宽度是 1242 pixels,如果选择 16:9,那么图片的左边和右边高度是 1242 * 16 / 9 = 2208 pixels。1242 x 2208 pixels 就是我们要的每个小图片的规格

我们设 TB = 1242,LR = 2208。

这里,T 取 Top 的首字母;B 取 Bottom 的首字母;L 取 Left 的shou'字母;R 取 Right 的首字母。

第二,文字长图片切割后的小图片没有序号,因此各个连续页之间最好有重叠部分,也就是实现衔接。

我们假设:

长图片总高度 LEN = 11575,重叠部分的高度是 OL。

这里,LEN 取自 Length 的头三个字母;OL 取自 Overlap。

LEN / LR = 11575 / 2208 = 5.24... 向上取舍,那么小图片总数 NUM = Roundup(6)。

这里 NUM 取自 Number 的头三个字母。

那么重叠部分的个数是 NUM - 1。

重叠部分的高度 OL = (NUM * LR - LEN) / (NUM-1) = (6*2208 - 11575)/(6-1) = 334.6。

那下图来演示以下。这是一个长图片分成四个小图片的情况,A、B、C、D 分别是每个小图片的左上角。

顶部和底部的空白高度是相等的,等于 LR - OL。

中间的每一个空白的高度是相等的,等于 LR - 2 * OL。

注意:图片的坐标 y 轴是向下的。图示如下:

这样很容易算出 A、B、C、D 点的坐标。

有了 A 点的坐标,我们将其写如到一个命令行里,如下,执行该命令行,就切割出了第一个小图片。这是 Irfanview 自带的命令行,参考这个页面

i_view32.exe c:\temp\longimage.jpg /crop=(0,0,TB,LR) /convert=c:\temp\splitimage1.jpg

写一个简单的小程序可以一次性将切割所有小图片的命令行写入到一个命令行执行文件里,执行该文件一次性完成所有小图片的切割。

+++++

优化重叠部分

上面的衔接等分切割还是有问题。重叠部分是全部一致相等的,这个重叠部分可能很高,重叠了很多行文字。比如上面计算出来的重叠部分高度是 334.6,重叠部分是 5 行字左右。这不理想。

理想的做法是除了最后两个小图片之外,前面所有的小图片的重叠部分为两行字左右,然后倒数第二张图片与最后一张图片能重叠多少就多少。

在手机上,两行 9 号中文文字的高度在常规间距下,选择这个重叠部分高度为 150 pixels 完全可以。

同样可以计算出每个小图片的左上角的坐标,写入到命令行文件,然后执行。

+++++

Python 小程序

Python 程序来实现上面的步骤。程序如下:

首先读入图片的尺寸。这个可以自动来完成,但是我电脑只安装了最基本的库,所以还是手工输入吧。

# Input width and height of the image
width = int(input("Enter the width: "))
height = int(input("Enter the height: "))

然后设定 overlap,建议设在 120 到 160 之间,除非字体特别大。

# Input overlap
overlap = int(input("Enter the overlap: ")) 

然后确定分割后的小图片的尺寸,采用 16:9 比例:

# width and height of the split image
tb = width
lr = math.floor(width * 16 / 9)

计算切割成多少份:

# Calculate the number of divisions
divisions = math.ceil(height / lr)

用一个函数计算出每一份的左上角的坐标:

# Calculate coordinates
division_coordinates = calculate_coordinates(height, lr, overlap, divisions)

然后将每个坐标放到每一个命令行里去,并写入到一个文件中:

# Write command lines to the file
with open("split_image.cmd", "w") as file:
    for i, (x, y) in enumerate(division_coordinates):
        output_filename = f"C:\\Users\\rrr\\Downloads\\splitimage{i + 1}.jpg"
        cmd_line = f'"C:\\Program Files\\IrfanView\\i_view64.exe" "C:\\Users\\rrr\\Downloads\\longimage.jpg" /crop=({x},{y},{tb},{lr}) /convert="{output_filename}"\n'
        file.write(cmd_line)

print("Command lines written to split_image.cmd")

就这样完成了。

计算坐标的函数如下:

def calculate_coordinates(height, lr, overlap, divisions):
    # Calculate the EndSpace and MidSpace
    EndSpace = lr - overlap
    MidSpace = lr - 2 * overlap

    # Initialize an empty list to store coordinates
    coordinates = []

    # First division: (0, 0)
    coordinates.append((0, 0))

    # Calculate coordinates for subsequent divisions
    for i in range(1, divisions - 1):  # Exclude the last division
        y = EndSpace + (i -1) * overlap + (i -1) * MidSpace
        coordinates.append((0, y))

    # Last division: (0, height - lr)
    coordinates.append((0, height - lr))

    return coordinates

因为用到了数学库,所以在第一行要加一句:

import math

完毕。

No comments:

Post a Comment