예제 #1
0
 def addWebEntityImage(self, image_url):
     utils.log("downloading '%s'" % image_url)
     
     image    = utils.getWebImage(image_url)
     suffix   = os.path.basename(image_url)
     filename = "entities/%s" % suffix
     
     return self.addImage(filename, image)
예제 #2
0
    def addResizedProfileImages(self, screen_name, image_url):
        # Filename is lowercase screen name
        prefix = 'users/%s' % screen_name.lower()

        # Retry getting web image multiple times in case of bad connection
        num_retries = 0
        max_retries = 5

        while True:
            try:
                image = utils.getWebImage(image_url, "profile")
                break
            except urllib2.HTTPError as e:
                logs.warning('Get web image exception: %s' % e)
                num_retries += 1
                if num_retries > max_retries:
                    msg = "Unable to connect to get web image after %d retries (%s)" % (max_retries, image_url)
                    logs.warning(msg)
                    raise 
                
                logs.info("Retrying (%s)" % (num_retries))
                time.sleep(30)

        if image.format not in ('JPEG', 'PNG'):
            logs.warning("Cannot add a profile image of format '%s', only JPEG or PNG")
            return

        sizes    = self.profileImageSizes
        max_size = self.profileImageMaxSize

        def cropImageToSquare(image):
            width, height = image.size

            if width != height:
                # Extract a square aspect ratio image by cropping the longer side
                diff = abs(height - width) / 2

                if width > height:
                    box = (diff, 0, width - diff, height)
                else:
                    box = (0, diff, width, height - diff)

                square = image.crop(box)
            else:
                # image is already square
                square = image
            return square


        image = cropImageToSquare(image)
        self._addImageSizes(prefix, image, max_size, sizes, original_url=image_url)
예제 #3
0
 def generate_from_user(self, user, entities):
     cluster = self.get_clusters(entities) #, limit=max(10, int(.8 * len(entities))))
     markers = '%7C'.join("%s,%s" % pt for pt in cluster['data'])
     images  = []
     API_KEY = "AIzaSyAxgU3LPU-m5PI7Jh7YTYYKAz6lV6bz2ok"
     bounds  = ""
     
     # TODO: test specific center + zoom depending on #markers
     
     if len(cluster['data']) > 4:
         bounds = "center=%s,%s&zoom=%d&" % (cluster['avg'][0], cluster['avg'][1], 14)
     
     for size in self._sizes:
         map_url = "https://maps.googleapis.com/maps/api/staticmap?sensor=false&scale=1&format=jpg&maptype=roadmap&size=%dx%d&%smarkers=%s&key=%s" % (size[0], size[1], bounds, markers, API_KEY)
         image   = utils.getWebImage(map_url)
         
         image   = self._apply_postprocessing(image, user)
         images.append(image)
     
     return images
