예제 #1
0
    def get(self, *args, **kwargs):
        orig_image = self.orig_image
        if orig_image:
            orig_w = getattr(orig_image, 'width', None) or 0
            orig_h = getattr(orig_image, 'height', None) or 0
            orig_image_name = getattr(orig_image, 'name', None)
        else:
            orig_w, orig_h = 0, 0
            orig_image_name = None

        initial = {
            'standalone': self.is_standalone,
            'sizes': json.dumps(self.sizes),
            'thumbs': json.dumps(dict([
                (t['name'], t)
                for t in self.thumbs.queryset.values('id', 'name', 'width', 'height')])),
            'image_id': getattr(self.db_image, 'pk', None) if orig_image else None,
            'orig_image': orig_image_name,
            'orig_w': orig_w,
            'orig_h': orig_h,
        }

        FormSet = modelformset_factory(Thumb, form=ThumbForm, formset=ThumbFormSet, extra=0)
        thumb_formset = FormSet(queryset=self.thumbs, initial=[], prefix='thumbs')

        size_dict = dict([(s.name, s) for s in self.sizes])

        for thumb_form in thumb_formset.initial_forms:
            name = thumb_form.initial['name']
            if name in size_dict:
                thumb_form.initial['size'] = json.dumps(size_dict[name])
            # The thumb being cropped and thumbs referencing it
            pk = thumb_form.initial['id']
            thumb_group = self.thumbs.queryset.filter(Q(pk=pk) | Q(reference_thumb_id__exact=pk))
            thumb_group_data = dict([(t['name'], t) for t in thumb_group.values('id', 'name', 'width', 'height')])
            thumb_form.initial.update({
                'thumbs': json.dumps(thumb_group_data),
                'changed': False,
            })

        return render(self.request, 'cropduster/upload.html', {
            'django_is_gte_19': (django.VERSION[:2] >= (1, 9)),
            'is_popup': True,
            'orig_image': '',
            'parent_template': get_admin_base_template(),
            'image': getattr(self.image_file.preview_image, 'url', u"%scropduster/img/blank.gif" % settings.STATIC_URL),
            'standalone': self.is_standalone,
            'upload_form': UploadForm(initial={
                'upload_to': self.upload_to,
                'sizes': initial['sizes'],
                'image_element_id': self.request.GET.get('el_id', ''),
                'standalone': self.is_standalone,
                'preview_width': self.preview_size[0],
                'preview_height': self.preview_size[1],
            }),
            'crop_form': CropForm(initial=initial, prefix='crop'),
            'thumb_formset': thumb_formset,
        })
