Bilder mit PHP gemäß EXIF-Daten drehen

Nachdem ich ein Gästebuch-Plugin für WordPress implementiert hatte, bei dem Besucher Bilder hochladen können, ist aufgefallen, dass Bilder gedreht im Gästebuch dargestellt werden, was man anhand des Motivs erkennen kann. Sobald man das Bild separat aufruft, werden sie im Browser zwar richtig rum dargestellt, sind aber verzerrt. Auf dem iPhone werden die Bilder auch im Gästebuch in der “korrekten” Ausrichtung dargestellt.

Wenn die Bilder mit dem iPhone gemacht werden (gefühlt betrifft das heutzutage ca. 80% aller Bilder), wird in den EXIF-Daten des Bildes die Ausrichtung gespeichert. Der iPhone-Besitzer bekommt nichts davon mit, lädt das Bild ins Gästebuch hoch und wundert sich dann, warum es falsch ist.

Als Lösung habe ich mich entschlossen, die Bilder beim Upload zu drehen (und zu skalieren). Mit der Funktion exif_read_data kann man die EXIF-Daten entsprechend auslesen. Das Bild wird auf maximal 800 Pixel Breite oder Höhe skaliert.

$image = imagecreatefromstring(file_get_contents($_FILES['picture']['tmp_name']));
$exif = exif_read_data($_FILES['picture']['tmp_name']);
if(!empty($exif['Orientation'])) {
	switch($exif['Orientation']) {
		case 8:
			$image = imagerotate($image,90,0);
			break;
		case 3:
			$image = imagerotate($image,180,0);
			break;
		case 6:
			$image = imagerotate($image,-90,0);
			break;
	}
}
 
// scale image
$ratio = imagesx($image)/imagesy($image); // width/height
if($ratio > 1) {
	$width = 800;
	$height = round(800/$ratio);
} else {
	$width = round(800*$ratio);
	$height = 800;
}
$scaled = imagecreatetruecolor($width, $height);
imagecopyresampled($scaled, $image, 0, 0, 0, 0, $width, $height, imagesx($image), imagesy($image));
 
imagejpeg($scaled, $targetFilePath);
imagedestroy($image);
imagedestroy($scaled);

Tags:

Geschrieben in default | Kommentare deaktiviert für Bilder mit PHP gemäß EXIF-Daten drehen

Hörbücher im Park

Es mag der Eindruck entstehen, als würde ich nicht mehr lesen. Das stimmt natürlich nicht. Ich bin nur vor einiger Zeit auch auf Hörbücher umgestiegen. Als junge Mutter hat man wenig Zeit zum Lesen, dafür geht man oft genug mit dem Kinderwagen spazieren, da bietet es sich doch an, dass man Hörbücher hört.
(mehr …)

Geschrieben in books | Kommentare deaktiviert für Hörbücher im Park

Hack-Auberginen-Pastete

Zutaten:

  • 250g Rinderhack
  • Aubergine mittelgroß
  • Tomatenmark
  • 5 Yufkateig-Blätter
  • Ei
  • etwas Milch
  • Käse zum Überbacken z.B. Mozarella

Zubereitung:
Backofen auf 200 Grad vorheizen. Hackfleisch in der Pfanne mit etwas Öl anbraten. Aubergine in kleine Würfel schneiden und zum Hackfleisch geben. Tomatenmark (nach belieben, gerne mehrere Eßlöffel) hinzufügen und etwas Wasser. Alles schön weiterbraten, dabei salzekn und pfeffern. Total gut, wenn man Harissa-Gewürz oder Harissa-Paste hat, das dann da einrühren. Backpapier abschneiden (ca. 30cm von einer Rolle) und auslegen. Darauf ein Yufkateig-Blatt legen und mit etwas Olivenöl besteichen. Ein zweites Yufkateig-Blatt so darauf legen, dass es an zwei Seiten ca. 5cm übersteht und es mit Olivenöl besteichen. Das dritte Blatt so darauflegen, dass es im Bezug zum ersten wieder an zwei Seiten ca. 5cm über steht und wieder mit Olivenöl besteichen. Die zwei weiteren Blätter auch so auf die anderen Legen. Mit dem Backpapier zusammen die Teigblätter in eine flache Auflaufform (am besten Quiche-Form) legen und leicht andrücken. Das Hackfleisch hineingeben (Füllung). Ei mit etwas Milch verquirlen und über das Hackfleisch geben, Käse drauf streuen. Die überhängenden Yufka-Blätter in die Mitte klappen, etwas andrücken und mit etwas Olivenöl bestreichen. Auf mittlerer Schiene ca. 15 Minuten backen.