예제 #4
0
    def createInstagramImage(self, entity_img_url, user_generated, coordinates, primary_color, secondary_color,
                             user_name, category, types, title, subtitle):
        def dropShadow(image, rounded, offset=(5,5), background=0xffffff, shadow=0x444444,
                       border=8, iterations=3):
            """
            Add a gaussian blur drop shadow to an image.

            image       - The image to overlay on top of the shadow.
            offset      - Offset of the shadow from the image as an (x,y) tuple.  Can be
                          positive or negative.
            background  - Background colour behind the image.
            shadow      - Shadow colour (darkness).
            border      - Width of the border around the image.  This must be wide
                          enough to account for the blurring of the shadow.
            iterations  - Number of times to apply the filter.  More iterations
                          produce a more blurred shadow, but increase processing time.
            """

            # Create the backdrop image -- a box in the background colour with a
            # shadow on it.
            totalWidth = image.size[0] + abs(offset[0]) + 2*border
            totalHeight = image.size[1] + abs(offset[1]) + 2*border
            back = Image.new('RGB', (totalWidth, totalHeight), background)
            if rounded:
                roundedsquare = Image.open(self.__basepath + 'roundedsquare.png')
                roundedsquare = roundedsquare.resize((totalWidth, totalHeight), Image.ANTIALIAS)
                roundedsquare.paste(back, (0, 0), roundedsquare)
                back = roundedsquare

            # Place the shadow, taking into account the offset from the image
            shadowLeft = border + max(offset[0], 0)
            shadowTop = border + max(offset[1], 0)
            back.paste(shadow, (shadowLeft, shadowTop, shadowLeft + image.size[0],
                                shadowTop + image.size[1]) )

            # Apply the filter to blur the edges of the shadow.  Since a small kernel
            # is used, the filter must be applied repeatedly to get a decent blur.
            n = 0
            while n < iterations:
                back = back.filter(ImageFilter.BLUR)
                n += 1

            # Paste the input image onto the shadow backdrop
            imageLeft = border - min(offset[0], 0)
            imageTop = border - min(offset[1], 0)
            #back.paste(image, (imageLeft, imageTop))

            return back

        def fitImg(entityImg, width, height):
            aspect_ratio = width/float(height)
            w, h = entityImg.size
            print("aspect ratio: %s   w/h:%s" % (aspect_ratio, w/float(h)))

            print( w/float(h))

            if w/float(h) >= aspect_ratio:
                new_height = int( h / (w/float(width)))
                print ('width: %s  new_height: %s' % (width, new_height))
                return entityImg.resize((width, new_height), Image.ANTIALIAS)
            else:
                new_width = int( w / (h/float(height)))
                print ('new_width: %s  height: %s' % (new_width, height))
                return entityImg.resize((new_width, height), Image.ANTIALIAS)

        def transformEntityImage(entityImg, stampImg, rounded, pin, a,b,c,d,e,f,g,h, x, y):
            origAlbumSize = entityImg.size
            xResize = float(origAlbumSize[0])/600
            entityImg = entityImg.resize((600, int(origAlbumSize[1]/xResize)), Image.ANTIALIAS)
            entityImgSize = entityImg.size

            #            draw = ImageDraw.Draw(entityImg)
            #            draw.line((entityImg.size[0]/2, 0, entityImg.size[0]/2, entityImg.size[1]), fill='#000000')
            #            draw.line((0, entityImg.size[1]/2, entityImg.size[0], entityImg.size[1]/2), fill='#000000')
            if rounded:
                buf = Image.new('RGBA', entityImgSize, (255,255,255,0))
                #buf2 = Image.new('RGBA', shadowSize, (255,255,255,0))
                roundedsquare = Image.open(self.__basepath + 'roundedsquare.png')
                entityImg = entityImg.resize((600,600), Image.ANTIALIAS)
                #shadow = shadow.resize((600,600), Image.ANTIALIAS)
                #roundedEntitySquare = roundedsquare.resize(entityImgSize, Image.ANTIALIAS)
                #roundedShadowSquare = roundedsquare.resize(shadowSize, Image.ANTIALIAS)
                buf.paste(entityImg, (0,0), roundedsquare)
                #buf2.paste(shadow, (0,0), roundedsquare)
                entityImg = buf
                #shadow = buf2
            shadow = dropShadow(entityImg, False, background=0xffffff, shadow=0xd0d0d0, offset=(0,0), border=20)#.show()
            shadowSize = shadow.size

            adjust = (((entityImgSize[1]/float(entityImgSize[0]))-1.0) * 0.2) + 1.0

            a = (a*adjust)/2
            b = (b*adjust)/2
            d = (d*adjust)/2
            e = (e*adjust)/2
            g = (g*adjust)/2
            h = (h*adjust)/2

            mode = "RGBA"
            size = 612, 612
            size2x = 612*2, 612*2
            shadowsize2x = 660*2, 660*2
            shadowOffset = x, y

            buf2 = Image.new(mode, size2x, (255,255,255,255))

            mask = Image.new('1', entityImgSize, 1)
            shadowmask = Image.new('1', shadowSize, 1)

            stampImg = stampImg.transform(size2x, Image.PERSPECTIVE, (a,-2.30/2,c,1.006/2,e,f,g,h), Image.BICUBIC)
            entityImg = entityImg.transform(size2x, Image.PERSPECTIVE, (a,b,c,d,e,f,g,h), Image.BICUBIC)
            shadow = shadow.transform(shadowsize2x, Image.PERSPECTIVE,(a,b,c,d,e,f,g,h), Image.BICUBIC)
            mask = mask.transform(size2x, Image.PERSPECTIVE, (a,b,c,d,e,f,g,h), Image.BICUBIC)
            shadowmask = shadowmask.transform(shadowsize2x, Image.PERSPECTIVE, (a,b,c,d,e,f,g,h), Image.BICUBIC)

            stampImg = stampImg.filter(ImageFilter.GaussianBlur)
            stampImg = stampImg.resize((1000,1000), Image.ANTIALIAS)
            if not rounded:
                buf2.paste(shadow, shadowOffset, shadowmask)
            buf2.paste(entityImg, (0, 0), mask)
            buf2.paste(stampImg, (412,-100), stampImg)
            entityImg = buf2.resize(size, Image.ANTIALIAS)

            #            if pin:
            #                pinImg = Image.open(self.__basepath + 'pin.png')
            #                entityImg.paste(pinImg, (278,200), pinImg)

            return entityImg

        def getCategoryIcon(category):
            categoryIcons = Image.open(self.__basepath + 'categoryicons18px.png')
            #icon = Image.new('RGBA', (18,18), (255,255,255,0))

            categories = ('restaurant', 'bar', 'cafe', 'place', 'album', 'song', 'artist', 'film', 'tv_show',
                          'book', 'software', 'other')
            if category not in categories:
                categoryIndex = len(categories)-1
            else:
                categoryIndex = categories.index(category)
            print categoryIndex

            icon = ImageChops.offset(categoryIcons, -20*categoryIndex, 20)
            icon = icon.crop((0, 0, 18, 18))
            #icon.paste(categoryIcons, (20*categoryIndex, 20, (20*categoryIndex)+18, 38))
            return icon

        def getInstagramTextImg(user_name, category, types, title, subtitle):
            textImg = Image.new('RGBA', (612*2,195*2), (255,255,255,255))
            draw = ImageDraw.Draw(textImg)
            titling_gothic = ImageFont.truetype(self.__basepath +"TitlingGothicFB.ttf", 80*2)
            helvetica_neue_bold = ImageFont.truetype(self.__basepath +"HelveticaNeue-Bold.ttf", 24*2)
            helvetica_neue = ImageFont.truetype(self.__basepath + "HelveticaNeue.ttf", 24*2)
            header_nameW, header_nameH = draw.textsize(user_name, font=helvetica_neue_bold)

            prefix = 'a'
            if len(set(types).intersection(set(['establishment', 'app', 'album', 'artist', 'app']))) > 0:
                prefix = 'an'
            type = types[0].replace('_', ' ')
            if type == 'tv':
                type = 'TV show'


            header = ' stamped %s %s' % (prefix, type)
            headerW, headerH = draw.textsize(header, font=helvetica_neue)

            # truncate title text if necessary.  Allow ten pixels of padding on each side and append ellipsis
            final_title = title
            while True:
                titleW, titleH = draw.textsize(final_title, font=titling_gothic)
                if titleW > (612-20)*2:
                    final_title = final_title[:-2] + u"\u2026"
                    continue
                break
            subtitleW, subtitleH = draw.textsize(subtitle, font=helvetica_neue)

            draw.text((612-((headerW+header_nameW)/2),0), user_name, font=helvetica_neue_bold, fill='#939393')
            draw.text((612-((headerW+header_nameW)/2)+header_nameW,0), header, font=helvetica_neue, fill='#939393')
            draw.text((612-(titleW/2),40*2), final_title, font=titling_gothic, fill='#000000')
            draw.line((165*2, 134*2, (612-165)*2, 134*2), fill='#e0e0e0')
            draw.text(((612*2/2)-(subtitleW/2),(134+20)*2), subtitle, font=helvetica_neue, fill='#939393')
            del draw
            textImg = textImg.resize((612, 195), Image.ANTIALIAS)
            icon = getCategoryIcon(category)
            textImg.paste(icon, ((612/2)-(18/2), 124))
            return textImg

        masks = [
            (270, 270, self.__basepath + 'stamp_mask.png'),
            (612,  9,  self.__basepath + 'ribbon-top.png'),
            (612,  9,  self.__basepath + 'ribbon-bottom.png'),
        ]

        gradientImgs = [self.__imageDB.generate_gradient_images(primary_color, secondary_color, x[0], x[1], x[2])
                        for x in masks]
        stamp = gradientImgs[0]
        ribbon_top = gradientImgs[1]
        ribbon_bot = gradientImgs[2]
        shadow_top = Image.open(self.__basepath + 'shadow-top.png')
        shadow_bot = shadow_top.transpose(Image.FLIP_TOP_BOTTOM)

        a =  1.77
        b =  -1.61
        c =  298
        d =  1.074
        e =  4.11
        f =  -820
        g =  -0.0001
        h =  0.00215
        x = -44
        y = 1

        size = 612,612
        img = Image.new('RGBA', size, (255,255,255,255))

        if coordinates is not None and user_generated == False:
            entity_img_url = "https://maps.googleapis.com/maps/api/staticmap?center=%s&zoom=18&sensor=false&scale=1&format=png&maptype=roadmap&size=600x600&key=AIzaSyAEjlMEfxmlCBQeyw_82jjobQAFjYx-Las" % coordinates

        if entity_img_url is not None:
            #entityImg = Image.open(entity_img_url)
            entityImg = utils.getWebImage(entity_img_url)
            if user_generated:
                boxW = 612
                boxH = 612-195-40-30
                entityImg = fitImg(entityImg, boxW, boxH)
                w, h = entityImg.size
                offsetX = (boxW - w)/2
                offsetY = (boxH - h)/2 + 195+40
                img.paste(entityImg, (offsetX, offsetY))
            else:
                entityImg = transformEntityImage(entityImg, stamp, 'app' in types, coordinates is not None,
                    a,b,c,d,e,f,g,h,x,y)
                img.paste(entityImg, (7,166))
        else:
            pass
        textImg = getInstagramTextImg(user_name, category, types, title, subtitle)
        img.paste(textImg, (0, 40), textImg)
        img.paste(ribbon_top, (0, 0))
        img.paste(shadow_top, (0, ribbon_top.size[1]))
        img.paste(ribbon_bot, (0, 612-ribbon_bot.size[1]))
        img.paste(shadow_bot, (0, 612-ribbon_top.size[1]-shadow_bot.size[1]), shadow_bot)

        return img
