JavaScript + GD - Animation, Bild rotieren
php-neuling
- php
1 suit0 bleicher0 suit0 php-neuling0 suit0 php-neuling0 ChrisB
0 php-neuling
0 suit
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:
<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
wie drehe/rotiere ich ein img-element mit js/php?
Wenn du nur "ganze" Winkel brauchst 90, 180, 270 - kannst du auch mit CSS (transform + rotate) und für den Internet Explorer mit dem Transform-Filter (BasicImage, rotate) arbeiten.
Damit reduzierst du deinen Code auf der serverseite auf 0 und auf der JavaScript-Seite auf etwa 5 Zeilen sowie auf der CSS-Seite auf etwa 20 Zeilen.
Grüße,
Wenn du nur "ganze" Winkel brauchst
warum das? CSS3 erlaubt doch beliebige werte 0-360°, zudem kann man das ganze mit transition-duration animieren....
MFG
bleicher
Wenn du nur "ganze" Winkel brauchst
warum das? CSS3 erlaubt doch beliebige werte 0-360°,
Beim IE-Filter nur 90°-Schritte.
zudem kann man das ganze mit transition-duration animieren....
Kein IE-Support.
ja, habe mich da jetzt mal etwas reingelesen - danke für den tipp nochmal.
bei FF kann man mit javascript wunderbar über style.MozTransform eine
drehung animieren und zudem mit -moz-origin das rotationszentrum ändern :-)
leider scheint mir eine dynamische manipulation der IE-filter mit javascript
etwas komplizierter ^^
ja, habe mich da jetzt mal etwas reingelesen - danke für den tipp nochmal.
bei FF kann man mit javascript wunderbar über style.MozTransform eine
drehung animieren und zudem mit -moz-origin das rotationszentrum ändern :-)
leider scheint mir eine dynamische manipulation der IE-filter mit javascript
etwas komplizierter ^^
Musst du auch nicht - definiere eifach eine Reihe an Klassen für die Rotationszustände und wechsle diese per JavaScript.
Musst du auch nicht - definiere eifach eine Reihe an Klassen für die Rotationszustände und wechsle diese per JavaScript.
ok, aber anscheinend gibt's für die rotation mit ie-filter dasselbe problem
wie bei der gd-funktion imagerotate(): man muss der translation des
rotationszentrums einige mathematische aufmerksamkeit widmen.
wenn ich das richtig sehe, wird der code bspw. bei einer drehung um 360°
in - sagen wir - 5°-schritten um ein beliebiges rotationszentrum keineswegs
erheblich kürzer mit ie-filter statt gd.
bleibt natürlich der vorteil, dass nicht jeder rotations-zwischenschritt
neu als "gd-bild" hochgeladen werden muss.
sowas wie -moz-origin gibt's nicht für ie, oder?
für die einfache rotation ohne origin-verschiebung ist für ie
.filters.item("DXImageTransform.Microsoft.Matrix").M11 = Math.cos(deg*Math.PI/180);....M12 =...M22 = Math.cos(deg*Math.PI/180),
was für ff .style.MozTransform = "rotate("+deg+"deg)"; ist.
gruß
Hi,
ok, aber anscheinend gibt's für die rotation mit ie-filter dasselbe problem
wie bei der gd-funktion imagerotate(): man muss der translation des
rotationszentrums einige mathematische aufmerksamkeit widmen.
Ein bisschen, ja: Correcting Transform Origin and Translate in IE
MfG ChrisB
hey chris,
danke für den link!
hab mich schon mit eigenen mathe-anstrengungen um das problem gekümmert
mittlerweile - eigentlich nicht so schwer.
könnt alles soviel einfacher sein, wenn man IE ignorieren könnte lol
aber wenn man sich da erstmal reingefuchst hat, dann macht's auch
irgendwie spaß, diese matrizen-schlacht ^^
liebe grüße
danke dir!
sehr merkwürdig, dass ich über diese transform- bzw. -moz-transform-eigenschaften zuvor noch nicht gestolpert bin |~D
da werd ich gleich mal mit rumbasteln...
lieben gruß
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?
Nachtrag: vergessen deine Frage zubeantworten.
Dass es ruckelt liegt daran, dass die Bilder einerseits von PHP erzeugt werden müssen und andererseits vom Browser natürlich erst geladen werden müssen ;) das kostet.