<commit_before><?php

namespace Difra;

final class Images {

	static function getInstance() {
		static $self = null;
		return $self ? $self : $self = new self;
	}

	/**
	 * Получение объекта из строки данных
	 * @param string|\Difra\Param\AjaxFile $data
	 * @throws Exception
	 * @return \Imagick|null
	 */
	public function data2image( $data ) {

		if( $data instanceof \Difra\Param\AjaxFile ) {
			$data = $data->val();
		} elseif( $data instanceof \Imagick ) {
			return clone $data;
		}
		try {
			$img = new \Imagick;
			$img->readImageBlob( $data );
			return $img;
		} catch( \ImagickException $ex ) {
			throw new Exception( 'Invalid image file format' );
		}
	}

	/**
	 * Получение строки данных из объекта
	 * @param \Imagick $img
	 * @param string   $type
	 * @return string mixed
	 */
	public function image2data( $img, $type = 'png' ) {

		$img->setImageFormat( $type );
		if( $img->getImageWidth() * $img->getImageHeight() > 40000 ) {
			switch( $type ) {
			case 'png':
				$img->setInterlaceScheme( \imagick::INTERLACE_PNG );
				break;
			case 'jpeg':
				$img->setInterlaceScheme( \imagick::INTERLACE_JPEG );
				break;
			}
		}
		return $img->getImageBlob();
	}

	/**
	 * Перевод строки данных в другой формат
	 * @param string $data
	 * @param string $type
	 * @return bool|string
	 */
	public function convert( $data, $type = 'png' ) {

		$img = $this->data2image( $data );
		return $img ? $this->image2data( $img, $type ) : false;
	}

	/**
	 * Resizes image from binary string to given resolution keeping aspect ratio
	 *
	 * @param string|\Difra\Param\AjaxFile $data		binary string with image in it
	 * @param int                          $maxWidth        maximum height of thumbnail
	 * @param int                          $maxHeight       maximum width of thumbnail
	 * @param string                       $type		resulting image type
	 *
	 * @return string
	 */
	public function createThumbnail( $data, $maxWidth, $maxHeight, $type = 'png' ) {

		$img = $this->data2image( $data );

		$img->resizeImage( $maxWidth, $maxHeight, \Imagick::FILTER_LANCZOS, 0.9, false );
		return $this->image2data( $img, $type );
	}

	/**
	 * Resizes image from binary string to given resolution keeping aspect ratio
	 *
	 * @param string $data                    binary string with image in it
	 * @param int    $maxWidth		  maximum width of thumbnail
	 * @param int    $maxHeight               maximum height of thumbnail
	 * @param string $type                    resulting image type
	 *
	 * @return string
	 */
	public function scaleAndCrop( $data, $maxWidth, $maxHeight, $type = 'png' ) {

		$img = $this->data2image( $data );
		$img->cropThumbnailImage( $maxWidth, $maxHeight );
		return $this->image2data( $img, $type );
	}

}

<commit_msg>Fix бага, приводившего к обрезанию краёв при использовании Images->createThumbnail(), попытка 2: ручное вычисление новых размеров картинки.<commit_after><?php

namespace Difra;

final class Images {

	static function getInstance() {
		static $self = null;
		return $self ? $self : $self = new self;
	}

	/**
	 * Получение объекта из строки данных
	 * @param string|\Difra\Param\AjaxFile $data
	 * @throws Exception
	 * @return \Imagick|null
	 */
	public function data2image( $data ) {

		if( $data instanceof \Difra\Param\AjaxFile ) {
			$data = $data->val();
		} elseif( $data instanceof \Imagick ) {
			return clone $data;
		}
		try {
			$img = new \Imagick;
			$img->readImageBlob( $data );
			return $img;
		} catch( \ImagickException $ex ) {
			throw new Exception( 'Invalid image file format' );
		}
	}

	/**
	 * Получение строки данных из объекта
	 * @param \Imagick $img
	 * @param string   $type
	 * @return string mixed
	 */
	public function image2data( $img, $type = 'png' ) {

		$img->setImageFormat( $type );
		if( $img->getImageWidth() * $img->getImageHeight() > 40000 ) {
			switch( $type ) {
			case 'png':
				$img->setInterlaceScheme( \imagick::INTERLACE_PNG );
				break;
			case 'jpeg':
				$img->setInterlaceScheme( \imagick::INTERLACE_JPEG );
				break;
			}
		}
		return $img->getImageBlob();
	}

	/**
	 * Перевод строки данных в другой формат
	 * @param string $data
	 * @param string $type
	 * @return bool|string
	 */
	public function convert( $data, $type = 'png' ) {

		$img = $this->data2image( $data );
		return $img ? $this->image2data( $img, $type ) : false;
	}

	/**
	 * Resizes image from binary string to given resolution keeping aspect ratio
	 *
	 * @param string|\Difra\Param\AjaxFile $data		binary string with image in it
	 * @param int                          $maxWidth        maximum height of thumbnail
	 * @param int                          $maxHeight       maximum width of thumbnail
	 * @param string                       $type		resulting image type
	 *
	 * @return string
	 */
	public function createThumbnail( $data, $maxWidth, $maxHeight, $type = 'png' ) {

		$img = $this->data2image( $data );
		if( $maxWidth < ( $w = $img->getimagewidth() ) or $maxHeight < ( $h = $img->getimageheight() ) ) {
			if( $w / $maxWidth > $h / $maxHeight ) {
				$nw = $maxWidth;
				$nh = round( $h * $maxWidth / $w );
			} else {
				$nh = $maxHeight;
				$nw = round( $w * $maxHeight / $h );
			}
			$img->resizeImage( $nw, $nh, \Imagick::FILTER_LANCZOS, 0.9, true );
		}
		return $this->image2data( $img, $type );
	}

	/**
	 * Resizes image from binary string to given resolution keeping aspect ratio
	 *
	 * @param string $data                    binary string with image in it
	 * @param int    $maxWidth		  maximum width of thumbnail
	 * @param int    $maxHeight               maximum height of thumbnail
	 * @param string $type                    resulting image type
	 *
	 * @return string
	 */
	public function scaleAndCrop( $data, $maxWidth, $maxHeight, $type = 'png' ) {

		$img = $this->data2image( $data );
		$img->cropThumbnailImage( $maxWidth, $maxHeight );
		return $this->image2data( $img, $type );
	}

}


{'fraction_non_alphanumeric': 0.13591740013540962, 'fraction_numerical': 0.005247122545700745, 'mean_word_length': 2.7163522012578616, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '184517', 'n_tokens_mistral': 2185, 'n_tokens_neox': 1986, 'n_words': 557}