@@ -0,0 +1,19 @@ |
||
| 1 |
+# -*- coding: utf-8 -*- |
|
| 2 |
+from __future__ import unicode_literals |
|
| 3 |
+ |
|
| 4 |
+from django.db import models, migrations |
|
| 5 |
+ |
|
| 6 |
+ |
|
| 7 |
+class Migration(migrations.Migration): |
|
| 8 |
+ |
|
| 9 |
+ dependencies = [ |
|
| 10 |
+ ('account', '0003_auto_20151202_2313'),
|
|
| 11 |
+ ] |
|
| 12 |
+ |
|
| 13 |
+ operations = [ |
|
| 14 |
+ migrations.AlterField( |
|
| 15 |
+ model_name='lensmaninfo', |
|
| 16 |
+ name='lensman_id', |
|
| 17 |
+ field=models.CharField(null=True, max_length=255, blank=True, help_text='\u6444\u5f71\u5e08\u552f\u4e00\u6807\u8bc6', unique=True, verbose_name='lensman_id', db_index=True), |
|
| 18 |
+ ), |
|
| 19 |
+ ] |
@@ -150,6 +150,9 @@ REST_FRAMEWORK = {
|
||
| 150 | 150 |
# 唯一标识设置 |
| 151 | 151 |
CURTAIL_UUID_LENGTH = 7 |
| 152 | 152 |
|
| 153 |
+# 水印设置 |
|
| 154 |
+WATERMARK_LOGO = os.path.join(PROJ_DIR, 'static/pai2/img/paiai_96_96.png').replace('\\', '/')
|
|
| 155 |
+ |
|
| 153 | 156 |
# 域名设置 |
| 154 | 157 |
DOMAIN = 'http://xfoto.com.cn' |
| 155 | 158 |
|
@@ -11,7 +11,7 @@ class UUIDInfoAdmin(admin.ModelAdmin): |
||
| 11 | 11 |
|
| 12 | 12 |
|
| 13 | 13 |
class PhotosInfoAdmin(admin.ModelAdmin): |
| 14 |
- list_display = ('lensman_id', 'session_id', 'photo_id', 'photo_name', 'photo_path', 'status', 'created_at', 'updated_at')
|
|
| 14 |
+ list_display = ('lensman_id', 'session_id', 'photo_id', 'p_photo_path', 'status', 'created_at', 'updated_at')
|
|
| 15 | 15 |
list_filter = ('lensman_id', 'status')
|
| 16 | 16 |
|
| 17 | 17 |
|
@@ -0,0 +1,42 @@ |
||
| 1 |
+# -*- coding: utf-8 -*- |
|
| 2 |
+from __future__ import unicode_literals |
|
| 3 |
+ |
|
| 4 |
+from django.db import models, migrations |
|
| 5 |
+ |
|
| 6 |
+ |
|
| 7 |
+class Migration(migrations.Migration): |
|
| 8 |
+ |
|
| 9 |
+ dependencies = [ |
|
| 10 |
+ ('photo', '0004_photosinfo_photo_name'),
|
|
| 11 |
+ ] |
|
| 12 |
+ |
|
| 13 |
+ operations = [ |
|
| 14 |
+ migrations.RemoveField( |
|
| 15 |
+ model_name='photosinfo', |
|
| 16 |
+ name='photo_name', |
|
| 17 |
+ ), |
|
| 18 |
+ migrations.RemoveField( |
|
| 19 |
+ model_name='photosinfo', |
|
| 20 |
+ name='photo_path', |
|
| 21 |
+ ), |
|
| 22 |
+ migrations.AddField( |
|
| 23 |
+ model_name='photosinfo', |
|
| 24 |
+ name='l_photo_path', |
|
| 25 |
+ field=models.CharField(help_text='\u7167\u7247\u5b58\u653e\u8def\u5f84', max_length=255, null=True, verbose_name='l_photo_path', blank=True), |
|
| 26 |
+ ), |
|
| 27 |
+ migrations.AddField( |
|
| 28 |
+ model_name='photosinfo', |
|
| 29 |
+ name='m_photo_path', |
|
| 30 |
+ field=models.CharField(help_text='\u7167\u7247\u5b58\u653e\u8def\u5f84', max_length=255, null=True, verbose_name='m_photo_path', blank=True), |
|
| 31 |
+ ), |
|
| 32 |
+ migrations.AddField( |
|
| 33 |
+ model_name='photosinfo', |
|
| 34 |
+ name='p_photo_path', |
|
| 35 |
+ field=models.CharField(help_text='\u7167\u7247\u5b58\u653e\u8def\u5f84', max_length=255, null=True, verbose_name='p_photo_path', blank=True), |
|
| 36 |
+ ), |
|
| 37 |
+ migrations.AddField( |
|
| 38 |
+ model_name='photosinfo', |
|
| 39 |
+ name='r_photo_path', |
|
| 40 |
+ field=models.CharField(help_text='\u7167\u7247\u5b58\u653e\u8def\u5f84', max_length=255, null=True, verbose_name='r_photo_path', blank=True), |
|
| 41 |
+ ), |
|
| 42 |
+ ] |
@@ -32,8 +32,10 @@ class PhotosInfo(CreateUpdateMixin): |
||
| 32 | 32 |
lensman_id = models.CharField(_(u'lensman_id'), max_length=255, blank=True, null=True, help_text=u'摄影师唯一标识', db_index=True) |
| 33 | 33 |
session_id = models.CharField(_(u'session_id'), max_length=255, blank=True, null=True, help_text=u'照片组唯一标识', db_index=True) |
| 34 | 34 |
photo_id = models.CharField(_(u'photo_id'), max_length=255, blank=True, null=True, help_text=u'照片唯一标识', db_index=True, unique=True) |
| 35 |
- photo_name = models.CharField(_(u'photo_name'), max_length=255, blank=True, null=True, help_text=u'照片存放名称') |
|
| 36 |
- photo_path = models.CharField(_(u'photo_path'), max_length=255, blank=True, null=True, help_text=u'照片存放路径') |
|
| 35 |
+ p_photo_path = models.CharField(_(u'p_photo_path'), max_length=255, blank=True, null=True, help_text=u'照片存放路径') |
|
| 36 |
+ m_photo_path = models.CharField(_(u'm_photo_path'), max_length=255, blank=True, null=True, help_text=u'照片存放路径') |
|
| 37 |
+ l_photo_path = models.CharField(_(u'l_photo_path'), max_length=255, blank=True, null=True, help_text=u'照片存放路径') |
|
| 38 |
+ r_photo_path = models.CharField(_(u'r_photo_path'), max_length=255, blank=True, null=True, help_text=u'照片存放路径') |
|
| 37 | 39 |
|
| 38 | 40 |
class Meta: |
| 39 | 41 |
verbose_name = _('photosinfo')
|
@@ -46,9 +48,20 @@ class PhotosInfo(CreateUpdateMixin): |
||
| 46 | 48 |
return u'{0.pk}'.format(self)
|
| 47 | 49 |
|
| 48 | 50 |
@property |
| 49 |
- def photo_url(self): |
|
| 50 |
- return u'{0}/media/{1}'.format(settings.DOMAIN, self.photo_path) if self.photo_path else ''
|
|
| 51 |
- # return u'{0}/p/{1}'.format(settings.DOMAIN, self.photo_name) if self.photo_name else ''
|
|
| 51 |
+ def p_photo_url(self): |
|
| 52 |
+ return u'{0}/media/{1}'.format(settings.DOMAIN, self.p_photo_path) if self.p_photo_path else ''
|
|
| 53 |
+ |
|
| 54 |
+ @property |
|
| 55 |
+ def m_photo_url(self): |
|
| 56 |
+ return u'{0}/media/{1}'.format(settings.DOMAIN, self.m_photo_path) if self.m_photo_path else ''
|
|
| 57 |
+ |
|
| 58 |
+ @property |
|
| 59 |
+ def l_photo_url(self): |
|
| 60 |
+ return u'{0}/media/{1}'.format(settings.DOMAIN, self.l_photo_path) if self.l_photo_path else ''
|
|
| 61 |
+ |
|
| 62 |
+ @property |
|
| 63 |
+ def r_photo_url(self): |
|
| 64 |
+ return u'{0}/media/{1}'.format(settings.DOMAIN, self.r_photo_path) if self.r_photo_path else ''
|
|
| 52 | 65 |
|
| 53 | 66 |
def _data(self): |
| 54 | 67 |
return {
|
@@ -56,7 +69,6 @@ class PhotosInfo(CreateUpdateMixin): |
||
| 56 | 69 |
'user': self.lensman_id, |
| 57 | 70 |
'session': self.session_id, |
| 58 | 71 |
'photo': self.photo_id, |
| 59 |
- # 'photo_url': self.photo_url, |
|
| 60 | 72 |
} |
| 61 | 73 |
|
| 62 | 74 |
data = property(_data) |
@@ -6,7 +6,7 @@ |
||
| 6 | 6 |
</head> |
| 7 | 7 |
<body> |
| 8 | 8 |
{% for photo in photos %}
|
| 9 |
- <div><img src="{{ photo.photo_url }}"></div>
|
|
| 9 |
+ <div><img src="{{ photo.p_photo_url }}"></div>
|
|
| 10 | 10 |
{% endfor %}
|
| 11 | 11 |
</body> |
| 12 | 12 |
</html> |
@@ -1,5 +1,6 @@ |
||
| 1 | 1 |
# -*- coding: utf-8 -*- |
| 2 | 2 |
|
| 3 |
+from django.conf import settings |
|
| 3 | 4 |
from django.core.files.storage import default_storage |
| 4 | 5 |
from django.db import transaction |
| 5 | 6 |
from django.http import JsonResponse |
@@ -12,6 +13,7 @@ from photo.models import UUIDInfo, PhotosInfo |
||
| 12 | 13 |
from photo.serializers import PhotosInfoSerializer |
| 13 | 14 |
|
| 14 | 15 |
from utils.uuid_utils import curtailUUID |
| 16 |
+from utils.watermark_utils import watermark_wrap |
|
| 15 | 17 |
|
| 16 | 18 |
import os |
| 17 | 19 |
|
@@ -83,20 +85,25 @@ def upload_photo(request): |
||
| 83 | 85 |
photo_id = curtailUUID(PhotosInfo, 'photo_id') |
| 84 | 86 |
|
| 85 | 87 |
_, extension = os.path.splitext(photo.name) |
| 86 |
- # photo_path = 'photo/{0}/{1}/{2}{3}'.format(lensman_id, session_id, photo_id, extension)
|
|
| 87 |
- photo_name = '{0}{1}'.format(photo_id, extension)
|
|
| 88 |
- photo_path = 'photo/{0}'.format(photo_name)
|
|
| 88 |
+ m_photo_path = 'photo/{photo_id}_m{extension}'.format(photo_id=photo_id, extension=extension)
|
|
| 89 | 89 |
|
| 90 |
- if default_storage.exists(photo_path): |
|
| 91 |
- default_storage.delete(photo_path) |
|
| 92 |
- default_storage.save(photo_path, photo) |
|
| 90 |
+ if default_storage.exists(m_photo_path): |
|
| 91 |
+ default_storage.delete(m_photo_path) |
|
| 92 |
+ default_storage.save(m_photo_path, photo) |
|
| 93 |
+ |
|
| 94 |
+ p_photo_path = 'photo/{photo_id}_p{extension}'.format(photo_id=photo_id, extension=extension)
|
|
| 95 |
+ watermark_wrap( |
|
| 96 |
+ os.path.join(settings.MEDIA_ROOT, m_photo_path).replace('\\', '/'),
|
|
| 97 |
+ settings.WATERMARK_LOGO, |
|
| 98 |
+ os.path.join(settings.MEDIA_ROOT, p_photo_path).replace('\\', '/')
|
|
| 99 |
+ ) |
|
| 93 | 100 |
|
| 94 | 101 |
photo, created = PhotosInfo.objects.get_or_create( |
| 95 | 102 |
lensman_id=lensman_id, |
| 96 | 103 |
session_id=session_id, |
| 97 | 104 |
photo_id=photo_id, |
| 98 |
- photo_name=photo_name, |
|
| 99 |
- photo_path=photo_path |
|
| 105 |
+ p_photo_path=p_photo_path, |
|
| 106 |
+ m_photo_path=m_photo_path, |
|
| 100 | 107 |
) |
| 101 | 108 |
|
| 102 | 109 |
return JsonResponse({
|
@@ -113,22 +120,22 @@ def session_detail(request, session): |
||
| 113 | 120 |
|
| 114 | 121 |
def photo_standard(request, photo): |
| 115 | 122 |
photo = PhotosInfo.objects.get(photo_id=photo) |
| 116 |
- return render(request, 'photo/photo_detail.html', {'photo_url': photo.photo_url})
|
|
| 123 |
+ return render(request, 'photo/photo_detail.html', {'photo_url': photo.p_photo_url})
|
|
| 117 | 124 |
|
| 118 | 125 |
|
| 119 | 126 |
def photo_medium(request, photo): |
| 120 | 127 |
photo = PhotosInfo.objects.get(photo_id=photo) |
| 121 |
- return render(request, 'photo/photo_detail.html', {'photo_url': photo.photo_url})
|
|
| 128 |
+ return render(request, 'photo/photo_detail.html', {'photo_url': photo.m_photo_url})
|
|
| 122 | 129 |
|
| 123 | 130 |
|
| 124 | 131 |
def photo_large(request, photo): |
| 125 | 132 |
photo = PhotosInfo.objects.get(photo_id=photo) |
| 126 |
- return render(request, 'photo/photo_detail.html', {'photo_url': photo.photo_url})
|
|
| 133 |
+ return render(request, 'photo/photo_detail.html', {'photo_url': photo.l_photo_url})
|
|
| 127 | 134 |
|
| 128 | 135 |
|
| 129 | 136 |
def photo_raw(request, photo): |
| 130 | 137 |
photo = PhotosInfo.objects.get(photo_id=photo) |
| 131 |
- return render(request, 'photo/photo_detail.html', {'photo_url': photo.photo_url})
|
|
| 138 |
+ return render(request, 'photo/photo_detail.html', {'photo_url': photo.r_photo_url})
|
|
| 132 | 139 |
|
| 133 | 140 |
|
| 134 | 141 |
class PhotoInfoViewSet(viewsets.ModelViewSet): |
@@ -0,0 +1,62 @@ |
||
| 1 |
+# -*- coding: utf-8 -*- |
|
| 2 |
+ |
|
| 3 |
+try: |
|
| 4 |
+ import Image |
|
| 5 |
+ import ImageEnhance |
|
| 6 |
+except ImportError: |
|
| 7 |
+ from PIL import Image, ImageEnhance |
|
| 8 |
+ |
|
| 9 |
+ |
|
| 10 |
+def reduce_opacity(im, opacity): |
|
| 11 |
+ """Returns an image with reduced opacity.""" |
|
| 12 |
+ assert 0 <= opacity <= 1 |
|
| 13 |
+ im = im.convert('RGBA') if im.mode != 'RGBA' else im.copy()
|
|
| 14 |
+ alpha = im.split()[3] |
|
| 15 |
+ alpha = ImageEnhance.Brightness(alpha).enhance(opacity) |
|
| 16 |
+ im.putalpha(alpha) |
|
| 17 |
+ return im |
|
| 18 |
+ |
|
| 19 |
+ |
|
| 20 |
+def watermark(im, mark, position, opacity=1): |
|
| 21 |
+ """Adds a watermark to an image.""" |
|
| 22 |
+ if opacity < 1: |
|
| 23 |
+ mark = reduce_opacity(mark, opacity) |
|
| 24 |
+ if im.mode != 'RGBA': |
|
| 25 |
+ im = im.convert('RGBA')
|
|
| 26 |
+ # create a transparent layer the size of the image and draw the |
|
| 27 |
+ # watermark in that layer. |
|
| 28 |
+ layer = Image.new('RGBA', im.size, (0, 0, 0, 0))
|
|
| 29 |
+ if position == 'tile': |
|
| 30 |
+ for y in range(0, im.size[1], mark.size[1]): |
|
| 31 |
+ for x in range(0, im.size[0], mark.size[0]): |
|
| 32 |
+ layer.paste(mark, (x, y)) |
|
| 33 |
+ elif position == 'scale': |
|
| 34 |
+ # scale, but preserve the aspect ratio |
|
| 35 |
+ ratio = min( |
|
| 36 |
+ float(im.size[0]) / mark.size[0], float(im.size[1]) / mark.size[1]) |
|
| 37 |
+ w = int(mark.size[0] * ratio) |
|
| 38 |
+ h = int(mark.size[1] * ratio) |
|
| 39 |
+ mark = mark.resize((w, h)) |
|
| 40 |
+ layer.paste(mark, ((im.size[0] - w) / 2, (im.size[1] - h) / 2)) |
|
| 41 |
+ else: |
|
| 42 |
+ layer.paste(mark, position) |
|
| 43 |
+ # composite the watermark with the layer |
|
| 44 |
+ return Image.composite(layer, im, layer) |
|
| 45 |
+ |
|
| 46 |
+ |
|
| 47 |
+def watermark_wrap(im_path, mark_path, save_path=''): |
|
| 48 |
+ im, mark = Image.open(im_path), Image.open(mark_path) |
|
| 49 |
+ new_im = watermark(im, mark, (50, 50), 0.5) |
|
| 50 |
+ new_im.save(save_path or im_path) |
|
| 51 |
+ |
|
| 52 |
+ |
|
| 53 |
+def watermark_test(): |
|
| 54 |
+ im, mark = Image.open('original_CGzC_10a50000c8811190.jpg'), Image.open('paiai_96_96.png')
|
|
| 55 |
+ watermark(im, mark, 'tile', 0.5).show() |
|
| 56 |
+ watermark(im, mark, 'scale', 1.0).show() |
|
| 57 |
+ watermark(im, mark, (50, 50), 0.5).show() |
|
| 58 |
+ |
|
| 59 |
+ |
|
| 60 |
+if __name__ == '__main__': |
|
| 61 |
+ # watermark_test() |
|
| 62 |
+ watermark_wrap('original_CGzC_10a50000c8811190.jpg', 'paiai_96_96.png')
|