Вход Регистрация
Файл: vendor/visavi/captcha/src/GifEncoder.php
Строк: 91
<?php

declare(strict_types=1);

namespace 
VisaviCaptcha;

use 
RuntimeException;

class 
GifEncoder
{
    
/* GIF header 6 bytes */
    
private string $gif = 'GIF89a';
    private array 
$buf = [];
    private 
bool $first = true;
    private 
int $lop;
    private 
int $dis;

    
/**
     * GIF encoder
     *
     * @param array $frames Binary contents of the source gif images
     * @param array $delays Frame delays, in hundredths of a second
     * @param int   $lop    Loop count, 0 means forever
     * @param int   $dis    Disposal method
     *
     * @throws RuntimeException
     */
    
public function __construct(array $frames, array $delays, int $lop, int $dis)
    {
        
$this->lop = max($lop, 0);
        
$this->dis = ($dis > -1) ? min($dis, 3) : 2;

        foreach (
$frames as $i => $frame) {
            if (! 
str_starts_with($frame, 'GIF87a') && ! str_starts_with($frame, 'GIF89a')) {
                throw new 
RuntimeException(sprintf('%s (%d source)', 'Source is not a GIF image!', $i));
            }

            
$this->assertNotAnimated($frame, $i);

            
$this->buf[] = $frame;
        }

        
$this->addHeader();

        foreach (
$this->buf as $i => $frame) {
            
$this->addFrames($i, $delays[$i] ?? 0);
        }

        
$this->addFooter();
    }

    
/**
     * Reject sources that are animated themselves
     *
     * @throws RuntimeException
     */
    
private function assertNotAnimated(string $frame, int $i): void
    
{
        
$length = strlen($frame);

        for (
$j = 13 + 3 * (2 << (ord($frame[10]) & 0x07)); $j < $length; $j++) {
            if (
$frame[$j] === ';') {
                return;
            }

            if (
$frame[$j] === '!' && substr($frame, $j + 3, 8) === 'NETSCAPE') {
                throw new 
RuntimeException(sprintf(
                    
'%s (%d source)',
                    
'Does not make animation from animated GIF source!',
                    
$i + 1
                
));
            }
        }
    }

    
/**
     * Add header
     */
    
private function addHeader(): void
    
{
        if (
ord($this->buf[0][10]) & 0x80) {
            
$cmap = 3 * (2 << (ord($this->buf[0][10]) & 0x07));
            
$this->gif .= substr($this->buf[0], 6, 7);
            
$this->gif .= substr($this->buf[0], 13, $cmap);
            
$this->gif .= "!37713NETSCAPE2.031";
            
$this->gif .= chr($this->lop & 0xFF) . chr(($this->lop >> 8) & 0xFF) . "";
        }
    }

    
/**
     * Add frames
     */
    
private function addFrames(int $i, int $d): void
    
{
        
$localStr = 13 + 3 * (2 << (ord($this->buf[$i][10]) & 0x07));
        
$localEnd = strlen($this->buf[$i]) - $localStr - 1;
        
$localTmp = substr($this->buf[$i], $localStr, $localEnd);
        
$globalLen = 2 << (ord($this->buf[0][10]) & 0x07);
        
$localLen = 2 << (ord($this->buf[$i][10]) & 0x07);
        
$globalRgb = substr($this->buf[0], 13, 3 * $globalLen);
        
$localRgb = substr($this->buf[$i], 13, 3 * $localLen);
        
$localExt = "!xF9x04" . chr($this->dis << 2) . chr(($d >> 0) & 0xFF) . chr(($d >> 8) & 0xFF) . "x0x0";

        switch (
$localTmp[0]) {
            case 
'!':
                
$localImg = substr($localTmp, 8, 10);
                
$localTmp = substr($localTmp, 18);
                break;
            case 
',':
                
$localImg = substr($localTmp, 0, 10);
                
$localTmp = substr($localTmp, 10);
                break;
            default:
                
$localImg = $localTmp;
        }

        
// The first frame is described by the global color table written in the header
        
$samePalette = $globalLen === $localLen && $this->blockCompare($globalRgb, $localRgb, $globalLen);

        if (
$this->first || $samePalette || ! (ord($this->buf[$i][10]) & 0x80)) {
            
$this->gif .= $localExt . $localImg . $localTmp;
        } else {
            
// Frame palette differs from the global one, so keep it as a local color table
            
$byte = ord($localImg[9]);
            
$byte |= 0x80;
            
$byte &= 0xF8;
            
$byte |= (ord($this->buf[$i][10]) & 0x07);
            
$localImg[9] = chr($byte);

            
$this->gif .= $localExt . $localImg . $localRgb . $localTmp;
        }

        
$this->first = false;
    }

    
/**
     * Add footer
     */
    
private function addFooter(): void
    
{
        
$this->gif .= ';';
    }

    
/**
     * Block compare
     */
    
private function blockCompare(string $globalBlock, string $localBlock, int $len): bool
    
{
        for (
$i = 0; $i < $len; $i++) {
            if (
                
$globalBlock[3 * $i + 0] !== $localBlock[3 * $i + 0]
                || 
$globalBlock[3 * $i + 1] !== $localBlock[3 * $i + 1]
                || 
$globalBlock[3 * $i + 2] !== $localBlock[3 * $i + 2]
            ) {
                return 
false;
            }
        }

        return 
true;
    }

    
/**
     * Get animation
     */
    
public function getAnimation(): string
    
{
        return 
$this->gif;
    }
}
Онлайн: 2
Реклама