Skip to content
This repository has been archived by the owner on Jul 22, 2022. It is now read-only.

Commit

Permalink
Release 2.1
Browse files Browse the repository at this point in the history
  • Loading branch information
kubinka0505 committed Mar 1, 2021
0 parents commit 567d4bb
Show file tree
Hide file tree
Showing 14 changed files with 905 additions and 0 deletions.
Binary file added Captions/Example_(Multiline)_RNAzRzO2.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Captions/Example_7Qg2EOMh.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 18 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
## 0.1
Alpha development.

## 0.3
Re-write.

## 0.4
Initial release.

## 2.0
Bug-fixing.
Added GIF support.
Changed fonts.

## 2.1
Modified several functions.
Optimized creation time (ffmpeg >= 4.0.0)
Added font.
15 changes: 15 additions & 0 deletions Config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"Image": {
"URL": "",
"Max_Width": 300,
"Crop": false
},
"Font": {
"Type": 2
},
"Settings": {
"Speed": 28
},
"Text": "",
"Wrap": 14
}
Binary file added Fonts/Futura BT Pro Condensed Extra Black.ttf
Binary file not shown.
Binary file added Fonts/Futura Condensed Extra Bold.otf
Binary file not shown.
Binary file added Fonts/Roboto Black.otf
Binary file not shown.
674 changes: 674 additions & 0 deletions License.txt

Large diffs are not rendered by default.

56 changes: 56 additions & 0 deletions ReadMe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<a href="https://ifunny.co/"><img src="https://cdn.discordapp.com/attachments/312993895887929355/714526409468412004/iFunny_Captions.png"></img></a>
<center> <a href="https://www.python.org/downloads/release/python-375/"><img alt="Python 3.7.5" src="https://img.shields.io/badge/Python-3.7.5-brightgreen?style=for-the-badge&link=https://www.python.org/&https://www.python.org/downloads/&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAMAAAAMCGV4AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAABVlBMVEUAAAA5e7Q3ebA3eK43dak3dKY2dKI5gLg4ebA1eq83d6s3caI8aaU5e7M3eK42eKs4cJsAgIA4eK85d7A2dqs2dKk2dKc3cqR2koD/10v/20k2ebU4ebDRvlz/1UX/00Q4erDbxFf/0UA2eK42aZb/1ET/zz83d6s3cqQ6c6GZpXuprXCpq2y8s2P900X/00M3cKL/3lH/zDs2dKZVg5L/yjk3c6U3caJihoz/yTn/xzg7dp03bpuqqnH/0kP/0kD/0D7/zjz/yzz/wzz//wD/2E7/zj7/yDf/41X/1Ub/zj3/zTz/yjn/yDf/1Ub/00L/0ED/zj3/zDv/yTr/xzg3d6s3dak3dKc3cqQ3caI3cJ82bp03eK42bZr/10c2a5j/1UX/00P/0UE3dKb/zz//zT3/3U7/20z/2Ur/10j/1Ub/zj3/zDv/00T/0D//0kL/1ET///8twZG5AAAAVXRSTlMAVcbw67tCEuhD9/YRG/ukKQIgLYiIiL44MxUm3HX1QKxwwuqzlfj6/oVudnZvhf2fq/aydbYz7njbKQ0zLb13d3ciEQEaoSoJ7vxN4Rw3suj27MNWkzfuJAAAAAFiS0dEca8HXOIAAAAHdElNRQfkBQcLNhpsHcMTAAAAuklEQVQI12NgAAJGJuZQFlY2Bihg5+DkCguP4OaB8nn5+IHcyCgBME9QSFhEVEw8MipaQlKKgUFaJiYULBsdKxsnJ8+gAOfGKyYkKjEow7kqqolJagzqYckamlraOjq6evpJKakMLMkRBoZp6RmZWYlArhGDcUSkCYybnWPKYGYeZQHi5iblZedYWjEwWNvYArl29g6OTs4uYBe5AmXz89yM3KHu9fAsyM/z8vbxhXnIzz8gMCg4BMQEAKy7MbtksegJAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDIwLTA1LTA3VDExOjU0OjI2KzAwOjAw1j8VsQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAyMC0wNS0wN1QxMTo1NDoyNiswMDowMKdirQ0AAAAASUVORK5CYII="></center></a>

## Description
I was very unsatisfied that there was only a mobile app caption tool so I've decided to create one.

## Completed & Planned Features
- [x] Completed
- [ ] In Development
---
- [x] PNG Captions
- [x] GIF Captions
- [ ] Offline support
- [x] <code>Giphy</code> URLs support*
- [x] <code>Tenor</code> URLs support*
- [x] Optimization
- [ ] GIF size reduction
- [ ] Transparent GIF support
- [ ] *[Program Showcase]()*

* - Beta

## Requirements
- <code>Python 3.5</code> +
- <code>PIL</code>
- <code>requests</code>
- <code>textwrap</code>
- **<code>ffmpeg static executable binary >= 4.0.0</code>**
- [Windows](https://www.videohelp.com/software/ffmpeg/old-versions "Windows: win") (Move <code>ffmpeg.exe</code> from <code>bin</code> to main folder)
- [Linux](https://www.johnvansickle.com/ffmpeg/old-releases/)

## Usage
1. Modify the parameters in the <code>Config.json</code>:
- <code>Image</code> :
- <code>URL</code> : **Direct** media URL. __[Can be any Image/Video format that <code>ffmpeg</code> supports](https://en.wikipedia.org/wiki/FFmpeg#Supported_formats "Supported ffmpeg formats")__.
- <code>Max_Width</code> : Maximum single frame width. Height is relatively scaled, same as font size. *Formula: Max Width ÷ 10*. **Default is 300**.
- <code>Crop</code> : Crops transparent pixels around the **__every frame__**. **Default is <code>false</code>**.
- <code>Font</code> :
- <code>Type</code> : Defines font style used as caption text. **Default is <code>2</code>**.
- <code>1</code> : <code>Roboto Black</code> (otf)
- <code>2</code> : <code>Futura Condensed Extra Bold</code> (otf)
- <code>3</code> : <code>Futura BT Pro Condensed Extra Black</code> (ttf)*
- <code>Settings</code> :
- <code>Speed</code> : Single frame display time. (in milliseconds). **Default is 28**.
- <code>Text</code> : Image caption text.
- <code>Wrap</code> : Text-wrap, used to break the words. **Default is 14**.
2. Open <code>Run.sh</code>
3. ...or go to Your command prompt and type following:
```bash
git clone https://github.com/kubinka0505/iFunny-Captions
cd iFunny-Captions
py __init__.py
```
4. Share Your image from <code>Captions</code> directory.

* - TrueType fonts (ttf) are poorly resized and will look bad on small images.
1 change: 1 addition & 0 deletions Run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
python __init__.py
22 changes: 22 additions & 0 deletions Scripts/Caption.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
Image_Base = Image.new("RGBA", (2000, 1500), (255,) * 3) # White
Image_Trans = Image.new("RGBA", (2000, 1500), (255, 255, 255, 0)) # Transparent

Draw = ImageDraw.Draw(Image_Trans)

if Config()["Font"]["Type"] == 1:
__Path = "{0}\\Fonts\\Roboto Black.otf".format(os.getcwd())
if Config()["Font"]["Type"] == 2:
__Path = "{0}\\Fonts\\Futura Condensed Extra Bold.otf".format(os.getcwd())
if Config()["Font"]["Type"] == 3:
__Path = "{0}\\Fonts\\Futura BT Pro Condensed Extra Black.ttf".format(os.getcwd())

if system() != "Windows":
__Path = __Path.replace("\\", "/")

Font = ImageFont.truetype(__Path, Config()["Image"]["Max_Width"] // 10)
Draw.text((0,) * 2, text = "\n".join(wrap(Config()["Text"], Config()["Wrap"])), fill = (0,) * 3, font = Font, align = "center")

Image_Trans = Image_Trans.crop(Image_Trans.getbbox()) # Cropped Text

Pasted = Image.new("RGBA", (Config()["Image"]["Max_Width"], Image_Trans.size[1] + Config()["Image"]["Max_Width"] // 10 * 2), (255,) * 3)
Pasted = Trans_Paste(Pasted, Image_Trans)
10 changes: 10 additions & 0 deletions Scripts/Gifer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Caption = Image.open(Frame)
if Config()["Image"]["Crop"] == True: Caption = Caption.crop(Caption.getbbox())

Width = Pasted.size[0]
Percentage = (Width / float(Caption.size[0]))
Height_Size = int((float(Caption.size[1]) * float(Percentage)))
Caption = Caption.resize((Width, Height_Size), Image.LANCZOS)

Captionized = Margin(Caption, Pasted.size[1])
Captionized.paste(Pasted)
46 changes: 46 additions & 0 deletions Scripts/Utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
def Trans_Paste(Background: Image, Foreground: Image) -> Image:
"""Pasting transparent `Foreground` to `Background`."""
FRGRND_TRNS = Image.new("RGBA", Background.size)
#---#
Background_Width, Background_Height = Background.size
Foreground_Width, Foreground_Height = Foreground.size
#---#
FRGRND_TRNS.paste(Foreground, ((Background_Width - Foreground_Width) // 2, (Background_Height - Foreground_Height) // 2), mask = Foreground)
#---#
IMG_RET = Image.alpha_composite(Background, FRGRND_TRNS)
return IMG_RET

def __Get_Service(URL: str):
"""Converting raw URL to direct Image.
Supported Services:
- Tenor
- Giphy"""
if "tenor.com/view" in URL:
return get(URL).text.split('contentUrl')[1].split("content")[0][2:].split('"')[1].replace("\\u002F", "/")
if "giphy.com/gifs" in URL:
return "https://media"+str(get(URL).text).split("https://media")[2].split('"')[0]
else:
return URL

def Margin(Picture: Image, Top: int, Color: ImageColor = "#FFF") -> Image:
"""Adds margin to an `Picture`."""
Width, Height = Picture.size
Height = Height + Top + 0
#---#
Field = Image.new(Picture.mode, (Width, Height), Color)
Field.paste(Picture, (0, Top))
return Field

def Config():
"""Loading values from JSON file."""
__Path = "{0}\Config.json"
#---#
if system() != "Windows":
__Path = __Path.replace("\\", "/")
#---#
return load(open(__Path.format(os.getcwd()), encoding = "utf-8"))

def Random_String(Length: int = 16):
"""Random string creation used in saving files."""
return "".join(choice(printable[0:62]) for String in range(Length))
63 changes: 63 additions & 0 deletions __init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import os
from json import load
from requests import get
from random import choice
from textwrap import wrap
from platform import system
from string import printable
from PIL import Image, ImageDraw, ImageFont, ImageColor

__author__ = "kubinka0505"
__copyright__ = __author__
__credits__ = [__author__, "SuperCuber"]
__version__ = "2.1"
__date__ = "14.11.2020"
__status__ = "Development"
__license__ = "GPL V3"

__FORMAT = "png"
print("Setting up utils...")
exec(open("{0}{1}Scripts{1}Utils.py".format(os.getcwd(), "\\" if system == "Windows" else "/")).read())

print("Converting URL Image to Frames... This can take a while.")
os.system('ffmpeg.exe -i {0} Frame_%06d.{1} -hide_banner -loglevel panic'.format(__Get_Service(Config()["Image"]["URL"]), __FORMAT))
Frames = [File for File in os.listdir(os.getcwd()) if File.endswith(__FORMAT)]
Frames.sort(key = str)

print("Making {0}...".format("PNG" if len(Frames) == 1 else "GIF"))
for Frame in Frames:
Caption = Image.open(Frame)
#---#
exec(open("{0}{1}Scripts{1}Caption.py".format(os.getcwd(), "\\" if system == "Windows" else "/")).read())
exec(open("{0}{1}Scripts{1}Gifer.py".format(os.getcwd(), "\\" if system == "Windows" else "/")).read())
#---#
Captionized.save(Frame)

GIF = Image.open(Frames[0])
print("Saving {0}...".format("PNG" if len(Frames) == 1 else "GIF"))
GIF.save("{0}{1}Captions{1}{2}_{3}.{4}".format(
os.getcwd(),
"\\" if system == "Windows" else "/",
Config()["Text"].\
replace(" ", "_").\
replace("\\", "_").\
replace("/", "_").\
replace(":", "_").\
replace("*", "_").\
replace("?", "_").\
replace("<", "_").\
replace(">", "_").\
replace("|", "_").\
encode().decode("utf-8", errors = "strict"),
Random_String(8),
"png" if len(Frames) == 1 else "gif"
),
save_all = True,
loop = 0,
append_images = [Image.open(Frame) for Frame in Frames[1:]],
duration = Config()["Settings"]["Speed"],
)

print("Removing {0}...".format("Image" if len(Frames) == 1 else "Frames"))
[os.remove("{0}{1}{2}".format(os.getcwd(), "\\" if system == "Windows" else "/" , Frame)) for Frame in os.listdir(os.getcwd()) if Frame.endswith(__FORMAT)]
print("Done!")

0 comments on commit 567d4bb

Please sign in to comment.