Geschrieben in cooking | Kommentare deaktiviert für Hack-Auberginen-Pastete

“Access denied” beim Hinzufügen von Bildern als Redakteur

Wenn ein Redakteur einem normalen Inhaltselement in TYPO3 6 ein Bild hinzufügen möchte und die Fehlermeldung “Access denied” erscheint, dann muss bei den Zugriffsrechten das Lese- und Schreibrecht auf die Tabelle “File Reference” gesetzt werden.

Geschrieben in TYPO3 | Kommentare deaktiviert für “Access denied” beim Hinzufügen von Bildern als Redakteur

Bild aus Media als Hintergrundbild ausgeben (FAL)

Vor langer Zeit hatte ich mal einen Beitrag geschrieben, wie man das verknüpfte Bild aus dem Feld ‘media’ einer Seite als Hintergrundbild ausgeben kann.

Seit TYPO3 6.0 werden die Bilder nicht in den Upload-Ordner hochgeladen, sondern referenziert. Dafür reicht aber eine zusätzliche Zeile im Code. Dieser Schnipsel kann im Template-Setup verwendet werden:

10 = IMG_RESOURCE
10 {
	file.import = uploads/media/
	file.import.data = levelmedia:-1, slide
	file.import.listNum = 0
	file.treatIdAsReference = 1
	stdWrap.wrap = <div id="visual" style="background-image: url(|)">
}

Zusätzliche Informationen zum Plugin im BE

Ich finde es ja ziemlich cool, dass im Fall von tt_news im Backend anzeigt wird, welche Ansicht (CODE) im Plugin gewählt ist und auch mal Hinweise und Fehler anzeigt werden, falls das Plugin nicht vollständig konfiguriert ist. Denn das ist häufig der Nachteil an Plugins, sie sind wie eine Black Box, man sieht nur beim Bearbeiten, was da eingestellt ist.

Wenn man es weiß, ist es eigentlich ziemlich einfach. Zunächst muss man eine Klasse integrieren, die die erweiterten Informationen extrahieren soll. Dazu am besten folgende Zeile in ext_tables.php oder ext_localconf.php einsetzen (ja, list_type_Info):

$pluginSignature = strtolower($extensionName).'_pi1';
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['cms/layout/class.tx_cms_layout.php']['list_type_Info'][$pluginSignature]['my_extension'] 
= 'EXT:my_extension/Classes/Layout/Entry.php:Entry->getExtensionSummary';

In welchem Ordner man die Datei ablegt, ist einem selbst überlassen.

Dann sollte man eben diese Datei mit dem Namen anlegen, darin die entsprechende Klasse mit der Funktion. In meinem Fall heißt die Datei Entry.php, enthält die Klasse Entry und die Funktion getExtensionSummary.

class Entry {
	function getExtensionSummary($params, &$pObj) {
 
	}
}

Die Funktion bekommt zwei Parameter: $params ist ein Objekt, dass alle Infomationen zum Content Element enthält und $pObj ist eine Referenz auf Parent-Objekt. Als erstes sollte man den list_type nochmal prüfen. Der Wert XXX sollte mit der vorher angegebenen Plugin-Signatur übereinstimmen.

if($params['row']['list_type'] == 'XXX') {
	// Flexform parsen
	$data = \TYPO3\CMS\Core\Utility\GeneralUtility::xml2array($params['row']['pi_flexform']);
	if(is_array($data) && $data['data']['sDEF']['lDEF']['switchableControllerActions']) {
		$selectedAction = $data['data']['sDEF']['lDEF']['switchableControllerActions']['vDEF'];
		return $result;
	}
}

Die Rückgabe dieser Funktion wird an die normale Ausgabe im BE drangehängt.

Wenn man einen Datensatz braucht, um z.B. seinen Titel anzuzeigen, dann kann man es wie folgt tun:

$entry= \TYPO3\CMS\Backend\Utility\BackendUtility::getRecord('tx_myextension_domain_model_entry', $id);
$result = '<b>'.$entry['title'].'</b>';

Trim ViewHelper

