示例#1
0
class Screenshot(models.Model):
    DIFF_EPSILON = 1e-4

    STATE_PENDING = 0
    STATE_MATCHING = 1
    STATE_DIFFERENT = 2
    STATE_NEW = 3
    STATE_DELETED = 4
    STATE_CHOICES = (
        (STATE_PENDING, 'Pending'),
        (STATE_MATCHING, 'Matching'),
        (STATE_DIFFERENT, 'Different'),
        (STATE_NEW, 'New'),
        (STATE_DELETED, 'Deleted'),
    )

    build = models.ForeignKey(Build,
                              models.CASCADE,
                              related_name='screenshots')
    state = models.IntegerField(choices=STATE_CHOICES, default=STATE_PENDING)
    parent = models.ForeignKey('self',
                               models.SET_NULL,
                               null=True,
                               related_name='children')
    date_created = models.DateTimeField(auto_now_add=True)
    name = models.CharField(max_length=255)
    metadata_json = models.TextField(blank=True, null=True)
    image = models.ImageField(upload_to='screenshots/')
    image_diff = models.ImageField(upload_to='screenshot_diffs/', null=True)
    image_diff_amount = models.FloatField(null=True)
    archived = models.BooleanField(default=False, db_index=True)

    @cached_property
    def metadata(self):
        if self.metadata_json:
            return json.loads(self.metadata_json)
        return None

    @cached_property
    def metadata_pretty(self):
        if self.metadata:
            return json.dumps(self.metadata, indent=2, ensure_ascii=False)
        return None

    def find_parent(self):
        parent_build = self.build.parent
        if parent_build:
            return parent_build.screenshots.filter(name=self.name).first()
        else:
            return None

    def process(self):
        self.parent = self.find_parent()
        if self.parent is None:
            self.state = Screenshot.STATE_NEW
        else:
            wand_current = Image(filename=self.image.path)
            wand_parent = Image(filename=self.parent.image.path)
            wand_diff, difference = wand_current.compare(
                wand_parent, metric='root_mean_square')

            self.image_diff_amount = difference
            if difference > self.DIFF_EPSILON:
                self.image_diff = ContentFile(
                    wand_diff.make_blob('png'),
                    name='{}_{}_diff.png'.format(self.parent.id, self.id),
                )
                self.state = Screenshot.STATE_DIFFERENT
            else:
                self.state = Screenshot.STATE_MATCHING

    def archive(self):
        if self.image:
            self.image.delete(save=False)
        if self.image_diff:
            self.image_diff.delete(save=False)
        self.archived = True

    class Meta:
        unique_together = (('build', 'name'), )