Esempio n. 1
0
class Photo(models.Model):
    PORTRAIT = 'P'
    LANDSCAPE = 'L'
    ORIENTATION_CHOICES = ((PORTRAIT, 'Portrait'), (LANDSCAPE, 'Landscape'))
    project = models.ForeignKey(Project,
                                on_delete=models.CASCADE,
                                related_name="photos")
    photo = models.ImageField(upload_to='project_photos/')
    orientation = models.CharField(max_length=1, choices=ORIENTATION_CHOICES)
    display_order = models.IntegerField()
    portrait = ImageSpecField(source='photo',
                              processors=[
                                  SmartResize(500, 700),
                                  ResizeCanvas(1110, 700, color='black')
                              ],
                              format='JPEG',
                              options={'quality': 60})
    landscape = ImageSpecField(source='photo',
                               processors=[SmartResize(1110, 700)],
                               format='JPEG',
                               options={'quality': 60})
    thumbnail = ImageSpecField(source='photo',
                               processors=[SmartResize(400, 200)],
                               format='JPEG',
                               options={'quality': 60})
    credit = models.CharField(max_length=100)

    @property
    def is_landscape(self):
        return self.orientation == self.LANDSCAPE

    def __str__(self):
        return '{} {}'.format(self.project.title, self.pk)
Esempio n. 2
0
class Gift(TimeStampedModel):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    name = models.CharField(verbose_name=_('Name'), max_length=300)
    description = models.TextField(verbose_name=_('Description'), null=True, blank=True)
    link = models.TextField(verbose_name=_('Link'), null=True, blank=True)
    price = models.DecimalField(verbose_name=_('Price'), max_digits=7, decimal_places=2)
    gift_is_part = models.BooleanField(verbose_name=_('Gift is part'), default=False)
    max_parts = models.PositiveIntegerField(verbose_name=_('Maximum number of parts'))
    taken_parts = models.PositiveIntegerField(verbose_name=_('Number of parts taken'), default=0)
    img = models.ImageField(blank=True, null=True)
    img_catalog = ImageSpecField(source='img', processors=[ResizeToFit(800, 600), ResizeCanvas(800, 600)],
                                 format='JPEG', options={'quality': 60})
    img_miniature = ImageSpecField(source='img', processors=[ResizeToFill(60, 60)],
                                   format='JPEG', options={'quality': 60})

    def is_available(self):
        if self.taken_parts < self.max_parts:
            return True
        else:
            return False

    def avail_parts(self):
        return self.max_parts - self.taken_parts

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse("wedding:gift-detail", kwargs={'pk': self.pk})

    class Meta:
        verbose_name = "Gift"
        verbose_name_plural = "Gifts"
        permissions = (
            ("edit", "Can edit the Gift list"),
        )
Esempio n. 3
0
class Image(models.Model):
    """Image model."""

    # *******************************************************************
    # ******************** Language independent data ********************
    # *******************************************************************
    api_url = models.TextField(
        null=False,
        blank=False,
        unique=True,
        verbose_name=_("Image API URL"),
    )
    primary = models.BooleanField(default=False,
                                  verbose_name=_("Primary image"))
    image = models.FileField(
        null=True,
        blank=True,
        upload_to='collection_images',
        verbose_name=_("Image"),
    )
    image_large = ImageSpecField(source='image',
                                 processors=[
                                     ResizeToFit(960, 960, upscale=False),
                                 ],
                                 format='JPEG',
                                 options={
                                     'quality': 85,
                                     'suffix': '_large'
                                 })
    image_sized = ImageSpecField(source='image_large',
                                 processors=[
                                     ResizeToFit(108, 108, upscale=False),
                                     ResizeCanvas(128, 128),
                                 ],
                                 format='JPEG',
                                 options={
                                     'quality': 90,
                                     'suffix': '_sized'
                                 })
    image_ml = ImageSpecField(source='image_large',
                              processors=[
                                  ResizeToFit(108, 108, upscale=False),
                                  ResizeCanvas(128, 128),
                              ],
                              format='PNG',
                              options={
                                  'quality': 90,
                                  'suffix': '_ml'
                              })
    active = models.BooleanField(
        default=False,
        verbose_name=_("Active"),
    )
    trimmed = models.BooleanField(
        default=False,
        verbose_name=_("Trimmed"),
    )
    created = models.DateField(
        auto_now_add=True,
        verbose_name=_("Date imported"),
    )
    updated = models.DateField(
        auto_now=True,
        verbose_name=_("Date updated"),
    )

    # *******************************************************************
    # ******************** Data translated into English *****************
    # *******************************************************************
    title = models.CharField(max_length=255,
                             null=True,
                             blank=True,
                             verbose_name=_("Title"),
                             help_text=_("Title of the object"))
    description = models.TextField(null=True,
                                   blank=True,
                                   verbose_name=_("Description"),
                                   help_text=_("Description of the object"))

    # *******************************************************************
    # ******************** Original data as imported ********************
    # *******************************************************************
    title_orig = models.CharField(max_length=255,
                                  null=True,
                                  blank=True,
                                  verbose_name=_("Original title"),
                                  help_text=_("Title of the object"))
    description_orig = models.TextField(
        null=True,
        blank=True,
        verbose_name=_("Original description"),
        help_text=_("Description of the object"))

    class Meta(object):
        """Meta options."""

    def __str__(self):
        return self.api_url
