Ejemplo n.º 1
0
    def renderCaptcha(self, cpath='', solpath='', cname=None):
        ''' Generate one captcha set (captcha image + solution mask) '''

        # == INIT
        # Position the reference image (clickable model-only image) to the left or to the right? (this adds more complexity for bots)
        rightorleft = random.random()
        # Generate a random name, unless it was specified otherwise
        if not cname:
            cname = "%s" % self.randomID()

        # Generating a 3D scene
        w = self.world
        w.generateScene()

        # == GENERATING CAPTCHA SOLUTION MASK
        # Render and save clickable mask
        #w.renderClickableArea() # Already rendered just after the generation of the world
        imgMask = w.renderToPNM()
        if rightorleft < 0.5:
            imgMask.expandBorder(left=imgMask.getReadXSize(), right=0, bottom=0, top=0, color=(0,0,0,1))
        else:
            imgMask.expandBorder(left=0, right=imgMask.getReadXSize(), bottom=0, top=0, color=(0,0,0,1))

        # Save the solution mask as a PNG then RLE
        # TODO find a way to convert from PNMImage to RLE directly in-memory without saving it to a file
        pngpath = os.path.join(cpath, "%s.png" % cname)
        imgMask.write(pngpath) # save image as png to avoid losing information (important since it's the solution mask!)
        imgMask.clear() # freeing memory
        #w.renderAndSave('testmask.png')

        # Convert PNG to RLE
        rle = RLEImage()
        rle.convertImageToRLE(pngpath, os.path.join(cpath, "%s.rle" % cname))
        del rle # freeing memory

        if not self.debug and not self.debugPng:
            os.remove(pngpath) # delete the png, not needed and it frees some space

        # == GENERATING CAPTCHA QUESTION
        # Render and save captcha image (the one that will be presented to the user)

        # First we generate the whole captcha scene (where the user will have to click)
        w.renderReset()
        img1 = w.renderToPNM()
        # Second, we generate the reference model alone so that the user know what he has to look for
        w.renderClickableModel(self.showRefModel, self.showRefName)
        img2 = w.renderToPNM()

        # Place the reference image randomly at the right side or at the left side (to confuse bots a little bit more)
        if rightorleft < 0.5:
            img1.expandBorder(left=img2.getReadXSize(), right=0, bottom=0, top=0, color=(0,0,0,1)) # resizing the first image to the size of two images (reference image + whole scene image)
            img1.copySubImage(img2, 0, 0) # copying reference image onto the first one, side by side
        else:
            img1.expandBorder(left=0, right=img2.getReadXSize(), bottom=0, top=0, color=(0,0,0,1))
            img1.copySubImage(img2, img2.getReadXSize(), 0)

        # Saving final image
        # First step: we save the jpg image
        jpgpath = os.path.join(solpath, "%s.jpg" % cname)
        img1.write( jpgpath ) # save image (using jpg will add even more complexity for bots, because JPEG is a lossy image compression using psycho-human optimization: lossy + adapted to human = worst for bots) TODO: add a parameter to adjust the JPEG quality and loss

        img2.clear() # freeing memory
        img1.clear() # freeing memory

        # Second step: reload the jpg in PIL and resave with a different quality (because Panda3D doesn't allow to set jpg quality)
        # This is important: saving with a lower quality reduce bandwidth but also raise the difficulty for the bots
        img = Image.open(jpgpath, 'r')
        img.save(jpgpath, quality = self.jpgquality, optimize=False, progressive=True) # Optimize does an extra pass. Not needed here: we don't want to optimize for bots.
        del img # freeing memory

        if self.debug:
            w.base.run() # if debug mode enabled, we show a window with the world we have just generated

        return cname # return the ID of the generated captcha
Ejemplo n.º 2
0
 def checkSolution(self, solpath, name, x, y):
     ''' Check if a Captcha response is correct '''
     rle = RLEImage()
     result = rle.openAndCheck( os.path.join(solpath, "%s.rle" % name) , x, y)
     del rle
     return result