Mir ist aufgefallen, dass es man den Fluid Code zwar sehr schön formatieren kann, es aber nicht unbedingt schön in der Ausgabe aussieht. Jedes If führt in der Ausgabe zu einem Zeilenumbruch, was im Endeffekt zu einem unnötig langen HTML-Code führt. Also habe ich einen Trim-ViewHelper geschrieben. Dieser geht ein bisschen über das einfache trim von PHP hinaus – es werden alle Zeilenumbrüche und doppelte Leerzeichen entfernt, da sie in der Darstellung von HTML keine Rolle spielen. Und das ist der Code von meinem ViewHelper (namespace bitte selbst einsetzen):

class TrimViewHelper extends \TYPO3\CMS\Fluid\Core\ViewHelper\AbstractViewHelper {
 
	/**
	 * @param mixed $value The value to output
	 * @return string
	 */
	public function render($value = NULL) {
		if ($value === NULL) {
			$value =  $this->renderChildren();
		}
		// remove new line - does not matter in html anyway
		$value = str_replace(chr(10), '', $value);
		// remove multiple whitespaces
		$value = preg_replace ('#\s+#' , ' ' , $value);
		return trim($value);
	}
}

Extbase Plugin per TypoScript einbinden

Wenn man ein auf Extbase/Fluid-Basis erstelltes Plugin auf jeder Seite einsetzen möchte, dann braucht man folgenden Code im Setup des Seitentemplates:

temp.myPlugin = USER
temp.myPlugin {
   userFunc = tx_extbase_core_bootstrap->run
   pluginName = MyPlugin
   extensionName = MyExtension
 
   settings =< plugin.tx_myextension.settings
   persistence =< plugin.tx_myextension.persistence
   view =< plugin.tx_myextension.view
}

Statt MyPlugin und MyExtension muss man natürlich den Namen des eigenen Plugins und der Extension einsetzen. Wichtig ist, dass das Plugin mit configurePlugin und registerPlugin in ext_localconf.php bzw. ext_tables.php registriert und konfiguriert ist. In meinem Fall ist MyPlugin so konfiguriert, dass TestController->listAction aufgerufen werden soll.

Nun hatte ich das Problem, dass ich meine Klassen bereits nach TYPO3 6 Manier also mit Namespaces geschrieben habe. Wenn der Extbase Bootstrapper aber aus den Angaben den Controller-Klassennamen zusammenbaut, dann bekommt er folgendes: Tx_MyExtension_Controller_TestController. Die Klasse existiert natürlich nicht, denn sie heißt genamespaced ja so: \Vendor\MyExtension\Controller\TestController.

Ich habe rausgefunden, dass es eine ClassAliasMapper.php gibt, in der die alten Klassennamen auf die neuen Namen mit Namespace gemappt werden. So funktioniert ja z.B. der Aufruf Tx_Extbase_Core_Bootstrap immer noch, obwohl es die Klasse nicht gibt. Dann hab ich rausgefunden, dass alle Extensions nach der gleichen Datei durchsucht werden und diese Mapping-Liste erweitert wird. Im Extension-Ordner die Ordnerstruktur Migrations/Code/ und darin die Datei ClassAliasMap.php anlegen. Die Datei hat folgenden Inhalt:

return array(
	'Tx_MyExtension_Controller_TestController' => 'Vendor\\MyExtension\\Controller\\TestController'
);

Extbase-Klassen auf bestehende Tabellen mappen

Wenn man noch ohne Namespaces arbeitet, dann fügt man folgenden Code ins Setup der eigenen Extension ein:

config.tx_extbase.persistence.classes {
	Tx_MyExtension_Domain_Model_Page {
		mapping {
			tableName = pages
		}
	}
}

Seit TYPO3 6.0 sind nun Namespaces hinzugekommen, und nun sieht es so aus:

config.tx_extbase.persistence.classes {
	Vendor\MyExtension\Domain\Model\Page {
		mapping {
			tableName = pages
		}
	}
}

Wichtig ist, dass vor dem Vendor kein Slash steht.

Geschrieben in TYPO3 | Kommentare deaktiviert für Extbase-Klassen auf bestehende Tabellen mappen

Mehrspaltigkeit in TYPO3 6.0

Ich habe mich letzte Woche mit Mehrspaltigkeit in TYPO3 auseinandergesetzt. Ich habe bisher in 4er-Versionen gearbeitet und wollte nun der neuen Version 6 eine Chance geben. Da die Layouts, die ich serviert bekomme, meistens abwechslungsreich sind (2 oder 3 Spalten innerhalb einer Content-Spalte), habe ich bisher immer TemplaVoila genutzt. Die Flexibilität von TV und der Einsatz von FCEs macht TV zu einem mächtigen Templating-Tool in TYPO3.

(mehr …)