Esempio n. 4
0
class Especialista(TimeStampedModel):
    CHOICES_TIPO_DOCUMENTO = (
        ('CC', 'Cédula Ciudadanía'),
        ('CE', 'Cédula Extrangería'),
        ('PS', 'Pasaporte'),
        ('TI', 'Tarjeta Identidad'),
    )
    CHOICES_SEXO = (('F', 'Femenino'), ('M', 'Masculino'))
    user = models.OneToOneField(User,
                                related_name='especialista',
                                on_delete=models.CASCADE)
    tipo_documento = models.CharField(max_length=2,
                                      choices=CHOICES_TIPO_DOCUMENTO,
                                      default='CC')
    nro_identificacion = models.CharField(max_length=30, unique=True)
    nombre = models.CharField(max_length=60)
    nombre_segundo = models.CharField(max_length=60, null=True, blank=True)
    apellido = models.CharField(max_length=60)
    apellido_segundo = models.CharField(max_length=60, null=True, blank=True)
    fecha_nacimiento = models.DateTimeField()
    genero = models.CharField(choices=CHOICES_SEXO, default='F', max_length=20)
    grupo_sanguineo = models.CharField(max_length=60, null=True, blank=True)

    especialidad = models.ForeignKey(Especialidad,
                                     on_delete=models.PROTECT,
                                     verbose_name='Especialidad',
                                     null=True,
                                     blank=True)
    universidad = models.CharField(max_length=100, blank=True, null=True)
    registro_profesional = models.CharField(max_length=100,
                                            null=True,
                                            blank=True)

    firma = ProcessedImageField(
        processors=[ResizeToFit(400, 300),
                    ResizeCanvas(400, 300)],
        format='PNG',
        options={'quality': 100},
        null=True,
        blank=True)

    class Meta:
        verbose_name_plural = 'Especialistas'
        verbose_name = 'Especialista'

    @staticmethod
    def existe_documento(tipo_documento: str, nro_identificacion: str) -> bool:
        return Especialista.objects.filter(
            tipo_documento=tipo_documento,
            nro_identificacion=nro_identificacion).exists()

    @property
    def full_name(self):
        nombre_segundo = ''
        if self.nombre_segundo:
            nombre_segundo = ' %s' % (self.nombre_segundo)

        apellido_segundo = ''
        if self.apellido_segundo:
            apellido_segundo = ' %s' % (self.apellido_segundo)

        return '%s%s %s%s' % (self.nombre, nombre_segundo, self.apellido,
                              apellido_segundo)

    def __str__(self):
        return self.full_name
class Thumbnail1400(ImageSpec):
    processors = [ResizeToFit(1400, 1400),ResizeCanvas(1400,1400)]
    format = 'JPEG'
    options = {'quality': 100}
class Thumbnail450(ImageSpec):
    processors = [ResizeToFit(400, 300),ResizeCanvas(400,300)]
    format = 'PNG'
    options = {'quality': 90}
