php-neuling: JavaScript + GD - Animation, Bild rotieren

Beitrag lesen

hallo,

wie drehe/rotiere ich ein img-element mit js/php?

habe bisher ohne erfolg nach einer guten möglichkeit gesucht, ein bild zu drehen.
das neue canvas-element ist toll, allerdings machen die alten IEs da ein strich durch die rechnung.
man kann natürlich für jeden drehungsschritt ein eigenes bild mit photoshop, gimp o.ä. erzeugen und dann per js die src ändern. aber vorgestern bin ich über die imagerotate-funktion der gd-lib gestoßen und habe versucht, es damit hinzukriegen (siehe code unten).

vorweg:

  • habe zwecks überschaubarkeit auf eine verallgemeinerung meiner funktion rotiere() mittels parameter-übergabe verzichtet
  • die funktion ist zum drehen quadratischer bilder gedacht, kann aber natürlich mit etwas gerechne modifiziert (u. verallgemeinert) werden
  • das bild, das ich drehe, hat die maße 50x50 px;
  • ID(id) steht für: document.getElementById('id') - IDy(id) steht für: document.getElementById('id').style
  • bitte nur konstruktive kritik - bin ein noob in den bereichen html, js, php. js kenne ich seit wenigen monaten, php seit 2 wochen und die gd-lib seit vorgestern; mir ist also klar, dass mein script stümperhaft ist ;}
  • werde bei gelegenheit eine zeichnung zur veranschaulichung hinzufügen - falls interesse da ist und meine funktion nicht als schrott erkannt wird ^^
  
<html>  
<head>  
<title>rotate image with js and gd</title>  
<style>  
	input		{position:absolute; left:50px;}  
	#bild		{position:absolute; left:200px; top:200px;}  
</style type="text/css">  
<script language="JavaScript" type="text/javascript" src="Muster-Scripte/IDy.js"></script>  
<script type="text/javascript">  
  