예제 #2
0
    def generate_xmp(self, size, original_metadata=None):
        from cropduster.standalone.metadata import libxmp
        from cropduster.utils import json

        NS_MWG_RS = "http://www.metadataworkinggroup.com/schemas/regions/"
        NS_XMPMM = "http://ns.adobe.com/xap/1.0/mm/"
        NS_CROP = "http://ns.thealtantic.com/cropduster/1.0/"

        md5 = hashlib.md5()
        with open(self.image.filename, mode='rb') as f:
            md5.update(f.read())
        digest = md5.hexdigest()

        md = original_metadata or libxmp.XMPMeta()
        md.register_namespace(NS_XMPMM, 'xmpMM')
        md.register_namespace(NS_MWG_RS, 'mwg-rs')
        md.register_namespace('http://ns.adobe.com/xap/1.0/sType/Dimensions#', 'stDim')
        md.register_namespace('http://ns.adobe.com/xmp/sType/Area#', 'stArea')
        md.register_namespace(NS_CROP, 'crop')
        md.set_property(NS_CROP, 'crop:size/stDim:w', '%s' % (size.width or ''))
        md.set_property(NS_CROP, 'crop:size/stDim:h', '%s' % (size.height or ''))
        md.set_property(NS_CROP, 'crop:size/crop:json', json.dumps(size))
        md.set_property(NS_CROP, 'crop:md5', digest.upper())
        md.set_property(NS_MWG_RS, 'mwg-rs:Regions/mwg-rs:AppliedToDimensions', '', prop_value_is_struct=True)
        md.set_property(NS_MWG_RS, 'mwg-rs:Regions/mwg-rs:AppliedToDimensions/stDim:w', six.text_type(self.image.size[0]))
        md.set_property(NS_MWG_RS, 'mwg-rs:Regions/mwg-rs:AppliedToDimensions/stDim:h', six.text_type(self.image.size[1]))
        md.set_property(NS_MWG_RS, 'mwg-rs:Regions/mwg-rs:RegionList', '', prop_value_is_array=True)
        md.set_property(NS_MWG_RS, 'mwg-rs:Regions/mwg-rs:RegionList[1]/mwg-rs:Name', 'Crop')
        md.set_property(NS_MWG_RS, 'mwg-rs:Regions/mwg-rs:RegionList[1]/mwg-rs:Area', '', prop_value_is_struct=True)
        md.set_property(NS_MWG_RS, 'mwg-rs:Regions/mwg-rs:RegionList[1]/mwg-rs:Area/stArea:unit', "normalized")
        md.set_property(NS_MWG_RS, 'mwg-rs:Regions/mwg-rs:RegionList[1]/mwg-rs:Area/stArea:w', "%.5f" % (self.box.w / self.bounds.w))
        md.set_property(NS_MWG_RS, 'mwg-rs:Regions/mwg-rs:RegionList[1]/mwg-rs:Area/stArea:h', "%.5f" % (self.box.h / self.bounds.h))
        md.set_property(NS_MWG_RS, 'mwg-rs:Regions/mwg-rs:RegionList[1]/mwg-rs:Area/stArea:x', "%.5f" % (self.box.x1 / self.bounds.w))
        md.set_property(NS_MWG_RS, 'mwg-rs:Regions/mwg-rs:RegionList[1]/mwg-rs:Area/stArea:y', "%.5f" % (self.box.y1 / self.bounds.h))
        return md
예제 #3
0
    def generate_xmp(self, size, original_metadata=None):
        from cropduster.standalone.metadata import libxmp
        from cropduster.utils import json

        NS_MWG_RS = "http://www.metadataworkinggroup.com/schemas/regions/"
        NS_XMPMM = "http://ns.adobe.com/xap/1.0/mm/"
        NS_CROP = "http://ns.thealtantic.com/cropduster/1.0/"

        md5 = hashlib.md5()
        with default_storage.open(self.image.filename, mode='rb') as f:
            md5.update(f.read())
        digest = md5.hexdigest()

        md = original_metadata or libxmp.XMPMeta()
        md.register_namespace(NS_XMPMM, 'xmpMM')
        md.register_namespace(NS_MWG_RS, 'mwg-rs')
        md.register_namespace('http://ns.adobe.com/xap/1.0/sType/Dimensions#', 'stDim')
        md.register_namespace('http://ns.adobe.com/xmp/sType/Area#', 'stArea')
        md.register_namespace(NS_CROP, 'crop')
        md.set_property(NS_CROP, 'crop:size/stDim:w', '%s' % (size.width or ''))
        md.set_property(NS_CROP, 'crop:size/stDim:h', '%s' % (size.height or ''))
        md.set_property(NS_CROP, 'crop:size/crop:json', json.dumps(size))
        md.set_property(NS_CROP, 'crop:md5', digest.upper())
        md.set_property(NS_MWG_RS, 'mwg-rs:Regions/mwg-rs:AppliedToDimensions', '', prop_value_is_struct=True)
        md.set_property(NS_MWG_RS, 'mwg-rs:Regions/mwg-rs:AppliedToDimensions/stDim:w', six.text_type(self.image.size[0]))
        md.set_property(NS_MWG_RS, 'mwg-rs:Regions/mwg-rs:AppliedToDimensions/stDim:h', six.text_type(self.image.size[1]))
        # Clear out any existing <mwg-rs:RegionList> tags so they don't conflict
        # (for instance, iPhone face regions are stored in this tag)
        if md.does_property_exist(NS_MWG_RS, 'mwg-rs:Regions/mwg-rs:RegionList'):
            md.delete_property(NS_MWG_RS, 'mwg-rs:Regions/mwg-rs:RegionList')
        md.set_property(NS_MWG_RS, 'mwg-rs:Regions/mwg-rs:RegionList', '', prop_value_is_array=True)
        md.set_property(NS_MWG_RS, 'mwg-rs:Regions/mwg-rs:RegionList[1]/mwg-rs:Name', 'Crop')
        md.set_property(NS_MWG_RS, 'mwg-rs:Regions/mwg-rs:RegionList[1]/mwg-rs:Area', '', prop_value_is_struct=True)
        md.set_property(NS_MWG_RS, 'mwg-rs:Regions/mwg-rs:RegionList[1]/mwg-rs:Area/stArea:unit', "normalized")
        md.set_property(NS_MWG_RS, 'mwg-rs:Regions/mwg-rs:RegionList[1]/mwg-rs:Area/stArea:w', "%.5f" % (self.box.w / self.bounds.w))
        md.set_property(NS_MWG_RS, 'mwg-rs:Regions/mwg-rs:RegionList[1]/mwg-rs:Area/stArea:h', "%.5f" % (self.box.h / self.bounds.h))
        md.set_property(NS_MWG_RS, 'mwg-rs:Regions/mwg-rs:RegionList[1]/mwg-rs:Area/stArea:x', "%.5f" % (self.box.x1 / self.bounds.w))
        md.set_property(NS_MWG_RS, 'mwg-rs:Regions/mwg-rs:RegionList[1]/mwg-rs:Area/stArea:y', "%.5f" % (self.box.y1 / self.bounds.h))
        return md
