簡體   English   中英

自動換行文本以適合一定比例的矩形(不是大小)

[英]Word wrap text to fit an rectangle of certain ratio (not size)

任何人都知道一種算法可以在單詞邊界處打破文本以適應某個近似比例的矩形 - 例如 60:40(寬:高)?

請注意,這不僅僅是寬度(例如 80 個字符或 600 像素等)和任意高度,它排除了我能找到的每個自動換行算法。

javascript 的加分點,但這更多的是關於算法而不是實現。

這可以做到:

int lineHeight := getHeightOfTextLine()
int lines := 0
do {
  lines += 1
  int width = lines * lineHeight * ratio
  String wrappedText := break(input, width)
} while(getNumberOfLines(wrappedText) != lines)

從一行開始,我簡單地測試每個高度(lineHeight 的倍數),如果我有一個可以容納文本的給定比例的矩形。 如果以計算出的寬度打破文本會導致字符串的行數超過允許的行數(對於運行),則繼續,否則我有一個解決方案。

好吧,如果您從每個單詞的高度和寬度數組開始,那么您需要運行多種可能性,直到找到給定寬度的最小浪費(單詞和之間的空間):高度

通常你會從

ratio := 6 / 4
noOfLines := totalWidth / ( ratio * lineHeight )
targetLineWidth := totalWidth / noOfLines

然后嘗試確定在哪些單詞之后放置換行符以最小化單詞之間的空間。

如果您嘗試將每一行的空間最小化,則最后一行可能會出現額外的空間。 如果您首先確保即使是最后一行也均勻分布,那么您應該只檢查一些變化。

編輯
如果您想弄亂確切的字體指標, 這個問答看起來很有用。

這是一個使用textwrapPillow的 Python 實現,它也保留了現有的換行符:

from PIL import Image, ImageDraw
import textwrap

def get_text_with_linebreaks_to_fit_ratio(input_text, target_ratio):
    width_in_nchar = 1 
    placeholder_img = Image.new('RGB', (1, 1), (255, 255, 255))
    placeholder_img_D = ImageDraw.Draw(placeholder_img)
    intermediary_text = input_text.split("\n")   # splits on newlines

    while True:
        intermediary_text2 = [textwrap.wrap(element, width_in_nchar) for element in intermediary_text] # for each paragraph, cut it with a width of width_in_nchar
        wrapped_text = [item for sublist in intermediary_text2 for item in sublist]   # flattening the output list
        wrapped_text_as_string = "".join([el+"\n" for el in wrapped_text])

        a, b = placeholder_img.multiline_textsize(wrapped_text_as_string)
        if a/b > target_ratio:
            newest_ratio = a/b
            break
        old_ratio = a/b
        width_in_nchar +=1

    if newest_ratio - target_ratio> old_ratio - target_ratio: # if the last ratio we got is farther from target ratio than the previous ratio
        width_in_nchar -=1 # then we go one step back
        intermediary_text2 = [textwrap.wrap(element, width_in_nchar) for element in intermediary_text] 
        wrapped_text = [item for sublist in intermediary_text2 for item in sublist]  
        wrapped_text_as_string = "".join([el+"\n" for el in wrapped_text])

    return {"as_string" : wrapped_text_as_string, "as_list" : wrapped_text}

然后查看輸出:

input_text = """Lorem ipsum dolor sit amet, consectetur adipiscing elit. In pellentesque pharetra ex, at varius sem suscipit ac. Suspendisse luctus condimentum velit a laoreet. Donec dolor urna, tempus sed nulla vitae, dignissim varius neque. Etiam non vulputate diam. Nullam luctus nisi mauris, sit amet feugiat nisi dapibus in. Fusce in interdum nisi. Nullam mattis a odio non interdum.

Sed accumsan laoreet pretium. Nulla facilisi. Morbi in eros suscipit, commodo turpis id, dignissim lorem. Maecenas quis urna auctor, rutrum velit vel, efficitur sem. Donec vulputate viverra justo a accumsan. Phasellus posuere est consectetur, tincidunt lorem volutpat, porttitor erat. Sed at ipsum euismod eros blandit vestibulum.

Integer a auctor quam. Mauris scelerisque sapien quis elementum euismod. Curabitur sed est tortor. Nullam eget tristique purus, eget venenatis enim. Etiam sem quam, lacinia at quam sed, laoreet ultrices mauris. Nunc aliquam dui iaculis pretium fringilla. Maecenas in ante vel libero eleifend condimentum. Vivamus at venenatis libero. Pellentesque sagittis tristique risus a molestie. Fusce vitae leo sed mauris ultricies tincidunt venenatis in lacus. Integer finibus arcu porttitor, viverra massa in, bibendum lacus.

Donec gravida nisi in facilisis sollicitudin. In aliquam vulputate velit. Pellentesque semper vitae justo efficitur tincidunt. Maecenas sit amet arcu eget arcu congue lobortis quis quis massa. Sed fringilla iaculis augue sit amet sodales. Ut at diam id lorem dapibus dignissim non eu tellus. Morbi accumsan, massa cursus eleifend facilisis, sapien ligula fringilla augue, quis bibendum neque lorem tristique est. Aenean sed augue at elit condimentum lacinia quis eu lacus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.

Nullam quis nisl lacinia nulla congue eleifend vitae id neque. Quisque lacinia nulla in dui fermentum, non ullamcorper massa rutrum. Vestibulum varius blandit facilisis. Aenean bibendum lorem ac sem aliquet ultrices. Nam nunc metus, auctor vel metus ac, interdum vestibulum magna. Vivamus facilisis vulputate ligula. Interdum et malesuada fames ac ante ipsum primis in faucibus. Mauris volutpat tristique libero eu auctor. Ut ac vestibulum eros.
"""

wrapped_text_as_string = get_text_with_linebreaks_to_fit_ratio(input_text, 16/9)["as_string"]

img_width = 1000
img_height = 1000
img = Image.new('RGB', (img_width, img_height), (255, 255, 255))
img_D = ImageDraw.Draw(img)
img_D.multiline_text((10, 10), wrapped_text_as_string, fill=(0,0,0))
img.save("test_img.jpeg", 'jpeg', optimize=True, quality = 200)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM