Skip to content

Commit

Permalink
Refactored the code that renders device art images.
Browse files Browse the repository at this point in the history
  • Loading branch information
nathan-osman committed Sep 26, 2014
1 parent 76a0a88 commit cad94bb
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 54 deletions.
9 changes: 7 additions & 2 deletions twobuntu/touch/forms.py
@@ -1,10 +1,15 @@
from django import forms

from twobuntu.touch.generator import TEMPLATES


class DeviceArtForm(forms.Form):
"""
Form for uploading an app screenshot.
Form for uploading an app image.
"""

template = forms.TypedChoiceField(
choices=[(i, t['title']) for i, t in enumerate(TEMPLATES)],
coerce=int,
)
image = forms.ImageField()
add_panel = forms.BooleanField(required=False, label='Add the Unity panel to the picture')
50 changes: 50 additions & 0 deletions twobuntu/touch/generator.py
@@ -0,0 +1,50 @@
from io import BytesIO
from math import ceil

from django.contrib.staticfiles import finders
from PIL import Image

# Coordinates for rendering the picture with and without the Unity panel
# Each item in the array represents a layer for the generator to render
# The format of the tuple is (filename, dest_x, dest_y, dest_w, dest_h)
TEMPLATES = [
{
'title': 'Meizu MX3 with Unity Panel',
'dimensions': (1346, 2313),
'layers': [
(None, 131, 286, 1080, 1727),
('panel.png', 131, 213, 1080, 73),
('mx3.png', 0, 0, 1346, 2313),
],
},
{
'title': 'Meizu MX3 without Unity Panel',
'dimensions': (1346, 2313),
'layers': [
(None, 131, 213, 1080, 1800),
('mx3.png', 0, 0, 1346, 2313),
],
},
]


def generate_device_art(template, image):
"""
Combine the layers for the template into a final image.
"""
# Create the final image upon which everything will be rendered
t = TEMPLATES[template]
o = Image.new('RGBA', t['dimensions'])
# For each of the layers, resize and crop according to the definition, and blend
for l in t['layers']:
i = Image.open(finders.find('img/touch/%s' % l[0]) if l[0] else image)
w, h = i.size
i = i.crop((0, 0, w, int(ceil(float(l[4]) / float(l[3]) * w))))
i = i.resize((l[3], l[4]), Image.ANTIALIAS)
c = Image.new('RGBA', t['dimensions'])
c.paste(i, (l[1], l[2]))
o = Image.alpha_composite(o, c)
# Return a file-like object representing the rendered picture
response = BytesIO()
o.save(response, format='PNG')
return response.getvalue()
Binary file removed twobuntu/touch/static/img/touch-preview.png
Binary file not shown.
Binary file added twobuntu/touch/static/img/touch/mx3-preview.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
File renamed without changes
28 changes: 16 additions & 12 deletions twobuntu/touch/templates/touch/generator.html
Expand Up @@ -4,7 +4,7 @@
{% block content %}
<div class="row">
<div class="col-sm-4 text-center">
<img src="{% static "img/touch-preview.png" %}">
<img src="{% static "img/touch/mx3-preview.png" %}">
</div>
<div class="col-sm-8">
<h2>Ubuntu Touch Device Art Generator</h2>
Expand All @@ -25,17 +25,21 @@ <h2>Ubuntu Touch Device Art Generator</h2>
Our tool will automatically resize and crop the image if necessary.
</p>
<hr>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{% for field in form %}
{% include "fragments/field.html" %}
{% endfor %}
<br>
<button type="submit" class="btn btn-xl btn-primary">
<span class="fa fa-cogs"></span>
Generate
</button>
</form>
<div class="row">
<div class="col-md-6">
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{% for field in form %}
{% include "fragments/field.html" %}
{% endfor %}
<br>
<button type="submit" class="btn btn-xl btn-primary">
<span class="fa fa-cogs"></span>
Generate
</button>
</form>
</div>
</div>
</div>
</div>
{% endblock %}
43 changes: 3 additions & 40 deletions twobuntu/touch/views.py
@@ -1,55 +1,18 @@
from django.contrib.staticfiles import finders
from django.http import HttpResponse
from django.shortcuts import render
from io import BytesIO
from PIL import Image

from twobuntu.touch.forms import DeviceArtForm

# Dimensions used for calculations
TEMPLATE_W = 1346
TEMPLATE_H = 2313
SCREENSHOT_X = 131
SCREENSHOT_Y = 213
SCREENSHOT_W = 1080
SCREENSHOT_H = 1800
PANEL_H = 73


def generate_device_art(screenshot, add_panel=True):
"""
Load the template & overlay and combine them with the screenshot.
"""
response = BytesIO()
# Open the two images to be combined
s = Image.open(screenshot)
t = Image.open(finders.find('img/touch-frame.png'))
# Crop and resize the screenshot
w, h = s.size
s = s.crop((0, 0, w, int(float(SCREENSHOT_H) / float(SCREENSHOT_W) * w)))
s = s.resize((SCREENSHOT_W, SCREENSHOT_H), Image.ANTIALIAS)
# Create the output image for pasting the screenshot onto
o = Image.new('RGBA', (TEMPLATE_W, TEMPLATE_H))
# Add the panel if requested
if add_panel:
p = Image.open(finders.find('img/touch-panel.png'))
o.paste(p, (SCREENSHOT_X, SCREENSHOT_Y))
o.paste(s, (SCREENSHOT_X, SCREENSHOT_Y + PANEL_H))
else:
o.paste(s, (SCREENSHOT_X, SCREENSHOT_Y))
# Blend the frame above and save the image to the BytesIO
Image.alpha_composite(o, t).save(response, format='PNG')
return response.getvalue()
from twobuntu.touch.generator import generate_device_art


def generator(request):
"""
Generate a picture of a device with a screenshot.
Generate a picture of a device with a user-supplied image.
"""
if request.method == 'POST':
form = DeviceArtForm(data=request.POST, files=request.FILES)
if form.is_valid():
image = generate_device_art(request.FILES['image'], form.cleaned_data['add_panel'])
image = generate_device_art(form.cleaned_data['template'], request.FILES['image'])
response = HttpResponse(image, content_type='image/png')
response['Content-Disposition'] = 'attachment; filename="ubuntu-touch-device-art.png"'
response['Content-Length'] = len(image)
Expand Down

0 comments on commit cad94bb

Please sign in to comment.