예제 #4
0
def crop(request):
    if request.method == "GET":
        return json_error(request,
                          'crop',
                          action="cropping image",
                          errors=["Form submission invalid"])

    crop_form = CropForm(request.POST, request.FILES, prefix='crop')
    if not crop_form.is_valid():
        return json_error(request,
                          'crop',
                          action='submitting form',
                          forms=[crop_form],
                          log=True,
                          exc_info=full_exc_info())

    crop_data = copy.deepcopy(crop_form.cleaned_data)

    if crop_data.get('image_id'):
        db_image = Image.objects.get(pk=crop_data['image_id'])
    else:
        db_image = Image(image=crop_data['orig_image'])

    try:
        with db_image.image as f:
            f.open()
            pil_image = PIL.Image.open(BytesIO(f.read()))
            pil_image.filename = f.name
    except IOError:
        pil_image = None

    FormSet = modelformset_factory(Thumb, form=ThumbForm, formset=ThumbFormSet)
    thumb_formset = FormSet(request.POST, request.FILES, prefix='thumbs')

    if not thumb_formset.is_valid():
        return json_error(request,
                          'crop',
                          action='submitting form',
                          formsets=[thumb_formset],
                          log=True,
                          exc_info=full_exc_info())

    cropped_thumbs = thumb_formset.save(commit=False)

    non_model_fields = set(ThumbForm.declared_fields) - set(
        [f.name for f in Thumb._meta.fields])

    # The fields we will pull from when populating the ThumbForm initial data
    json_thumb_fields = ['id', 'name', 'width', 'height']

    thumbs_with_crops = [t for t in cropped_thumbs if t.crop_w and t.crop_h]
    thumbs_data = [f.cleaned_data for f in thumb_formset]

    standalone_mode = crop_data['standalone']

    # Address a standalone mode issue where, because the thumbs don't have a pk value,
    # Django no longer returns them in Formset.save() if they are in initial_forms
    if standalone_mode and not cropped_thumbs and len(
            thumb_formset.initial_forms):
        thumb_form = thumb_formset.initial_forms[0]
        obj = thumb_form.instance
        cropped_thumbs = [
            thumb_formset.save_existing(thumb_form, obj, commit=False)
        ]

    for i, (thumb, thumb_form) in enumerate(zip(cropped_thumbs,
                                                thumb_formset)):
        changed_fields = set(thumb_form.changed_data) - non_model_fields
        thumb_form._changed_data = list(changed_fields)
        thumb_data = thumbs_data[i]
        size = thumb_data['size']

        if changed_fields & set(['crop_x', 'crop_y', 'crop_w', 'crop_h']):
            # Clear existing primary key to force new thumb creation
            thumb.pk = None

            thumb.width = min(filter(None, [thumb.width, thumb.crop_w]))
            thumb.height = min(filter(None, [thumb.height, thumb.crop_h]))

            try:
                new_thumbs = db_image.save_size(size,
                                                thumb,
                                                tmp=True,
                                                standalone=standalone_mode)
            except CropDusterResizeException as e:
                return json_error(request,
                                  'crop',
                                  action="saving size",
                                  errors=[force_text(e)])

            if not new_thumbs:
                continue

            if standalone_mode:
                thumb = new_thumbs
                new_thumbs = {thumb.name: thumb}

            cropped_thumbs[i] = thumb = new_thumbs.get(thumb.name, thumb)

            update_props = [
                'crop_x', 'crop_y', 'crop_w', 'crop_h', 'width', 'height',
                'id', 'name'
            ]
            for prop in update_props:
                thumbs_data[i][prop] = getattr(thumb, prop)

            thumbs_data[i].update({
                'changed': True,
                'url': db_image.get_image_url(thumb.name),
            })

            for name, new_thumb in six.iteritems(new_thumbs):
                thumb_data = dict([(k, getattr(new_thumb, k))
                                   for k in json_thumb_fields])
                thumb_data['url'] = db_image.get_image_url(
                    name, tmp=not (new_thumb.image_id))
                crop_data['thumbs'].update({name: thumb_data})
                if new_thumb.reference_thumb_id:
                    continue
                thumbs_data[i]['thumbs'].update({name: thumb_data})
        elif thumb.pk and thumb.name and thumb.crop_w and thumb.crop_h:
            thumb_path = db_image.get_image_path(thumb.name, tmp=False)
            tmp_thumb_path = db_image.get_image_path(thumb.name, tmp=True)

            if default_storage.exists(thumb_path):
                if not thumb_form.cleaned_data.get(
                        'changed') or not default_storage.exists(
                            tmp_thumb_path):
                    with default_storage.open(thumb_path) as f:
                        with default_storage.open(tmp_thumb_path,
                                                  'wb') as tmp_file:
                            tmp_file.write(f.read())

        if not thumb.pk and not thumb.crop_w and not thumb.crop_h:
            if not len(thumbs_with_crops):
                continue
            best_fit = thumb_form.cleaned_data['size'].fit_to_crop(
                thumbs_with_crops[0], original_image=pil_image)
            if best_fit:
                thumbs_data[i].update({
                    'crop_x': best_fit.box.x1,
                    'crop_y': best_fit.box.y1,
                    'crop_w': best_fit.box.w,
                    'crop_h': best_fit.box.h,
                    'changed': True,
                    'id': None,
                })

    for thumb_data in thumbs_data:
        if isinstance(thumb_data['id'], Thumb):
            thumb_data['id'] = thumb_data['id'].pk

    preview_url = db_image.get_image_url('_preview')
    preview_w = PREVIEW_WIDTH
    preview_h = PREVIEW_HEIGHT
    orig_width, orig_height = crop_data['orig_w'], crop_data['orig_h']
    if (orig_width and orig_height):
        resize_ratio = min(PREVIEW_WIDTH / float(orig_width),
                           PREVIEW_HEIGHT / float(orig_height))
        if resize_ratio < 1:
            preview_w = int(round(orig_width * resize_ratio))
            preview_h = int(round(orig_height * resize_ratio))

    return HttpResponse(json.dumps({
        'crop': crop_data,
        'thumbs': thumbs_data,
        'initial': True,
        'preview_url': preview_url,
        'preview_w': preview_w,
        'preview_h': preview_h
    }),
                        content_type='application/json')