예제 #5
0
    def addResizedStampImages(self, sourceUrl, imageId, maxSize, sizes):
        image    = utils.getWebImage(sourceUrl, "stamp")
        prefix   = 'stamps/%s' % imageId

        return self._addImageSizes(prefix, image, maxSize, sizes, original_url=sourceUrl)
예제 #6
0
    def _create_collage(
        self,
        user,
        images,
        num_rows=None,
        num_cols=None,
        respect_aspect_ratio=False,
        adaptive_image_resizing=True,
        enable_drop_shadows=False,
        row_major=True,
        shuffle_images=False,
    ):

        # must specify num_cols or num_rows, but not both
        assert (num_cols is not None and num_cols > 0) != (num_rows is not None and num_rows > 0)

        num_images = len(images)
        output = []

        if num_rows is None:
            num_cols = int(num_cols)
            num_rows = int(math.ceil(num_images / num_cols))
        elif num_cols is None:
            num_rows = int(num_rows)
            num_cols = int(math.ceil(num_images / num_rows))

        user_logo_url = "http://static.stamped.com/logos/%s-%s-email-36x36.png" % (
            user.color_primary,
            user.color_secondary,
        )
        try:
            user_logo = utils.getWebImage(user_logo_url)
        except Exception:
            user_logo = None

        user_logo_cache = {}

        def get_user_logo(size):
            if user_logo is None:
                return None

            try:
                return user_logo_cache[size]
            except KeyError:
                logo = user_logo.resize(size, Image.ANTIALIAS)
                user_logo_cache[size] = logo

                return logo

        for size in self._sizes:
            logs.info("[%s] creating %sx%s collage" % (self, size[0], size[1]))

            canvas = Image.new("RGBA", size, (255, 255, 255, 255))
            offsets = []
            indices = []

            if row_major:
                for i in xrange(num_rows):
                    for j in xrange(num_cols):
                        indices.append(len(offsets))
                        offsets.append((i, j))
            else:
                for j in xrange(num_cols):
                    for i in xrange(num_rows):
                        indices.append(len(offsets))
                        offsets.append((i, j))

            if shuffle_images:
                indices = utils.shuffle(indices)

            for index in indices:
                i, j = offsets[index]

                # wrap images around if necessary to fill last row
                index = (i * num_cols + j) % num_images
                image = images[index]

                cell_size, cell_pos, logo_size, logo_pos = self.get_cell_bounds_func(
                    size, num_cols, num_rows, i, j, image
                )

                # adjust cell layout bounds to align to integer grid (helps minimize aliasing)
                cell_size = int(math.ceil(cell_size[0])), int(math.ceil(cell_size[1]))
                cell_pos = int(math.floor(cell_pos[0])), int(math.floor(cell_pos[1]))

                logo_size = int(math.ceil(logo_size[0])), int(math.ceil(logo_size[1]))
                logo_pos = int(math.floor(logo_pos[0])), int(math.floor(logo_pos[1]))

                width = cell_size[0]
                height = cell_size[1]

                if adaptive_image_resizing:
                    if image.size[0] / cell_size[0] < image.size[1] / cell_size[1]:
                        width = cell_size[0]
                        height = (width * image.size[1]) / image.size[0]

                        if not respect_aspect_ratio and height > cell_size[1]:
                            height = int((height + cell_size[1]) * 0.5)
                    else:
                        height = cell_size[1]
                        width = (height * image.size[0]) / image.size[1]

                        if not respect_aspect_ratio and width > cell_size[0]:
                            width = int((width + cell_size[0]) * 0.5)

                cell = image.resize((width, height), Image.ANTIALIAS)
                w = min(width, cell_size[0])
                h = min(height, cell_size[1])
                cell = cell.crop((0, 0, w, h))

                if enable_drop_shadows:
                    self._paste_image_with_drop_shadow(canvas, cell, cell_pos)
                else:
                    canvas.paste(cell, cell_pos)

                # overlay user's stamp logo on top of each entity image
                logo = get_user_logo(logo_size)

                if logo is not None:
                    logo_box = (logo_pos[0], logo_pos[1], logo_pos[0] + logo.size[0], logo_pos[1] + logo.size[1])
                    canvas.paste(logo, logo_box, logo)

            canvas = self._apply_postprocessing(canvas, user)
            output.append(canvas)

        return output
예제 #7
0
    def _get_image(self, image_url):
        logs.info("downloading '%s'" % image_url)

        return utils.getWebImage(image_url, "collage")