Earlier in the group, one of the guys asked what they should eat for lunch today, and then another guy posted a moving picture of the following:
Personally, I find it kinda interesting that the screenshot actually picks a random dish name like a lottery. Considering that not all of the dish name candidates in this motion picture are necessarily dishes that we can eat. We can play around with python to generate such a motion picture based on a list of dish names.
Before I also saw what screenshots to choose avatars and other moving pictures, that type of moving pictures generated through the picture are relatively simple, through the text mentioned in the animation workshop tool of Imagine can do. So this article only demonstrates how to generate text animation.
python generate text motion graphic
Let's go through this step by step:
Download emoji images locally
In order to analyze this kind of emoticon pictures, the first step needs to be downloaded first, but for WeChat's emoticon moving pictures, after testing it is not really possible to download them directly.
Although analyzed by a file monitoring tool, the gif emoji motion picture is stored in theC:\Users\ASUS\Documents\WeChat Files\Your WeChat.ID\FileStorage\CustomEmotion\xx\xxxx
The location, but it is not viewable with the image tool. Analyzing the binary with winhex got theV1MMWX
Such a file header suggests that WeChat encrypts all emojis to some degree. It's possible to decrypt them, but it's too much of a hassle to make such a big deal out of it.
I finally came up with a simple solution later, which is to send this emoji to the public number you have access to log into the backend, and then go to the backend of the public number to download it:
WeChat sends motion pictures that are stored as unique to itselfV1MMWX
Encrypted format, probably in order to use their own original compression algorithm has a greater compression ratio it. That means we want to directly look at the local WeChat stored gif animation, can only develop their own decoder specifically for this WeChat format.
Analyze the motion picture
Below I use the widget Imagine and open it using the animation workshop:
You can see that this motion picture consists of 22 text images with a frame switching time of 20 milliseconds.
Generate single images
Analysis is complete we consider the PIL library to generate a single image, if you have not yet installed the library of the children's shoes, use the following command to install the library:
pip install pillow
Below, I chose to use a blue background for the background. Let's start by drawing the dish name text in the center:
from PIL import Image, ImageFont, ImageDraw text = "Beef brisket casserole with pearl potatoes." size = 320 fontsize = (size-20)//len(text) im = (mode='RGB', size=(size, size), color="lightblue") draw = (im=im) (xy=(10, (size-fontsize*1.5)/2), text=text, fill=0, font=('', size=fontsize)) im
Due to the inconsistency in the number of words in the names of the dishes, automatic text resizing was done to fill the whole picture.
Font I chose Microsoft Black, of course, Microsoft Black also has three sub-fonts, you can check the properties of the font file through the system font installation directory so as to know the corresponding file name of the font:
The text with shadows on the bottom will be a little tricky to generate, my thinking is to draw solid black text first, and then offset the text with black edges white fill upwards by a few units when drawing the text:
def text_border(text, x, y, font, shadowcolor, fillcolor): ((x - 1, y), text, font=font, fill=shadowcolor) ((x + 1, y), text, font=font, fill=shadowcolor) ((x, y - 1), text, font=font, fill=shadowcolor) ((x, y + 1), text, font=font, fill=shadowcolor) ((x - 1, y - 1), text, font=font, fill=shadowcolor) ((x + 1, y - 1), text, font=font, fill=shadowcolor) ((x - 1, y + 1), text, font=font, fill=shadowcolor) ((x + 1, y + 1), text, font=font, fill=shadowcolor) ((x, y), text, font=font, fill=fillcolor) bottomtext = "Don't know what to eat? Screenshot for dinner." bottom_fontsize = 27 bottom_font = ('', size=bottom_fontsize) x, y = (size-bottom_fontsize*len(bottomtext))/2, size-bottom_fontsize*1.2 (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 selected Huawen Amber as the font, personally used to draw the text border method is relatively simple and brutal, if there is a better way, welcome to leave a message to exchange.
Considering that subsequent images sent to WeChat display small, simply compress the pixel size now:
((128, 128)) im
Below we encapsulate the generated code for easy subsequent calls:
from PIL import Image, ImageFont, ImageDraw def text_img(text, bgcolor="lightblue", bottomtext="Don't know what to eat? Screenshot for dinner.", size=360, result_size=(128, 128)): def text_border(text, x, y, font, shadowcolor, fillcolor): ((x - 1, y), text, font=font, fill=shadowcolor) ((x + 1, y), text, font=font, fill=shadowcolor) ((x, y - 1), text, font=font, fill=shadowcolor) ((x, y + 1), text, font=font, fill=shadowcolor) ((x - 1, y - 1), text, font=font, fill=shadowcolor) ((x + 1, y - 1), text, font=font, fill=shadowcolor) ((x - 1, y + 1), text, font=font, fill=shadowcolor) ((x + 1, y + 1), text, font=font, fill=shadowcolor) ((x, y), text, font=font, fill=fillcolor) im = (mode='RGB', size=(size, size), color=bgcolor) draw = (im=im) fontsize = (size-20)//len(text) (xy=(10, (size-fontsize*1.5)/2), text=text, fill=0, font=('', size=fontsize)) bottom_fontsize = (size-20)//len(bottomtext) bottom_font = ('', size=bottom_fontsize) x, y = (size-bottom_fontsize*len(bottomtext))/2, size-bottom_fontsize*1.2 (xy=(x, y), text=bottomtext, fill=0, font=bottom_font) text_border(bottomtext, x, y-4, bottom_font, 0, (255, 255, 255)) (result_size) return im
Test it:
text_img("Fish-flavored eggplant.")
OK, now we'll be able to generate an image for any dish. But where to get the name of the dish? I found a website, consider crawling it below:
Crawling dish data
The URL is:/caipu/
This site turned out to be very simple, a simple xpath to get all the names of the dishes:
Start downloading below:
from lxml import etree import requests req = ("/caipu/") html = () menu = ("//dl[@class='recipe_list']//a/text()") menu = list(set([_.strip(".") for _ in menu])) print(len(menu), menu[:10], menu[-10:])
3744 ['Lotus Root Soup with Spare Ribs', 'taro ball (* dessert)', 'seafood soup', 'Cold Almond Abalone Mushroom', 'casserole', 'Creamy Corn Juice', 'stir-fried string bean', 'eggplant sauce', 'Mango mochi cake', 'steamed bread'] ['steamed eggplant', 'Stir Fried Chicken with Broccoli', 'Old Fashioned Cake', 'Spare ribs and rice cake', 'stir-fried loofah', 'Steamed Spare Ribs with Taro', 'stir-fried pork with fungus', 'Oyster Sauce Oatmeal' , 'Spicy Chicken Nuggets', 'Lotus Leaf Cake']
With these dish names, we can already use them to generate moving pictures. However, in order to still be able to learn how to cook in the future, we can save the names of the dishes, and when we want to learn how to cook it open the page:/?q= dish name to search.
Save the name of the dish:
with open("", "w", encoding="u8") as f: ("Name of the dish\n") for row in menu: (row) ("\n")
Here we start generating the dish name motion picture:
Generate menu name animation
More than 3767 dish names are too many after all, we can take 30 dish names at random to generate moving pictures:
import random gif_list = (menu, k=30) print(gif_list)
['steamed egg', 'cinnamon roll', 'Scrambled Eggs with Cold Melon', 'Baked Sweet Potato with Cheese', 'banana split', 'yogurt mousse', 'egg rice noodle roll, a roll made from sheets of rice flour dough, steamed and stuffed with egg', 'shredded tripe in red oil', 'corn and egg pancake', 'hot and sour tofu soup', 'Stewed Beef Brisket with Turnip', 'Bitter Melon and Spare Ribs Soup', 'Celery with Bean Curd', 'stir-fried potato with tomato', 'Steamed Eggplant with Garlic', 'bean paste bread', 'stir-fried pork with mushrooms', 'stir-fry lotus root ', 'Diced Beef with Black Pepper', 'Pumpkin Pancakes', 'Fried Cucumber', 'Mixed Grain Steamed Buns', 'Peach Hill Skin Mooncake', 'Sautéed Pork with Scallions', 'Stir-Fried Beef', 'Crucian Carp with Bean Paste', 'Braised Bean Curd with Shrimp', 'Vegetarian Dumplings', 'Cold Cucumber', 'Fish Head in Casserole']
PS: It's better to pick your own dish name and write the list to death 😅
import imageio frames = [text_img(text) for text in gif_list] ("", frames, 'GIF', duration=0.02)
Generate results:
Complete code for generating motion pictures based on a list of dish names
import imageio from PIL import Image, ImageFont, ImageDraw def text_img(text, bgcolor="lightblue", bottomtext="Don't know what to eat? Screenshot for dinner.", size=360, result_size=(128, 128)): def text_border(text, x, y, font, shadowcolor, fillcolor): ((x - 1, y), text, font=font, fill=shadowcolor) ((x + 1, y), text, font=font, fill=shadowcolor) ((x, y - 1), text, font=font, fill=shadowcolor) ((x, y + 1), text, font=font, fill=shadowcolor) ((x - 1, y - 1), text, font=font, fill=shadowcolor) ((x + 1, y - 1), text, font=font, fill=shadowcolor) ((x - 1, y + 1), text, font=font, fill=shadowcolor) ((x + 1, y + 1), text, font=font, fill=shadowcolor) ((x, y), text, font=font, fill=fillcolor) im = (mode='RGB', size=(size, size), color=bgcolor) draw = (im=im) fontsize = (size-20)//len(text) (xy=(10, (size-fontsize*1.5)/2), text=text, fill=0, font=('', size=fontsize)) bottom_fontsize = (size-20)//len(bottomtext) bottom_font = ('', size=bottom_fontsize) x, y = (size-bottom_fontsize*len(bottomtext))/2, size-bottom_fontsize*1.2 (xy=(x, y), text=bottomtext, fill=0, font=bottom_font) text_border(bottomtext, x, y-4, bottom_font, 0, (255, 255, 255)) (result_size) return im def save_meau_gif(savename, meau): frames = [text_img(text) for text in meau] (savename, frames, 'GIF', duration=0.02)
Example of use:
meau = [ "Glutinous Rice Chicken in Lotus Leaf.", "Roast Lamb", "Black Pepper Steak.", "Home-style chicken.", "Garlic bean curd.", "Beef with onions.", "Scrambled eggs with loofah.", "Scrambled eggs with mushrooms.", "Tofu with chicken.", "Hibiscus Vegetable Soup.", "Fried zucchini.", "Eggplant and beans.", "Beef with slippery eggs.", "Mushroom and bok choy.", "The Earth's Three Freshmen.", "Roasted apricot mushrooms in sauce.", "Chicken Wings with Bean Curd", "Sliced lotus root in vinegar.", "Coconut Chicken Stew.", "Braised tofu with shiitake mushrooms.", "Curry Chicken Legs and Rice.", "Chicken mashed potatoes.", "Eggplant and potato stew.", "Fried Udon Noodles", "Curry Potato Chicken.", "Baby vegetables in soup.", "Steamed eggplant with garlic.", "Baked Sweet Potato with Cheese.", "Chestnut cassoulet.", "Loofah and tofu soup.", ] save_meau_gif("", meau)
Generate results:
Since our moving pictures have been generated! Whenever you don't know what to eat, you can take a screenshot and play with it~🐶!
😆 Have fun choosing your meals~!
Other operations of the PIL operation gif
In fact, with specialized motion picture processing software can be operated, the following is still added, python operation API record:
Gif Splitting
For example, let's break down this chart:
from PIL import Image, ImageSequence img = ('Kung Fu Bear.gif') for i, f in enumerate((img), 1): (f'broken up inseparate items/Kung Fu Bear-{i}.png')
Split results:
GIF Rewind
Let's rewind the above motion picture a bit below:
from PIL import Image, ImageSequence import imageio im = ('Kung Fu Bear.gif') sequence = [() for f in (im)] () # Put the frames in the list in reverse order with the reverse() function sequence[0].save('Rewind Kung Fu Bear.gif', save_all=True, append_images=sequence[1:])
To this article on Python to generate screenshots of selected meals GIF animation is introduced to this article, more related Python to generate screenshots of GIF animation content, please search for my previous articles or continue to browse the following related articles I hope you will support me in the future more!