// fange Rotation bei 0° an  
                var deg = 0;  
	  
	function rotiere() {  
// eine 360°-Rotation, danach wird deg wieder auf 0 gesetzt  
		if (deg < 360)  
		{  
// die 360°-Rotation hier im Bsp. in 5°-Schritten alle 5ms (siehe  
// setTimeout unten)  
			deg += 5;  
// die GD-Funktion imagerotate() passt die Größe des Bildes der Drehung an,  
// wobei 2 Ecken des Ursprungsbildes jeweils die obere und die linke Kante  
// des neuen Bildes berühren und 4 mit der im 3. Parameter von imagerotate()  
// definierten Farbe gefüllten Dreiecke die durch diese  
// Größenanpassung entstandenen "Leerräume" bilden.  
// Die neue Größe des Bildes ist nach den Winkelsätzen  
// [cos(a)=Ankathete/Hypotenuse und sin(a)=Gegenkathete/Hypotenuse]  
// also Ankathete + Gegenkathete eines der 4 gleichen Dreiecke,  
// wobei die Hypotenuse der Breite/Höhe des Ursprungsbildes entspricht -  
// hier: 50px!  
// Zur Bestimmung der neuen Größe benötigen wir also den Winkel (hier:  
// moddeg), der genau der Winkel deg Modulo 90 ist. Ausnahme:  
// Ist deg genau 90°, 180°, 270° oder 360°, so wäre deg % 90 = 0;  
// also setzen wir für diese Fälle moddeg = 90.  
			if (deg != 90 && deg != 180 && deg != 270 && deg != 360)  
			{  
				var moddeg = deg % 90;  
			} else {  
				var moddeg = 90;  
			}  
			var ankat = 50 * Math.cos(moddeg * Math.PI / 180);  
			var gegkat = 50 * Math.sin(moddeg * Math.PI / 180);  
// Da die Breite/Höhe eines Bildes eine ganzzahlige Pixelgröße ist, kann  
// die neue Breite/Höhe (bis auf die Ausnahmefälle) nicht genau  
// Ankathete + Gegenkathete sein -> abrunden und um 1 erhöhen!  
			if (deg != 90 && deg != 180 && deg != 270 && deg != 360)  
			{  
				var newWidth = Math.floor(ankat + gegkat) + 1;  
			} else {  
				var newWidth = ankat + gegkat;  
			}  
// Jetzt zum neuen Rotationszentrum. Das Rotationszentrum bei imagerotate()  
// liegt in der Mitte des Bildes. Da allerdings die Bildgröße in  
// positiver x- und y-Richtung angepasst wird und das "alte Bild"  
// also im "neuen Bild" die obere und die rechte Kante berührt, bekommt  
// man ohne Modifikation nicht einmal eine Drehung des Bildes um dessen  
// ursprüngliches Rotationszentrum. Hier nun eine Modifikation, die das  
// Verschieben des Rotationspunktes auf die Mitte der Unterkante des  
// Ursprungsbildes bewirkt, wobei berücksichtigt wird, dass die  
// Unterkante mit den Drehungen variiert; es wird hier simuliert, es  
// gäbe lediglich das Ursprungsbild und nicht die 4 Dreiecke, die durch die  
// Bildvergrößerungen entstehen.  
// Mit einer Prise Mathe ermittelt man nun die Mitte der Unterkante des  
// gedrehten Ursprungsbildes und verschiebt das neue Bild in  
// x- und y-Richtung, s.d. diese ermittelte Mitte mit der des unge-  
// drehten Bildes - also mit dem Rotationszentrum - übereinstimmt.  
			if (deg <= 90)  
			{  
				var newLeft = Math.round(-newWidth + ankat/2 + 225);  
				var newTop = Math.round(-newWidth + gegkat/2 + 250);  
			}  
			if ((deg > 90) && (deg <= 180))  
			{  
				var newLeft = Math.round(-newWidth + gegkat/2 + 225);  
				var newTop = Math.round(-ankat/2 + 250);  
			}  
			if ((deg > 180) && (deg <= 270))  
			{  
				var newLeft = Math.round(-ankat/2 + 225);  
				var newTop = Math.round(-gegkat/2 + 250);  
			}  
			if ((deg > 270) && (deg <= 360))  
			{  
				var newLeft = Math.round(-gegkat/2 + 225);  
				var newTop = Math.round(-newWidth + ankat/2 + 250);  
			}  
// Dies ist die Drehung selbst: Die Bildquelle ist die Datei drehstern.php,  
// in der das Bild mit GD erstellt wird.  
//Der src wird eine GET-Variable angehängt (grad), die in drehstern.php mit  
// $_REQUEST["grad"] abgerufen und in die Variable $grad gespeichert wird.  
			bildSrc = 'drehstern.php?grad='+deg;  
			ID('bild').src = bildSrc;  
// Die Position des neuen - gedrehten - Bildes zur Beibehaltung des  
// Rotationszentrums korrigieren.  
			IDy('bild').left = newLeft + 'px';  
			IDy('bild').top = newTop + 'px';  
// 5° done. 355 more to go:  
			setTimeout('rotiere(5)',5);  
		}  
		else {deg = 0;}  
	}  
  
  
</script>  
</head>  
<body>  
	<h1>GD-image einbinden</h1>  
	<input type="button" value="Rotiere den Stern" onclick="javascript:rotiere()" />  
	<div>  
		<img src="drehstern.php" id="bild" />  
	</div>  
</body>  
</html>  

drehstern.php

  
<?php  
  
header('Content-type: image/png');  
  
$pic = 'bilder/stern.jpg';  
$grad = $_REQUEST["grad"];  
  
$quelle = imagecreatefromjpeg($pic);  
$bgfarbe = imagecolorallocate($quelle, 255, 255, 255);  
$rotate = imagerotate($quelle, $grad, $bgfarbe);  
  
imagepng($rotate);  
imagedestroy($quelle);  
imagedestroy($rotate);  
  
?>  

die rotation ist beim ersten drücken des buttons etwas ruckelig, bei allen folge-drücken dann aber i.o.
kann mir jemand erklären, woran das liegt?

freue mich über jede konstruktive kritik und auch über anregungen/hinweise/links dazu, wie man eleganter bilder drehen könnte (ohne bibliotheken).

vielen dank,

ein neuling