How to crop a image to a specified size

Hello, I’m a newer Tree.js, I have a very difficult problem that has taken a long time to solve. I need your help.

I want to put pictures of any size in a fixed size (100 * 150) area, but I don’t know how to do. The code I now implement is as follows:

<!DOCTYPE html>
<html lang="en">
<head>
	<title>three.js webgl - KTX2 texture loader</title>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
	<link type="text/css" rel="stylesheet" href="main.css">
</head>
<body>

<!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported -->
<script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script>

<script type="importmap">
			{
				"imports": {
					"three": "../build/three.module.js",
					"three/addons/": "./jsm/",
					"three-text2d": "../node_modules/three-text2d/tr"
				}
			}

</script>

<script type="module">

	import * as THREE from 'three';
	import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

	const width = window.innerWidth;
	const height = window.innerHeight;

	const renderer = new THREE.WebGLRenderer( { antialias: true } );
	renderer.setSize( width, height );
	renderer.outputEncoding = THREE.sRGBEncoding;
	document.body.appendChild( renderer.domElement );

	const scene = new THREE.Scene();
	scene.background = new THREE.Color( 'rgba(59,130,246,0.5)' );

	const camera = new THREE.PerspectiveCamera( 60, width / height, 0.1, 100 );
	camera.position.set( 2, 1.5, 1 );
	camera.lookAt( scene.position );
	scene.add( camera );

	const controls = new OrbitControls( camera, renderer.domElement );
	controls.autoRotate = true;

	animate();

	try {
		const width = 100;
		const height = 150;
		
		const imageLoader = new THREE.ImageLoader();
		imageLoader.load( 'textures/images/3.png', image => {
			const canvas = document.createElement( 'canvas' );
			const context = canvas.getContext( '2d' );
			
			const imgRect = coverImg( width, height, image.width, image.height );
			context.drawImage( image, imgRect.sx, imgRect.sy, imgRect.sWidth, imgRect.sHeight, 0, 0, width, height );

			const geometry = new THREE.PlaneGeometry( width, height );
			const material = new THREE.MeshBasicMaterial( {} );
			const mesh = new THREE.Mesh( geometry, material );
			const texture = new THREE.CanvasTexture( canvas );
			texture.encoding = THREE.sRGBEncoding;
			material.map = texture;
			material.needsUpdate = true;
			material.transparent = true;
			
			mesh.scale.set(1/width,1/height,1);
			mesh.position.set( 0, 0, 0.01 );
			scene.add( mesh );
		} );
	} catch (e) {
		console.error( e );
	}


	function coverImg( box_w, box_h, source_w, source_h ) {
		var sx = 0,
				sy = 0,
				sWidth = source_w,
				sHeight = source_h;
		if (source_w > source_h || ( source_w == source_h && box_w < box_h )) {
			sWidth = box_w * sHeight / box_h;
			sx = ( source_w - sWidth ) / 2;
		} else if (source_w < source_h || ( source_w == source_h && box_w > box_h )) {
			sHeight = box_h * sWidth / box_w;
			sy = ( source_h - sHeight ) / 2;
		}
		return {
			sx,
			sy,
			sWidth,
			sHeight
		};
	}

	function getSize( model ) {
		const box = new THREE.Box3().setFromObject( model );
		const size = box.getSize( new THREE.Vector3() );
		console.log( 'size=', size );
	}

	function animate() {

		requestAnimationFrame( animate );

		controls.update();

		renderer.render( scene, camera );

	}

	window.addEventListener( 'resize', onWindowResize );

	function onWindowResize() {

		const width = window.innerWidth;
		const height = window.innerHeight;

		camera.aspect = width / height;
		camera.updateProjectionMatrix();
		renderer.setSize( width, height );

	}

</script>

</body>
</html>

They key code is here:

try {
		const width = 100;
		const height = 150;

		const imageLoader = new THREE.ImageLoader();
		imageLoader.load( 'textures/images/3.png', image => {
			const canvas = document.createElement( 'canvas' );
			const context = canvas.getContext( '2d' );

			const imgRect = coverImg( width, height, image.width, image.height );
			context.drawImage( image, imgRect.sx, imgRect.sy, imgRect.sWidth, imgRect.sHeight, 0, 0, width, height );

			const geometry = new THREE.PlaneGeometry( width, height );
			const material = new THREE.MeshBasicMaterial( {} );
			const mesh = new THREE.Mesh( geometry, material );
			const texture = new THREE.CanvasTexture( canvas );
			texture.encoding = THREE.sRGBEncoding;
			material.map = texture;
			material.needsUpdate = true;
			material.transparent = true;

			mesh.scale.set(1/width,1/height,1);
			mesh.position.set( 0, 0, 0.01 );
			scene.add( mesh );
		} );
	} catch (e) {
		console.error( e );
	}

I feel that my code is too complicated and the direction is wrong. Thank you very much for your help.

I suggest you use similar resize logic like three.js uses inside the renderer:

1 Like

A good toturial :grinning:,I will try it later,thx!