Loop image generation breaks at index 16



  • Hi, I'm making custom Christmas gif postcards, everything's working until the loop reaches the 16th value of my list, I tried making them individually and it works, but when I try a for loop it gets stuck like in an infinite loop but I don't know why. Does anyone know what's happening?

    import csv
    import unicodedata
    import os
    
    def strip_accents(text):
        try:
            text = unicode(text, 'utf-8')
        except NameError: # unicode is a default on python 3 
            pass
        text = unicodedata.normalize('NFD', text)\
               .encode('ascii', 'ignore')\
               .decode("utf-8")
        return str(text)
    
    # Typeface
    canelaUnordered = []
    for font in installedFonts():
        if 'Canela' in font:
            canelaUnordered.append(font)
    canelaIndexes = [2, 3, 0, 1, 8, 9, 6, 7, 4, 5, 14, 15, 12, 13, 10, 11]
    canela = []
    for i in range(len(canelaUnordered)):
        canela.append(canelaUnordered[canelaIndexes[i]])    
    
    # Data for custom images
    data = []
    with open('./xmasList.csv', newline='', encoding='UTF-8') as data_csv:
      data_reader = csv.DictReader(data_csv,  delimiter=',', quotechar='|')
      for row in data_reader:
          if len(row['\ufeffNAME']) > 0:
              data.append(row['\ufeffNAME'])
              
    # Main copywrite
    cw = open('./xmasMessage.txt', 'r', encoding='UTF-8')
    cw = cw.read()  
              
    # Design class
    class Postcard():
        
        def __init__(self, x=1600, y=1600, m=160):
            self.x = x
            self.y = y
            self.m = m 
            self.tree = BezierPath()
            self.tree.moveTo((self.m, self.y*0.18))
            self.tree.lineTo((self.x/2, self.y *0.90))
            self.tree.lineTo((self.x - (self.m), self.y*0.18))
            self.tree.closePath()
    
        def c(self, val):
            if type(isinstance(val, (int, float))):
                if val <= 255:
                    return val / 255
                else:
                    raise Exception("Sorry, just numbers below 255")
        
        def hexToRGB(self, val):
            val = val.lstrip('#')
            lv = len(val)
            color = [int(val[i:i + lv // 3], 16) for i in range(0, lv, lv // 3)]
            r, g, b = color[0], color[1], color[2]
            return self.c(r), self.c(g), self.c(b)
        
        def copy(self, cw = cw):
            self.cw = cw
            words = self.cw.split()
            txtFillone = self.hexToRGB('#FFFFFF')
            txt = FormattedString(
                'ā€¢\n',
                font = canela[1],
                fontSize=160,
                lineHeight=200,
                fill = (txtFillone[0], txtFillone[1], txtFillone[2]),
                align = 'center'
                )
            
            txt.append('2020\n'.upper(), font=canela[1], fontSize=158, lineHeight=159)
            txt.append('Merry '.upper(), font = canela[4], fontSize=94, lineHeight=100)
            txt.append('Xmas'.upper() + '\nā€¢\n', font = canela[2])
            
            boldWords = ['holidays']
            breakWords = ['ever!']
            
            for word in words:
                txt.append('', fontSize=48, lineHeight=52, paragraphBottomSpacing=52)
                if word in boldWords:
                    txt.append(word + ' ', font = canela[13])
                elif word in breakWords:
                    txt.append(word + '\n', font = canela[13])
                else:
                    txt.append(word + ' ', font = canela[11])
                
            logo = FormattedString(
                'Sincerely eat\n',
                 align='center', font = canela[10], fontSize=80, lineHeight=180, fill=(1)
                )
                
            textBox(txt, self.tree)
            text(logo, (self.x/2, self.m))
            
        def receiver(self, tx, limit = 100):
            rFnt = canela[2]
            textSize = FormattedString(tx, font = rFnt, fontSize=1, lineHeight=1, align='center')
            rSz = 1180 / textSize.size()[0]
            if rSz > limit:
                rSz = limit
            receiver = FormattedString(tx,font=rFnt, fontSize=rSz, lineHeight=rSz, align='center', fill=(1))
            text(receiver, (self.x/2, self.y*0.20))
            stroke(2)
            strokeWidth(6)
            line((self.x*0.17, self.y*0.28), (self.x*0.83, self.y*0.28))
            
        def snow(self, copos=30, path='./snowFlake.pdf'):
            w, h = imageSize(path)
            copo = ImageObject(path)
            for i in range(copos):
                scaleFactor = randint(1, 5) * 0.1
                with savedState():
                    translate(randint(0, self.x), randint(self.y*0.12, self.y))
                    scale(scaleFactor)
                    image(copo, (-w/2, -h/2))
        
        def canvas(self, bgColor='#FF5900'):
            newPage(self.x, self.y)
        
            if type(bgColor) == list:
                self.bgColor = self.c(bgColor[0]), self.c(bgColor[1]), self.c(bgColor[2])
            elif type(bgColor) == str:
                if len(bgColor) == 7 or len(bgColor) == 4 or len(bgColor) == 6 or len(bgColor) == 3: 
                    self.bgColor = self.hexToRGB(bgColor)
                else:
                    raise Exception("Sorry, incorrect HexValue")
            else:
                raise Exception("Sorry, use one of the following formats: [r, g, b] or Hex value")
    
            fill(self.bgColor[0], self.bgColor[1], self.bgColor[2])
            rect(0, 0, self.x, self.y)
        
        def drawTree(self, deg):
            fill(0.1, 0.4, 0.3)
            stroke(0.1, 0.4, 0.3)
            strokeWidth(100)
            with savedState():
                rotate(deg, center=(self.x/2, self.y/2))
                drawPath(self.tree)
            
        def save(self, tx, user='eat', message='merryXmas2020'):
            fileName = strip_accents(tx).lower().strip().replace(' ', '_')
            saveDir = '2020_xmasCards'
            saveLoc = '/Users/{}/Desktop/'.format(user)
            if saveDir not in os.listdir(path=saveLoc):
                os.mkdir(saveLoc + saveDir)
            saveImage(saveLoc + saveDir + '/' + message + '_{}.gif'.format(fileName), imageResolution = 72)
            print(message + '_{}.gif'.format(fileName) + ' Done')
            newDrawing()
    
    def postcardGenerator(data, save=True, frames = 2):
        deg = 2
        rot = -2
        for i in range(frames): 
            card = Postcard()    
            card.canvas()
            card.drawTree(deg)
            card.snow()
            card.copy()
            card.receiver(data)
            if i == int(frames/2):
                rot *= -1
            deg += rot
        if save:
            card.save(data)
    
    # Ceate postcards
    for field in data:
        postcardGenerator(field)
    
    # testNum = 0
    # postcardGenerator(data[testNum], False)
    

    If you make the whole list with the testNum it works which makes me think that the problem is not in the external files I'm using.

    Thank you for your help!!



  • Here a handy script to generate files to test, if you use it this way you should change the following line:

    if len(row['\ufeffNAME']) > 0:
              data.append(row['\ufeffNAME'])
    

    to

    if len(row['NAME']) > 0:
              data.append(row['NAME'])
    
    import os
    import csv
    
    def fullNameGenerator():
        name = ''
        lastName = ''
        for letter in range(randint(4,10)):
            name += choice(letters)
        for letter in range(randint(4,10)):
            lastName += choice(letters)      
        fullName = name.title() + ' ' + lastName.title()
        return fullName
    
    letters = 'abcdefghijklmnopqrstuvwxyz'
    myMessage ='I wish you the best holidays ever! With All my love for you:'
    
    myPath = './'
    myDir = 'dataFiles'
    myDirPath = myPath + myDir
    if myDir not in os.listdir(myPath):
        os.mkdir(myPath + myDir)
    
    with open(myDirPath + '/xmasMessage.txt', 'w') as xmasMsg: 
        xmasMsg.write(myMessage)
        
    with open(myDirPath + '/xmasList.csv', 'w', newline='') as xmasList:
        csv_writter = csv.writer(xmasList)
        
        csv_writter.writerow(['NAME'])
        
        names = []
        for i in range(40):
            names.append([fullNameGenerator()])
    
        for row in names:
            csv_writter.writerow(row)
    

    And the snowflake pdf
    https://drive.google.com/file/d/1EZxopDsOjd-K7ur-QQm-Xc_0zj7dGPkv/view?usp=sharing

    Thanks again!!


  • admin

    it works if you don't create an ImageObject first of the snow flake.

    This is blowing your memory to moon and almost back as this will load the pdf in memory for every time you create a frame... The endless loop is different on the amount of available memory.

    If you insist to use an ImageObject try to cache it if you are reusing the same image data over and over again.

    # image(copo, (-w/2, -h/2))
    image(path, (-w/2, -h/2))
    

    happy xmass šŸ™‚



  • @frederik OMG it works now!!! thank you very much!!!! šŸ˜Š Happy holidays!!!