catalogue
- Generating text animation in Python
- Download emoticons locally
- Analysis dynamic diagram
- Generate a single picture
- Crawling dish data
- Generate dish name dynamic graph
- Other operations of PIL operation gif
- Gif split
- Gif rewind
Before, a little friend in the group asked what to eat this noon, and then another friend sent the following action chart:
Personally, I think it’s quite interesting. The screenshot is really like a lottery to choose a dish name at random. Considering that the candidates for dish names in this dynamic picture are not necessarily all the dishes we can eat. We can use Python to generate such a dynamic diagram according to the list of dish names.
What screenshots have you seen before? Choose the moving pictures such as avatars. The moving pictures generated by pictures are relatively simple, which can be done through the image animation workshop tool mentioned in the article. Therefore, this article only demonstrates how to generate text dynamic graph.
Generating text animation in Python
Let’s complete this step by step:
Download emoticons locally
In order to analyze this expression picture, you need to download it first, but the expression dynamic picture of wechat can’t be downloaded directly after testing.
Although it is analyzed by the file monitoring tool, the GIF expression animation is stored inC: \ users \ ASUS \ documents \ wechat files \ your wechat ID \ filestorage \ customemotion \ XX \ XXXX
Location, but you can’t view it with the picture tool. By analyzing binary system with WinHex, we getV1MMWX
Such a file header shows that wechat encrypts the expression to a certain extent. Although it can be decrypted, such a big fight is too troublesome.
A simple solution came to mind later, that is, send the expression to the official account that has permission to login to the backstage, then download it to the official account.
The motion pictures sent by wechat are stored as their ownV1MMWX
The encryption format may be to use its own original compression algorithm to have a larger compression ratio. That means that if we want to directly look at the GIF dynamic diagram stored in local wechat, we can only develop a decoder specifically for this wechat format.
Analysis dynamic diagram
Now I use the gadget imagine and open it with the Animation Workshop:
It can be seen that this moving picture is composed of 22 text pictures, and the frame switching time is 20 milliseconds.
Generate a single picture
After the analysis is completed, we consider using the PIL library to generate a single picture. If the children’s shoes of the library have not been installed, use the following command to install the Library:
pip install pillow
The blue background is selected as the background. Let’s draw the text of the dish name in the middle first:
from PIL import Image, ImageFont, ImageDraw
Text = "Braised Beef Brisket with pearl potatoes"
size = 320
fontsize = (size-20)//len(text)
im = Image.new(mode='RGB', size=(size, size), color="lightblue")
draw = ImageDraw.Draw(im=im)
draw.text(xy=(10, (size-fontsize*1.5)/2),
text=text, fill=0,
font=ImageFont.truetype('msyh.ttc', size=fontsize))
im
Due to the inconsistency in the number of names and characters of dishes, automatic text resizing is made in order to fill the whole picture.
Font I chose Microsoft YaHei. Of course, Microsoft YaHei also has three sub fonts. You can view the properties of the font file through the system font installation directory to know the file name corresponding to the font:
It will be troublesome to generate the text with shadow below. My idea is to draw the text in pure black first, and offset the text with black edge and white filling upward by several units:
def text_border(text, x, y, font, shadowcolor, fillcolor):
draw.text((x - 1, y), text, font=font, fill=shadowcolor)
draw.text((x + 1, y), text, font=font, fill=shadowcolor)
draw.text((x, y - 1), text, font=font, fill=shadowcolor)
draw.text((x, y + 1), text, font=font, fill=shadowcolor)
draw.text((x - 1, y - 1), text, font=font, fill=shadowcolor)
draw.text((x + 1, y - 1), text, font=font, fill=shadowcolor)
draw.text((x - 1, y + 1), text, font=font, fill=shadowcolor)
draw.text((x + 1, y + 1), text, font=font, fill=shadowcolor)
draw.text((x, y), text, font=font, fill=fillcolor)
Bottomtext = "don't know what to eat? Screenshot to eat"
bottom_fontsize = 27
bottom_font = ImageFont.truetype('STHUPO.TTF', size=bottom_fontsize)
x, y = (size-bottom_fontsize*len(bottomtext))/2, size-bottom_fontsize*1.2
draw.text(xy=(x, y), text=bottomtext,
fill=0, font=bottom_font)
text_border(bottomtext, x, y-4,
bottom_font, 0, (255, 255, 255))
im
The above code selects Chinese amber as the font. The personal method used to draw the text border is relatively simple and rough. If there is a better method, please leave a message.
Considering that the subsequent pictures sent to wechat are very small, just compress the pixel size now:
im.thumbnail((128, 128))
im
Let’s encapsulate the generated code to facilitate subsequent calls:
from PIL import Image, ImageFont, ImageDraw
def text_ IMG (text, bgcolor = "lightblue", bottomtext = "don't know what to eat? Screenshot to eat", size = 360, result_size = (128, 128)):
def text_border(text, x, y, font, shadowcolor, fillcolor):
draw.text((x - 1, y), text, font=font, fill=shadowcolor)
draw.text((x + 1, y), text, font=font, fill=shadowcolor)
draw.text((x, y - 1), text, font=font, fill=shadowcolor)
draw.text((x, y + 1), text, font=font, fill=shadowcolor)
draw.text((x - 1, y - 1), text, font=font, fill=shadowcolor)
draw.text((x + 1, y - 1), text, font=font, fill=shadowcolor)
draw.text((x - 1, y + 1), text, font=font, fill=shadowcolor)
draw.text((x + 1, y + 1), text, font=font, fill=shadowcolor)
draw.text((x, y), text, font=font, fill=fillcolor)
im = Image.new(mode='RGB', size=(size, size), color=bgcolor)
draw = ImageDraw.Draw(im=im)
fontsize = (size-20)//len(text)
draw.text(xy=(10, (size-fontsize*1.5)/2),
text=text, fill=0,
font=ImageFont.truetype('msyh.ttc', size=fontsize))
bottom_fontsize = (size-20)//len(bottomtext)
bottom_font = ImageFont.truetype('STHUPO.TTF', size=bottom_fontsize)
x, y = (size-bottom_fontsize*len(bottomtext))/2, size-bottom_fontsize*1.2
draw.text(xy=(x, y), text=bottomtext,
fill=0, font=bottom_font)
text_border(bottomtext, x, y-4,
bottom_font, 0, (255, 255, 255))
im.thumbnail(result_size)
return im
Test:
text_ IMG ("fish flavored eggplant")
OK, now we can generate pictures for any dish. But where does the name of the dish come from? I have found a website. Now consider climbing it:
Crawling dish data
The website is: https://m.meishij.net/caipu/
The result of this website is very simple. You can get all the dish names with a simple XPath:
Download Now:
from lxml import etree
import requests
req = requests.get("https://m.meishij.net/caipu/")
html = etree.HTML(req.text)
menu = html.xpath("//dl[@class='recipe_list']//a/text()")
menu = list(set([_.strip(".") for _ in menu]))
print(len(menu), menu[:10], menu[-10:])
3744 [‘spare ribs lotus root soup’, ‘taro balls’,’ seafood soup ‘,’ cold apricot abalone mushrooms’, ‘three juice stew pot’, ‘milk flavored corn juice’, ‘fried beans’,’ eggplant sauce ‘,’ mango glutinous rice dumpling ‘,’ steamed bread ‘] [‘ steamed eggplant ‘,’ broccoli fried chicken ‘,’ old-fashioned cake ‘,’ spare ribs rice cake ‘,’ fried towel gourd ‘,’ steamed spare ribs with taro ‘,’ fried pork with agaric fungus’, ‘oyster sauce and oatmeal’, ‘spicy chicken pieces’,’ lotus leaf cake ‘]
With these dish names, we can already use them to generate dynamic graphs. However, in order to learn how to cook in the future, we can save the dish names. When we want to learn how to cook, open the web page: https://so.meishi.cc/?q= Dish name, search.
Save dish name:
with open("meau.csv", "w", encoding="u8") as f:
f. Write ("dish name \ n")
for row in menu:
f.write(row)
f.write("\n")
Let’s start to generate the dish name dynamic diagram:
Generate dish name dynamic graph
After all, there are too many 3767 dish names. We can choose 30 dish names to generate a dynamic diagram:
import random
gif_list = random.choices(menu, k=30)
print(gif_list)
[‘steamed egg’, ‘Cinnamon Roll’, ‘fried egg with cold melon’, ‘baked sweet potato with cheese’, ‘banana crisp’, ‘yogurt mousse’, ‘egg vermicelli’, ‘shredded pork tripe with red oil’, ‘corn egg cake’, ‘hot and sour tofu soup’, ‘Stewed Beef Brisket with radish’, ‘balsam pear ribs soup’, ‘dried bean curd mixed with celery’, ‘fried soil with tomato’, ‘steamed eggplant with garlic’, ‘bean paste bread’, ‘fried meat with mushrooms’,’ fried lotus root ‘,’ black pepper beef granules’, ‘pumpkin pancake’, ‘fried cucumber ‘,’ steamed bread with grains’, ‘taoshanpi moon cake’, ‘fried meat with scallions’,’ stir fried beef ‘,’ crucian carp with bean sauce ‘,’ Braised Tofu with shrimp ‘,’ plain dumplings’, ‘cold cucumber’, ‘fish head in casserole’]
PS: it’s better to choose the dish name and write a dead list
import imageio
frames = [text_img(text) for text in gif_list]
imageio.mimsave("meau.gif", frames, 'GIF', duration=0.02)
Generated results:
Generate the complete code of dynamic diagram according to the menu name list
import imageio
from PIL import Image, ImageFont, ImageDraw
def text_ IMG (text, bgcolor = "lightblue", bottomtext = "don't know what to eat? Screenshot to eat", size = 360, result_size = (128, 128)):
def text_border(text, x, y, font, shadowcolor, fillcolor):
draw.text((x - 1, y), text, font=font, fill=shadowcolor)
draw.text((x + 1, y), text, font=font, fill=shadowcolor)
draw.text((x, y - 1), text, font=font, fill=shadowcolor)
draw.text((x, y + 1), text, font=font, fill=shadowcolor)
draw.text((x - 1, y - 1), text, font=font, fill=shadowcolor)
draw.text((x + 1, y - 1), text, font=font, fill=shadowcolor)
draw.text((x - 1, y + 1), text, font=font, fill=shadowcolor)
draw.text((x + 1, y + 1), text, font=font, fill=shadowcolor)
draw.text((x, y), text, font=font, fill=fillcolor)
im = Image.new(mode='RGB', size=(size, size), color=bgcolor)
draw = ImageDraw.Draw(im=im)
fontsize = (size-20)//len(text)
draw.text(xy=(10, (size-fontsize*1.5)/2),
text=text, fill=0,
font=ImageFont.truetype('msyh.ttc', size=fontsize))
bottom_fontsize = (size-20)//len(bottomtext)
bottom_font = ImageFont.truetype('STHUPO.TTF', size=bottom_fontsize)
x, y = (size-bottom_fontsize*len(bottomtext))/2, size-bottom_fontsize*1.2
draw.text(xy=(x, y), text=bottomtext,
fill=0, font=bottom_font)
text_border(bottomtext, x, y-4,
bottom_font, 0, (255, 255, 255))
im.thumbnail(result_size)
return im
def save_meau_gif(savename, meau):
frames = [text_img(text) for text in meau]
imageio.mimsave(savename, frames, 'GIF', duration=0.02)
Use example:
meau = [
"Lotus leaf glutinous rice chicken", "roast mutton", "Black Pepper Steak", "homemade large plate chicken", "mashed garlic beans",
"Fried beef with onion", "fried egg with towel gourd", "fried egg with mushroom", "sliced tofu with chicken", "Lotus fresh vegetable soup",
"Fried zucchini", "eggplant and beans", "beef with egg", "mushroom and green vegetables", "ground three delicacies",
"Braised Pleurotus eryngii with sauce", "chicken wings with fermented bean curd", "lotus root slices with vinegar", "stewed chicken with coconut", "Braised Tofu with mushrooms",
"Curry chicken leg rice", "mashed potato with chicken juice", "stewed potato with eggplant", "fried udong noodles", "curry potato chicken",
"Baby dish in soup", "steamed eggplant with minced garlic", "baked sweet potato with cheese", "braised chicken with chestnuts", "towel gourd tofu soup",
]
save_meau_gif("meau.gif", meau)
Generated results:
Since our dynamic graph has been generated! I don’t know what to eat. I can take out screenshots to play with~
Have a nice meal~
Other operations of PIL operation gif
In fact, it can be operated with special motion graph processing software. Here is a supplement. The operation API of Python records:
Gif split
For example, let’s split this picture:
from PIL import Image, ImageSequence
IMG = image. Open ('kung Fu bear. GIF ')
for i, f in enumerate(ImageSequence.Iterator(img), 1):
f. Save (f 'split / split - {I}. PNG')
Split result:
Gif rewind
Now let’s put the above dynamic diagram upside down:
from PIL import Image, ImageSequence
import imageio
Im = image. Open ('kung Fu bear. GIF ')
sequence = [f.copy() for f in ImageSequence.Iterator(im)]
Sequence. Reverse() # reverses the order of the frames in the list through the reverse() function
Sequence [0]. Save ('rewind Kung Fu bear. GIF ', save_all = true, append_images = sequence [1:])
This is the end of this article on generating screenshot GIF animation by python. For more information about generating screenshot GIF animation by python, please search the previous articles of developeppaer or continue to browse the relevant articles below. I hope you will support developeppaer in the future!