예제 #5
0
def upload(request):
    if request.method == 'GET':
        return index(request)

    # The data we'll be returning as JSON
    data = {
        'warning': [],
    }

    form = UploadForm(request.POST, request.FILES)

    if not form.is_valid():
        errors = form['image'].errors or form.errors
        return json_error(request,
                          'upload',
                          action="uploading file",
                          errors=[force_text(errors)])

    form_data = form.cleaned_data
    is_standalone = bool(form_data.get('standalone'))

    orig_file_path = form_data['image'].name
    if six.PY2 and isinstance(orig_file_path, six.text_type):
        orig_file_path = orig_file_path.encode('utf-8')
    orig_image = get_relative_media_url(orig_file_path)

    with default_storage.open(orig_image, mode='rb') as f:
        img = PIL.Image.open(BytesIO(f.read()))
        img.filename = f.name

    (w, h) = (orig_w, orig_h) = img.size

    if is_animated_gif(img) and not has_animated_gif_support():
        data['warning'].append(
            u"This server does not have animated gif support; your uploaded image "
            u"has been made static.")

    tmp_image = Image(image=orig_image)
    preview_w = form_data.get('preview_width') or PREVIEW_WIDTH
    preview_h = form_data.get('preview_height') or PREVIEW_HEIGHT

    # First pass resize if it's too large
    resize_ratio = min(preview_w / w, preview_h / h)

    def fit_preview(im):
        (w, h) = im.size
        if resize_ratio < 1:
            w = int(round(w * resize_ratio))
            h = int(round(h * resize_ratio))
            preview_img = im.resize((w, h), PIL.Image.ANTIALIAS)
        else:
            preview_img = im
        return preview_img

    if not is_standalone:
        preview_file_path = tmp_image.get_image_path('_preview')
        process_image(img, preview_file_path, fit_preview)

    data.update({
        'crop': {
            'orig_image': orig_image,
            'orig_w': orig_w,
            'orig_h': orig_h,
            'image_id': None,
        },
        'url': tmp_image.get_image_url('_preview'),
        'orig_image': orig_image,
        'orig_w': orig_w,
        'orig_h': orig_h,
        'width': w,
        'height': h,
    })
    if not is_standalone:
        return HttpResponse(json.dumps(data), content_type='application/json')

    size = Size('crop', w=img.size[0], h=img.size[1])

    md5 = form_data.get('md5')
    try:
        standalone_image = StandaloneImage.objects.get(md5=md5)
    except StandaloneImage.DoesNotExist:
        standalone_image = StandaloneImage(md5=md5, image=orig_image)
        standalone_image.save()
    cropduster_image, created = Image.objects.get_or_create(
        content_type=ContentType.objects.get_for_model(StandaloneImage),
        object_id=standalone_image.pk)

    if not cropduster_image.image:
        cropduster_image.image = orig_image
        cropduster_image.save()
    elif cropduster_image.image.name != orig_image:
        data['crop']['orig_image'] = data[
            'orig_image'] = cropduster_image.image.name
        data['url'] = cropduster_image.get_image_url('_preview')

    with cropduster_image.image as f:
        f.open()
        img = PIL.Image.open(BytesIO(f.read()))
        img.filename = f.name
    preview_file_path = cropduster_image.get_image_path('_preview')
    if not default_storage.exists(preview_file_path):
        process_image(img, preview_file_path, fit_preview)

    thumb = cropduster_image.save_size(size, standalone=True, commit=False)

    sizes = form_data.get('sizes') or []
    if len(sizes) == 1:
        size = sizes[0]
    else:
        size = Size('crop')

    data.update({
        'thumbs': [{
            'crop_x': thumb.crop_x,
            'crop_y': thumb.crop_y,
            'crop_w': thumb.crop_w,
            'crop_h': thumb.crop_h,
            'width': thumb.width,
            'height': thumb.height,
            'id': None,
            'changed': True,
            'size': json.dumps(size),
            'name': thumb.name,
        }]
    })
    data['crop'].update({
        'image_id': cropduster_image.pk,
        'sizes': json.dumps([size]),
    })
    return HttpResponse(json.dumps(data), content_type='application/json')