class Thumbnail80(ImageSpec):
    processors = [ResizeToFit(80, 65),ResizeCanvas(80,65)]
    format = 'PNG'
    options = {'quality': 90}
class Thumbnail50(ImageSpec):
    processors = [ResizeToFit(50, 40),ResizeCanvas(50,40)]
    format = 'PNG'
    options = {'quality': 80}
Esempio n. 9
0
class Shape(ResultBase):
    """ Abstract parent describing a complex polygon.  Shapes are represented
    as a bag of vertices, triangles, and line segments.  Users submit
    instances of SubmittedShapes, which are then intersected and triangulated
    to form subclasses of Shape. """

    #: min size of a shape
    MIN_PIXEL_AREA = 4096
    #: min size of a shape for rectification
    MIN_PLANAR_AREA = 16384

    #: Vertices format: x1,y1,x2,y2,x3,y3,... (coords are fractions of width/height)
    #: (this format allows easy embedding into javascript)
    vertices = models.TextField()
    #: num_vertices should be equal to len(points.split(','))//2
    num_vertices = models.IntegerField(db_index=True)

    #: Triangles format: p1,p2,p3,p2,p3,p4..., where p_i is an index into
    #: vertices, and p1-p2-p3 is a triangle.  Each triangle is three indices
    #: into points; all triangles are listed together.  This format allows easy
    #: embedding into javascript.
    triangles = models.TextField()
    #: num_triangles should be equal to len(triangles.split(','))//3
    num_triangles = models.IntegerField()

    #: Segments format: "p1,p2,p2,p3,...", where p_i is an index into vertices,
    #: and p1-p2, p2-p3, ... are the line segments.  The segments are unordered.
    #: Each line segment is two indices into points; all segments are listed
    #: together.  This format allows easy embedding into javascript.
    segments = models.TextField()
    #: num_segments should be equal to len(segments.split(','))//2
    num_segments = models.IntegerField()

    ## Line segments re-grouped as poly-lines "[[p1,p2,p3,p4],[p1,p2,p3],...]",
    ## json encoded.  Each p_i is an index into vertices.  This is the exact same
    ## data as the segments field, but with line segments properly grouped.
    #polylines = models.TextField()
    ## Number of unique polylines; should equal len(json.loads(polylines))
    #num_polylines = models.IntegerField()

    #: Area in normalized units.  To get the pixel area, multiply this by the
    #: total photo area.
    area = models.FloatField()

    #: Area in pixels
    pixel_area = models.IntegerField(null=True, db_index=True)

    #: flag to separate out this shape
    synthetic = models.BooleanField(default=False)
    synthetic_slug = models.CharField(max_length=32, blank=True)

    #: if true, enough users voted this to be the correct type of segmentation
    correct = models.NullBooleanField()
    #: further from 0: more confident in assignment of correct
    correct_score = models.FloatField(
        blank=True, null=True, db_index=True)

    #: if true, enough users voted this to be flat
    planar = models.NullBooleanField()
    #: CUBAM score for the planar field.  further from 0: more confident in
    #: assignment of planar.
    planar_score = models.FloatField(blank=True, null=True, db_index=True)
    #: method by which the planar field was set
    PLANAR_METHODS = (('A', 'admin'), ('C', 'CUBAM'), ('M', 'majority vote'))
    planar_method_to_str = dict((k, v) for (k, v) in PLANAR_METHODS)
    planar_method = models.CharField(
        max_length=1, choices=PLANAR_METHODS, blank=True, null=True)

    #: Photo masked by the shape and cropped to the bounding box.  The masked
    #: (excluded) region has pixels that are white with no opacity (ARGB value
    #: (0, 255, 255, 255)).
    image_crop = models.ImageField(
        upload_to='shapes', blank=True, max_length=255, storage=STORAGE)

    #: square thumbnail with whitebackground
    image_square_300 = ImageSpecField(
        [ResizeToFit(300, 300), ResizeCanvas(300, 300, color=(255, 255, 255))],
        source='image_crop', format='JPEG', options={'quality': 90}, cachefile_storage=STORAGE)

    #: bbox: photo cropped out to the bounding box of this shape
    image_bbox = models.ImageField(
        upload_to='bbox', blank=True, max_length=255, storage=STORAGE)

    #: bbox resized to fit in 512x512
    image_bbox_512 = ImageSpecField(
        [ResizeToFit(512, 512)],
        source='image_bbox', format='JPEG', options={'quality': 90}, cachefile_storage=STORAGE)

    #: bbox resized to fit in 1024x1024 (used by opengl widget in rectify task)
    image_bbox_1024 = ImageSpecField(
        [ResizeToFit(1024, 1024)],
        source='image_bbox', format='JPEG', options={'quality': 90}, cachefile_storage=STORAGE)

    #: position to show a label (normalized coordinates)
    label_pos_x = models.FloatField(blank=True, null=True)
    label_pos_y = models.FloatField(blank=True, null=True)

    ## json-encoded array [min x, min y, max x, max y] indicating the position
    ## of the bounding box.  as usual, positions are specified as fractions of
    ## width and height.
    #bbox = models.TextField(blank=True)

    ## bbox width/height aspect ratio
    #bbox_aspect_ratio = models.FloatField(null=True, blank=True)

    #: padded bounding box image.  this is the bounding box, expanded by 25% on
    #: each side (as a fraction of the bbox width,height), and then the smaller
    #: dimension is expanded to as quare.
    image_pbox = models.ImageField(
        upload_to='pbox', blank=True, max_length=255, storage=STORAGE)

    image_pbox_300 = ImageSpecField(
        [ResizeToFit(300, 300)],
        source='image_pbox', format='JPEG', options={'quality': 90},
        cachefile_storage=STORAGE)

    image_pbox_512 = ImageSpecField(
        [ResizeToFit(512, 512)],
        source='image_pbox', format='JPEG', options={'quality': 90},
        cachefile_storage=STORAGE)

    image_pbox_1024 = ImageSpecField(
        [ResizeToFit(1024, 1024)],
        source='image_pbox', format='JPEG', options={'quality': 90},
        cachefile_storage=STORAGE)

    # pbox width/height aspect ratio (as a ratio of pixel lengths)
    pbox_aspect_ratio = models.FloatField(null=True, blank=True)

    # json-encoded array [min x, min y, max x, max y] indicating the position
    # of the padded box.  as usual, positions are specified as fractions of
    # width and height.
    pbox = models.TextField(blank=True)

    ## The THREE.js vertices are re-normalized so that the aspect ratio is
    ## correct.  The x-coordinate is now in units of height, not width.

    ## THREE.js json file
    #three_js = models.FileField(
        #upload_to='three', blank=True, max_length=255)

    ## THREE.js buffer file
    #three_bin = models.FileField(
        #upload_to='three', blank=True, max_length=255)

    # approximate area of the rectified texture (in pixels)
    rectified_area = models.FloatField(null=True, blank=True)

    # dominant color of this shape
    dominant_r = models.FloatField(null=True, blank=True)
    dominant_g = models.FloatField(null=True, blank=True)
    dominant_b = models.FloatField(null=True, blank=True)

    # top 4 dominant colors written as #rrggbb (for easy HTML viewing)
    # (in decreasing order of frequency)
    dominant_rgb0 = models.CharField(max_length=7, blank=True, default='')
    dominant_rgb1 = models.CharField(max_length=7, blank=True, default='')
    dominant_rgb2 = models.CharField(max_length=7, blank=True, default='')
    dominant_rgb3 = models.CharField(max_length=7, blank=True, default='')

    # difference between top two colors
    dominant_delta = models.FloatField(null=True, blank=True)

    def has_fov(self):
        return self.photo.fov > 0

    def publishable(self):
        return self.photo.publishable()

    def image_pbox_height(self, width):
        """ Returns the height of image_pbox_<width> """
        return min(width, width / self.pbox_aspect_ratio)

    def label_pos_x_scaled(self):
        """ Returns the label position normalized by height instead of width
        """
        return self.label_pos_x * self.photo.aspect_ratio

    def label_pos_2_y_512(self):
        return self.label_pos_y + 1.25 * self.photo.font_size_512()

    # helpers for templates
    def image_pbox_height_1024(self):
        return self.image_pbox_height(1024)

    def image_pbox_height_512(self):
        return self.image_pbox_height(512)

    def save(self, *args, **kwargs):
        # compute counts:
        if not self.num_vertices:
            self.num_vertices = len(self.vertices.split(',')) // 2
        if not self.num_triangles:
            self.num_triangles = len(self.triangles.split(',')) // 3
        if not self.num_segments:
            self.num_segments = len(self.segments.split(',')) // 2
        if not self.area:
            from shapes.utils import complex_polygon_area
            self.area = complex_polygon_area(self.vertices, self.triangles)
        if not self.pixel_area:
            self.pixel_area = (self.area * self.photo.image_orig.width *
                               self.photo.image_orig.height)
        if not self.synthetic:
            self.synthetic = self.photo.synthetic
        if not self.label_pos_x or not self.label_pos_y:
            from shapes.utils import update_shape_label_pos
            update_shape_label_pos(self, save=False)

        thumbs_dirty = (not self.id)

        # compute cropped image synchronously, before saving
        # (this way the shape only shows up after all thumbs are available)
        if not self.image_crop or not self.image_bbox:
            from shapes.utils import update_shape_image_crop
            update_shape_image_crop(self, save=False)
            thumbs_dirty = True

        if not self.image_pbox:
            from shapes.utils import update_shape_image_pbox
            update_shape_image_pbox(self, save=False)
            thumbs_dirty = True

        #if not self.three_js or not self.three_bin:
            #from shapes.utils import update_shape_three
            #update_shape_three(self, save=False)

        #if not self.dominant_rgb0:
        if thumbs_dirty:
            from shapes.utils import update_shape_dominant_rgb
            update_shape_dominant_rgb(self, save=False)

        if (not self.dominant_delta and
                self.dominant_rgb0 and
                self.dominant_rgb1):
            from shapes.utils import update_shape_dominant_delta
            update_shape_dominant_delta(self, save=False)

        super(Shape, self).save(*args, **kwargs)

    def render_full_complex_polygon_mask(
            self, width=None, height=None, inverted=False):
        """
        Returns a black-and-white PIL image (mode ``1``) the same size as the
        original photo (unless ``width`` and ``height`` are specified.  Pixels
        inside the polygon are ``1`` and pixels outside are ``0`` (unless
        ``inverted=True``).

        :param width: width in pixels, or if ``None``, use
            ``self.photo.orig_width``.

        :param height: width in pixels, or if ``None``, use
            ``self.photo.orig_height``.

        :param inverted: if ``True``, swap ``0`` and ``1`` in the output.
        """

        from shapes.utils import render_full_complex_polygon_mask
        return render_full_complex_polygon_mask(
            vertices=self.vertices,
            triangles=self.triangles,
            width=width if width else self.photo.orig_width,
            height=height if height else self.photo.orig_height,
            inverted=inverted)

    # temporary hack
    def is_kitchen(self):
        return (self.photo.scene_category.name == u'kitchen')

    # temporary hack
    def is_living_room(self):
        return (self.photo.scene_category.name == u'living room')

    # deprecated -- delete at some point
    def area_pixels(self):
        return (self.area *
                self.photo.image_orig.width *
                self.photo.image_orig.height)

    def __unicode__(self):
        return 'Shape (%s v)' % self.num_vertices

    def segments_svg_path(self):
        """ Returns all line segments as SVG path data """
        verts = self.vertices.split(',')  # leave as string
        segs = [int(v) for v in self.segments.split(',')]
        data = []
        for i in xrange(0, len(segs), 2):
            v0 = 2 * segs[i]
            v1 = 2 * segs[i + 1]
            data.append(u"M%s,%sL%s,%s" % (
                verts[v0], verts[v0 + 1],
                verts[v1], verts[v1 + 1],
            ))
        return u"".join(data)

    def triangles_svg_path(self):
        """ Returns all triangles as SVG path data """
        verts = self.vertices.split(',')  # leave as string
        tris = [int(v) for v in self.triangles.split(',')]
        data = []
        for i in xrange(0, len(tris), 3):
            v0 = 2 * tris[i]
            v1 = 2 * tris[i + 1]
            v2 = 2 * tris[i + 2]
            data.append(u"M%s,%sL%s,%sL%s,%sz" % (
                verts[v0], verts[v0 + 1],
                verts[v1], verts[v1 + 1],
                verts[v2], verts[v2 + 1],
            ))
        return u"".join(data)

    def pbox_view_box(self):
        """ Returns the padded box as the tuple
        ``(min_x, min_y, width, height)`` """
        pbox = json.loads(self.pbox)
        return (pbox[0], pbox[1], pbox[2] - pbox[0], pbox[3] - pbox[0])

    def pbox_svg_transform(self):
        return "scale(%s,1) %s" % (
            self.pbox_aspect_ratio,
            bbox_svg_transform(json.loads(self.pbox)),
        )

    #def shape_svg_url_large(self):
        #from shapes.utils import material_shape_svg_url_large
        #return material_shape_svg_url_large(self)

    #def shape_svg_url_small(self):
        #from shapes.utils import material_shape_svg_url_small
        #return material_shape_svg_url_small(self)

    def get_entry_dict(self):
        """ Return a dictionary of this model containing just the fields needed
        for javascript rendering.  """

        # generating thumbnail URLs is slow, so only generate the ones
        # that will definitely be used.
        ret = {
            'id': self.id,
            'vertices': self.vertices,
            'triangles': self.triangles,
            'segments': self.segments,
            'photo': self.photo.get_entry_dict(),
        }
        if self.dominant_rgb0:
            ret['dominant_rgb0'] = self.dominant_rgb0
        #if self.image_pbox:
            #ret['pbox'] = self.pbox
            #ret['image_pbox'] = {
                #'300': self.image_pbox_300.url,
                #'512': self.image_pbox_512.url,
                #'1024': self.image_pbox_1024.url,
                #'orig': self.image_pbox.url,
            #}
        if self.image_bbox:
            ret['image_bbox'] = {
                #'512': self.image_bbox_512.url,
                '1024': self.image_bbox_1024.url,
                #'orig': self.image_bbox.url,
            }
        return ret

    def mark_invalid(self, *args, **kwargs):
        self.correct = False
        super(Shape, self).mark_invalid(*args, **kwargs)

    class Meta:
        abstract = True
        ordering = ['-num_vertices', '-time_ms']
Esempio n. 10
0
class ProductImage(models.Model):

    product = models.ForeignKey(Product,
                                verbose_name='product',
                                related_name='images',
                                on_delete=models.CASCADE)
    sort = models.PositiveSmallIntegerField('sorting', default=1)
    image = models.ImageField('picture', upload_to=upload_to('products'))

    image_admin = ImageSpecField(source='image',
                                 processors=[ResizeToCover(100, 100)],
                                 format='JPEG',
                                 options={'quality': 90})

    image_banner = ImageSpecField(source='image',
                                  processors=[
                                      ResizeToFit(250, 250),
                                      ResizeCanvas(250,
                                                   250,
                                                   anchor=Anchor.CENTER)
                                  ],
                                  format='PNG')

    image_product = ImageSpecField(source='image',
                                   processors=[
                                       ResizeToFit(280, 280),
                                       ResizeCanvas(280,
                                                    280,
                                                    anchor=Anchor.CENTER)
                                   ],
                                   format='PNG')

    image_category = ImageSpecField(source='image',
                                    processors=[
                                        ResizeToFit(160, 160),
                                        ResizeCanvas(160,
                                                     160,
                                                     anchor=Anchor.CENTER)
                                    ],
                                    format='PNG')

    image_list = ImageSpecField(source='image',
                                processors=[
                                    ResizeToFit(160, 160),
                                    ResizeCanvas(160,
                                                 160,
                                                 anchor=Anchor.CENTER)
                                ],
                                format='PNG')

    image_cart = ImageSpecField(source='image',
                                processors=[
                                    ResizeToFit(86, 86),
                                    ResizeCanvas(86, 86, anchor=Anchor.CENTER)
                                ],
                                format='PNG')

    class Meta:
        verbose_name = 'product image'
        verbose_name_plural = 'product images'
        ordering = ('sort', )