예제 #6
0
    def get(self, *args, **kwargs):
        orig_image = self.orig_image
        try:
            orig_w = getattr(orig_image, 'width', None) or 0
            orig_h = getattr(orig_image, 'height', None) or 0
            orig_image_name = getattr(orig_image, 'name', None)
        except Exception:
            # If original image not found, allow it to be re-uploaded
            orig_w, orig_h = 0, 0
            orig_image_name = None

        initial = {
            'standalone':
            self.is_standalone,
            'sizes':
            json.dumps(self.sizes),
            'thumbs':
            json.dumps(
                dict([(t['name'], t) for t in self.thumbs.queryset.values(
                    'id', 'name', 'width', 'height')])),
            'image_id':
            getattr(self.db_image, 'pk', None) if orig_image else None,
            'orig_image':
            orig_image_name,
            'orig_w':
            orig_w,
            'orig_h':
            orig_h,
        }

        FormSet = modelformset_factory(Thumb,
                                       form=ThumbForm,
                                       formset=ThumbFormSet,
                                       extra=0)
        thumb_formset = FormSet(queryset=self.thumbs,
                                initial=[],
                                prefix='thumbs')

        size_dict = dict([(s.name, s) for s in self.sizes])

        for thumb_form in thumb_formset.initial_forms:
            name = thumb_form.initial['name']
            if name in size_dict:
                thumb_form.initial['size'] = json.dumps(size_dict[name])
            # The thumb being cropped and thumbs referencing it
            pk = thumb_form.initial['id']
            thumb_group = self.thumbs.queryset.filter(
                Q(pk=pk) | Q(reference_thumb_id__exact=pk))
            thumb_group_data = dict([
                (t['name'], t)
                for t in thumb_group.values('id', 'name', 'width', 'height')
            ])
            thumb_form.initial.update({
                'thumbs': json.dumps(thumb_group_data),
                'changed': False,
            })

        return render(
            self.request, 'cropduster/upload.html', {
                'django_is_gte_19': (django.VERSION[:2] >= (1, 9)),
                'is_popup':
                True,
                'orig_image':
                '',
                'parent_template':
                get_admin_base_template(),
                'image':
                getattr(self.image_file.preview_image, 'url',
                        u"%scropduster/img/blank.gif" % settings.STATIC_URL),
                'standalone':
                self.is_standalone,
                'upload_form':
                UploadForm(
                    initial={
                        'upload_to': self.upload_to,
                        'sizes': initial['sizes'],
                        'image_element_id': self.request.GET.get('el_id', ''),
                        'standalone': self.is_standalone,
                        'preview_width': self.preview_size[0],
                        'preview_height': self.preview_size[1],
                    }),
                'crop_form':
                CropForm(initial=initial, prefix='crop'),
                'thumb_formset':
                thumb_formset,
            })
예제 #7
0
def crop(request):
    if request.method == "GET":
        return json_error(request, 'crop', action="cropping image",
                errors=["Form submission invalid"])

    crop_form = CropForm(request.POST, request.FILES, prefix='crop')
    if not crop_form.is_valid():
        return json_error(request, 'crop', action='submitting form', forms=[crop_form],
                log=True, exc_info=full_exc_info())

    crop_data = copy.deepcopy(crop_form.cleaned_data)
    db_image = Image(image=crop_data['orig_image'])
    try:
        pil_image = PIL.Image.open(db_image.image.path)
    except IOError:
        pil_image = None

    FormSet = modelformset_factory(Thumb, form=ThumbForm, formset=ThumbFormSet)
    thumb_formset = FormSet(request.POST, request.FILES, prefix='thumbs')

    if not thumb_formset.is_valid():
        return json_error(request, 'crop', action='submitting form', formsets=[thumb_formset],
                log=True, exc_info=full_exc_info())

    cropped_thumbs = thumb_formset.save(commit=False)

    non_model_fields = set(ThumbForm.declared_fields) - set([f.name for f in Thumb._meta.fields])

    # The fields we will pull from when populating the ThumbForm initial data
    json_thumb_fields = ['id', 'name', 'width', 'height']

    thumbs_with_crops = [t for t in cropped_thumbs if t.crop_w and t.crop_h]
    thumbs_data = [f.cleaned_data for f in thumb_formset]

    standalone_mode = crop_data['standalone']

    # Address a standalone mode issue where, because the thumbs don't have a pk value,
    # Django no longer returns them in Formset.save() if they are in initial_forms
    if standalone_mode and not cropped_thumbs and len(thumb_formset.initial_forms):
        thumb_form = thumb_formset.initial_forms[0]
        obj = thumb_form.instance
        cropped_thumbs = [thumb_formset.save_existing(thumb_form, obj, commit=False)]

    for i, (thumb, thumb_form) in enumerate(zip(cropped_thumbs, thumb_formset)):
        changed_fields = set(thumb_form.changed_data) - non_model_fields
        thumb_form._changed_data = list(changed_fields)
        thumb_data = thumbs_data[i]
        size = thumb_data['size']

        if changed_fields & set(['crop_x', 'crop_y', 'crop_w', 'crop_h']):
            # Clear existing primary key to force new thumb creation
            thumb.pk = None

            thumb.width = min(filter(None, [thumb.width, thumb.crop_w]))
            thumb.height = min(filter(None, [thumb.height, thumb.crop_h]))

            try:
                new_thumbs = db_image.save_size(size, thumb, tmp=True, standalone=standalone_mode)
            except CropDusterResizeException as e:
                return json_error(request, 'crop',
                                  action="saving size", errors=[force_text(e)])

            if not new_thumbs:
                continue

            if standalone_mode:
                thumb = new_thumbs
                new_thumbs = {thumb.name: thumb}

            cropped_thumbs[i] = thumb = new_thumbs.get(thumb.name, thumb)

            update_props = ['crop_x', 'crop_y', 'crop_w', 'crop_h', 'width', 'height', 'id', 'name']
            for prop in update_props:
                thumbs_data[i][prop] = getattr(thumb, prop)

            thumbs_data[i].update({
                'changed': True,
                'url': db_image.get_image_url(thumb.name),
            })

            for name, new_thumb in six.iteritems(new_thumbs):
                thumb_data = dict([(k, getattr(new_thumb, k)) for k in json_thumb_fields])
                crop_data['thumbs'].update({name: thumb_data})
                if new_thumb.reference_thumb_id:
                    continue
                thumbs_data[i]['thumbs'].update({name: thumb_data})
        elif thumb.pk and thumb.name and thumb.crop_w and thumb.crop_h:
            thumb_path = db_image.get_image_path(thumb.name, tmp=False)
            tmp_thumb_path = db_image.get_image_path(thumb.name, tmp=True)
            if os.path.exists(thumb_path):
                if not thumb_form.cleaned_data.get('changed') or not os.path.exists(tmp_thumb_path):
                    shutil.copy(thumb_path, tmp_thumb_path)

        if not thumb.pk and not thumb.crop_w and not thumb.crop_h:
            if not len(thumbs_with_crops):
                continue
            best_fit = thumb_form.cleaned_data['size'].fit_to_crop(
                    thumbs_with_crops[0], original_image=pil_image)
            if best_fit:
                thumbs_data[i].update({
                    'crop_x': best_fit.box.x1,
                    'crop_y': best_fit.box.y1,
                    'crop_w': best_fit.box.w,
                    'crop_h': best_fit.box.h,
                    'changed': True,
                    'id': None,
                })

    for thumb_data in thumbs_data:
        if isinstance(thumb_data['id'], Thumb):
            thumb_data['id'] = thumb_data['id'].pk

    return HttpResponse(json.dumps({
        'crop': crop_data,
        'thumbs': thumbs_data,
        'initial': True,
    }), content_type='application/json')
예제 #8
0
def upload(request):
    if request.method == 'GET':
        return index(request)

    # The data we'll be returning as JSON
    data = {
        'warning': [],
    }

    form = UploadForm(request.POST, request.FILES)

    if not form.is_valid():
        errors = form['image'].errors or form.errors
        return json_error(request, 'upload', action="uploading file",
                errors=[force_text(errors)])

    form_data = form.cleaned_data
    is_standalone = bool(form_data.get('standalone'))

    orig_file_path = form_data['image'].name
    if six.PY2 and isinstance(orig_file_path, unicode):
        orig_file_path = orig_file_path.encode('utf-8')
    orig_image = get_relative_media_url(orig_file_path)
    img = PIL.Image.open(orig_file_path)
    (w, h) = (orig_w, orig_h) = img.size

    if is_animated_gif(img) and not has_animated_gif_support():
        data['warning'].append(
            u"This server does not have animated gif support; your uploaded image "
            u"has been made static.")

    tmp_image = Image(image=orig_image)
    preview_w = form_data.get('preview_width') or PREVIEW_WIDTH
    preview_h = form_data.get('preview_height') or PREVIEW_HEIGHT

    # First pass resize if it's too large
    resize_ratio = min(preview_w / w, preview_h / h)

    def fit_preview(im):
        (w, h) = im.size
        if resize_ratio < 1:
            w = int(round(w * resize_ratio))
            h = int(round(h * resize_ratio))
            preview_img = im.resize((w, h), PIL.Image.ANTIALIAS)
        else:
            preview_img = im
        return preview_img

    if not is_standalone:
        preview_file_path = tmp_image.get_image_path('_preview')
        process_image(img, preview_file_path, fit_preview)

    data.update({
        'crop': {
            'orig_image': orig_image,
            'orig_w': orig_w,
            'orig_h': orig_h,
            'image_id': None,
        },
        'url': tmp_image.get_image_url('_preview'),
        'orig_image': orig_image,
        'orig_w': orig_w,
        'orig_h': orig_h,
        'width': w,
        'height': h,
    })
    if not is_standalone:
        return HttpResponse(json.dumps(data), content_type='application/json')

    size = Size('crop', w=img.size[0], h=img.size[1])

    md5 = form_data.get('md5')
    try:
        standalone_image = StandaloneImage.objects.get(md5=md5)
    except StandaloneImage.DoesNotExist:
        standalone_image = StandaloneImage(md5=md5, image=orig_image)
        standalone_image.save()
    cropduster_image, created = Image.objects.get_or_create(
        content_type=ContentType.objects.get_for_model(StandaloneImage),
        object_id=standalone_image.pk)

    if not cropduster_image.image:
        cropduster_image.image = orig_image
        cropduster_image.save()
    elif cropduster_image.image.name != orig_image:
        data['crop']['orig_image'] = data['orig_image'] = cropduster_image.image.name
        data['url'] = cropduster_image.get_image_url('_preview')

    img = PIL.Image.open(cropduster_image.image.path)
    preview_file_path = cropduster_image.get_image_path('_preview')
    if not os.path.exists(preview_file_path):
        process_image(img, preview_file_path, fit_preview)

    thumb = cropduster_image.save_size(size, standalone=True)

    sizes = form_data.get('sizes') or []
    if len(sizes) == 1:
        size = sizes[0]
    else:
        size = Size('crop')

    data.update({
        'thumbs': [{
            'crop_x': thumb.crop_x,
            'crop_y': thumb.crop_y,
            'crop_w': thumb.crop_w,
            'crop_h': thumb.crop_h,
            'width':  thumb.width,
            'height': thumb.height,
            'id': None,
            'changed': True,
            'size': json.dumps(size),
            'name': thumb.name,
        }]
    })
    data['crop'].update({
        'image_id': cropduster_image.pk,
        'sizes': json.dumps([size]),
    })
    return HttpResponse(json.dumps(data), content_type='application/json')