Funktionen und Merkmale

Aspose.3D FOSS für TypeScript ist eine MIT-lizenzierte Node.js-Bibliothek zum Laden, Erstellen und Exportieren von 3D‑Szenen. Sie wird mit vollständigen TypeScript‑Typdefinitionen und einer einzigen Laufzeitabhängigkeit (xmldom),.

Installation und Einrichtung

Installieren Sie das Paket von npm mit einem einzigen Befehl:

npm install @aspose/3d

Das Paket zielt auf CommonJS ab und erfordert Node.js 18 oder höher. Nach der Installation überprüfen Sie Ihre tsconfig.json enthält die folgenden Compiler-Optionen für volle Kompatibilität:

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "moduleResolution": "node",
    "esModuleInterop": true,
    "strict": true
  }
}

Importieren Sie die Haupt Scene Klasse aus dem Paketstamm. Format-spezifische Optionsklassen werden aus ihren jeweiligen Unterpfaden importiert:

import { Scene } from '@aspose/3d';
import { ObjLoadOptions } from '@aspose/3d/formats/obj';
import { GltfSaveOptions, GltfFormat } from '@aspose/3d/formats/gltf';

Funktionen und Merkmale

Formatunterstützung

Aspose.3D FOSS for TypeScript liest und schreibt sechs wichtige 3D‑Dateiformate. Die Format­erkennung erfolgt beim Laden automatisch anhand binärer Magic‑Numbers, sodass Sie das Quellformat nicht explizit angeben müssen.

FormatLesenSchreibenHinweise
OBJ (Wavefront)JaJaLiest/Schreibt .mtl Materialien; verwenden ObjLoadOptions.enableMaterials für den Import
glTF 2.0JaJaJSON-Textformat; PBR-Materialien
GLBJaJaBinäres glTF; gesetzt GltfSaveOptions.binaryMode = true
STLJaJaBinär und ASCII; vollständiger Roundtrip verifiziert
3MFJaJa3D Manufacturing Format with color and material metadata
FBXNein*Nein*Importer/Exporter existieren, aber die automatische Format-Erkennung ist nicht implementiert
COLLADA (DAE)JaJaEinheiten‑Skalierung, Geometrie, Materialien und Animationsclips

Laden von OBJ mit Materialien:

import { Scene } from '@aspose/3d';
import { ObjLoadOptions } from '@aspose/3d/formats/obj';

const scene = new Scene();
const options = new ObjLoadOptions();
options.enableMaterials = true;
options.flipCoordinateSystem = false;
options.scale = 1.0;
options.normalizeNormal = true;
scene.open('model.obj', options);

Speichern nach GLB (binäres glTF):

import { Scene } from '@aspose/3d';
import { GltfSaveOptions, GltfFormat } from '@aspose/3d/formats/gltf';

const scene = new Scene();
// ... build or load scene content

const opts = new GltfSaveOptions();
opts.binaryMode = true;
scene.save('output.glb', GltfFormat.getInstance(), opts);

Szenengraph

Alle 3D‑Inhalte sind als Baum von Node Objekten, die bei scene.rootNode. Jeder Knoten kann ein Entity (ein Mesh, Camera, Light, oder ein anderes SceneObject) Transform das es relativ zu seinem übergeordneten Knoten positioniert.

Wichtige Szenengraph‑Klassen:

  • Scene: der oberste Container; enthält rootNode und animationClips
  • Node: ein benannter Baumknoten mit childNodes, entity, transform, und materials
  • Entity: Basisklasse für anfügbare Objekte (Mesh, Camera, Light)
  • SceneObject: Basisklasse, gemeinsam genutzt von Node und Entity
  • A3DObject: Root-Basisklasse mit name und Property bag
  • Transform: lokale Translation, Rotation (Euler und Quaternion) und Skalierung

Durchlaufen des Szenengraphen:

import { Scene, Node, Mesh } from '@aspose/3d';

const scene = new Scene();
scene.open('model.obj');

function visit(node: Node, depth: number = 0): void {
  const indent = '  '.repeat(depth);
  console.log(`${indent}Node: ${node.name}`);
  if (node.entity) {
    console.log(`${indent}  Entity: ${node.entity.constructor.name}`);
  }
  for (const child of node.childNodes) {
    visit(child, depth + 1);
  }
}

visit(scene.rootNode);

Programmatisches Erstellen einer Szenenhierarchie:

import { Scene, Node } from '@aspose/3d';

const scene = new Scene();
const parent = scene.rootNode.createChildNode('chassis');
const wheel = parent.createChildNode('wheel_fl');
wheel.transform.translation.set(0.9, -0.3, 1.4);

Geometrie und Mesh

Mesh ist der primäre Geometrietyp. Er erweitert Geometry und stellt Kontrollpunkte (Vertices), Polygonindizes und Vertex-Elemente für Normalen, UVs und Vertex-Farben bereit.

Wichtige Geometrie‑Klassen:

  • Mesh: Polygonnetz mit controlPoints und polygonCount
  • Geometry: Basisklasse mit Vertex-Element-Verwaltung
  • VertexElementNormal: Pro-Vertex- oder Pro-Polygon-Vertex-Normalen
  • VertexElementUV: Texturkoordinaten (ein oder mehrere UV-Kanäle)
  • VertexElementVertexColor: Pro-Vertex-Farbdaten
  • MappingMode: Steuert, wie Elementdaten auf Polygone abgebildet werden (ByControlPoint, ByPolygonVertex,: , usw.)
  • ReferenceMode: Steuert die Indexierungsstrategie (Direct, IndexToDirect)
  • VertexElementType: Identifiziert die Semantik eines Vertex-Elements
  • TextureMapping: Aufzählung der Texturkanäle

Mesh-Daten aus einer geladenen Szene lesen:

import { Scene, Mesh, VertexElementType } from '@aspose/3d';

const scene = new Scene();
scene.open('model.stl');

for (const node of scene.rootNode.childNodes) {
  if (node.entity instanceof Mesh) {
    const mesh = node.entity as Mesh;
    console.log(`Mesh "${node.name}": ${mesh.controlPoints.length} vertices, ${mesh.polygonCount} polygons`);

    const normals = mesh.getElement(VertexElementType.NORMAL);
    if (normals) {
      console.log(`  Normal mapping: ${normals.mappingMode}`);
    }
  }
}

Materialsystem

Aspose.3D FOSS für TypeScript unterstützt drei Materialtypen, die das gesamte Spektrum von legacy Phong-Shading bis hin zu physikalisch basierendem Rendering abdecken:

  • LambertMaterial: Diffuse Farbe und Umgebungsfarbe; wird auf einfache OBJ/DAE-Materialien abgebildet
  • PhongMaterial: Fügt spekulare Farbe, Glanz und Emission hinzu; der Standard-OBJ-Materialtyp
  • PbrMaterial: physikalisch basiertes Roughness/Metallic-Modell; verwendet für den glTF 2.0-Import und -Export

Materialien aus einer geladenen OBJ-Szene lesen:

import { Scene, PhongMaterial, LambertMaterial } from '@aspose/3d';
import { ObjLoadOptions } from '@aspose/3d/formats/obj';

const scene = new Scene();
const options = new ObjLoadOptions();
options.enableMaterials = true;
scene.open('model.obj', options);

for (const node of scene.rootNode.childNodes) {
  for (const mat of node.materials) {
    if (mat instanceof PhongMaterial) {
      const phong = mat as PhongMaterial;
      console.log(`  Phong: diffuse=${JSON.stringify(phong.diffuseColor)}, shininess=${phong.shininess}`);
    } else if (mat instanceof LambertMaterial) {
      console.log(`  Lambert: diffuse=${JSON.stringify((mat as LambertMaterial).diffuseColor)}`);
    }
  }
}

Anwenden eines PBR-Materials beim Erstellen einer glTF-Szene:

import { Scene, Node, PbrMaterial } from '@aspose/3d';
import { GltfSaveOptions, GltfFormat } from '@aspose/3d/formats/gltf';

const scene = new Scene();
const node = scene.rootNode.createChildNode('sphere');
const mat = new PbrMaterial();
mat.albedo = new Vector3(0.8, 0.2, 0.2);   // albedo starts null, must assign
mat.metallicFactor = 0.0;
mat.roughnessFactor = 0.5;
node.material = mat;

const opts = new GltfSaveOptions();
opts.binaryMode = false;
scene.save('output.gltf', GltfFormat.getInstance(), opts);

Mathe‑Hilfsfunktionen

Die Bibliothek liefert einen vollständigen Satz von 3D-Mathematik‑Typen, alle vollständig typisiert:

  • Vector3: 3-Komponenten-Vektor; unterstützt add, subtract, scale, dot, cross, normalize, length
  • Vector4: 4-Komponenten-Vektor für homogene Koordinaten
  • Matrix4: 4×4-Transformationsmatrix mit multiply, invert, transpose, decompose
  • Quaternion: Rotations-Quaternion mit fromEulerAngles, toEulerAngles, slerp, normalize
  • BoundingBox: achsenbündige Begrenzungsbox mit min, max, center, size, merge
  • FVector3: Einzelpräzisionsvariante von Vector3 : verwendet in Vertex-Elementdaten

Berechnung einer Bounding Box aus Mesh‑Scheitelpunkten:

import { Scene, Mesh, Vector3, BoundingBox } from '@aspose/3d';

const scene = new Scene();
scene.open('model.obj');

let box = new BoundingBox();
for (const node of scene.rootNode.childNodes) {
  if (node.entity instanceof Mesh) {
    for (const pt of (node.entity as Mesh).controlPoints) {
      box.merge(new Vector3(pt.x, pt.y, pt.z));
    }
  }
}
console.log('Center:', box.center);
console.log('Extents:', box.size);

Erstellung einer Transformation aus Euler‑Winkeln:

import { Quaternion, Vector3, Matrix4 } from '@aspose/3d';

const rot = Quaternion.fromEulerAngle(0, Math.PI / 4, 0); // 45° around Y
const mat = new Matrix4();
mat.setTRS(new Vector3(0, 0, 0), rot, new Vector3(1, 1, 1));

Animationssystem

Die Animations‑API modelliert Clips, Nodes, Channels und Keyframe‑Sequenzen:

  • AnimationClip: benannte Sammlung von Animationsknoten; zugegriffen über scene.animationClips
  • AnimationNode: bindet einen Clip per Name an einen Szenenknoten
  • AnimationChannel: zielt auf eine bestimmte Eigenschaft (z. B. Translation X) innerhalb eines Animationsknotens
  • KeyFrame: ein einzelnes Zeit/Wert-Paar
  • KeyframeSequence: geordnete Liste von KeyFrame : Objekte mit Interpolation : und Extrapolation : Einstellungen
  • Interpolation: Keyframe-Interpolationsmodus: Linear, Constant, Cubic
  • Extrapolation: Verhalten vor/nach dem Keyframe-Bereich: Constant, Cycle, Mirror

Einlesen von Animationsdaten aus einer geladenen Szene:

import { Scene, AnimationClip, KeyframeSequence } from '@aspose/3d';

const scene = new Scene();
scene.open('animated.fbx');

for (const clip of scene.animationClips) {
  console.log(`Clip: "${clip.name}"`);
  for (const animNode of clip.nodes) {
    console.log(`  Node: ${animNode.name}`);
    for (const channel of animNode.channels) {
      const seq: KeyframeSequence = channel.keyframeSequence;
      console.log(`    Channel "${channel.name}": ${seq.keyFrames.length} keyframes`);
      console.log(`    Interpolation: ${seq.interpolation}`);
    }
  }
}

Unterstützung für Streams und Buffer

: Verwenden scene.openFromBuffer() : um eine 3D‑Szene direkt aus einem im Speicher befindlichen Buffer.: . Dies ist das empfohlene Muster für serverlose Funktionen, Streaming‑Pipelines und die Verarbeitung von über HTTP abgerufenen Assets, ohne sie auf die Festplatte zu schreiben.

import { Scene } from '@aspose/3d';
import { ObjLoadOptions } from '@aspose/3d/formats/obj';
import * as fs from 'fs';

// Load file into memory, then parse from buffer
const buffer: Buffer = fs.readFileSync('model.obj');
const scene = new Scene();
const options = new ObjLoadOptions();
options.enableMaterials = true;
scene.openFromBuffer(buffer, options);

for (const node of scene.rootNode.childNodes) {
  if (node.entity) {
    console.log(node.name, node.entity.constructor.name);
  }
}

Die automatische Formatserkennung anhand binärer Magic‑Numbers gilt beim Laden aus einem Buffer, sodass GLB-, STL‑Binary‑ und 3MF‑Dateien erkannt werden, ohne dass ein Format‑Parameter angegeben werden muss.

Anwendungsbeispiele

Beispiel 1: OBJ laden und nach GLB exportieren

Dieses Beispiel lädt eine Wavefront-OBJ-Datei mit Materialien und exportiert die Szene anschließend als binäre glTF (GLB)-Datei, die für Web- und Spiel-Engine‑Verwendung geeignet ist.

import { Scene } from '@aspose/3d';
import { ObjLoadOptions } from '@aspose/3d/formats/obj';
import { GltfSaveOptions, GltfFormat } from '@aspose/3d/formats/gltf';

function convertObjToGlb(inputPath: string, outputPath: string): void {
  const scene = new Scene();

  const loadOpts = new ObjLoadOptions();
  loadOpts.enableMaterials = true;
  loadOpts.flipCoordinateSystem = false;
  loadOpts.normalizeNormal = true;
  scene.open(inputPath, loadOpts);

  // Report what was loaded
  for (const node of scene.rootNode.childNodes) {
    if (node.entity) {
      console.log(`Loaded: ${node.name} (${node.entity.constructor.name})`);
    }
  }

  const saveOpts = new GltfSaveOptions();
  saveOpts.binaryMode = true; // write .glb instead of .gltf + .bin
  scene.save(outputPath, GltfFormat.getInstance(), saveOpts);

  console.log(`Exported GLB to: ${outputPath}`);
}

convertObjToGlb('input.obj', 'output.glb');

Beispiel 2: Round‑Trip STL mit Normalen‑Validierung

Dieses Beispiel lädt eine binäre STL-Datei, gibt Normaleninformationen pro Vertex aus und exportiert die Szene anschließend als ASCII‑STL und überprüft den Round‑Trip.

import { Scene, Mesh, VertexElementNormal, VertexElementType } from '@aspose/3d';
import { StlLoadOptions, StlSaveOptions } from '@aspose/3d/formats/stl';

const scene = new Scene();
const loadOpts = new StlLoadOptions();
scene.open('model.stl', loadOpts);

let totalPolygons = 0;
for (const node of scene.rootNode.childNodes) {
  if (node.entity instanceof Mesh) {
    const mesh = node.entity as Mesh;
    totalPolygons += mesh.polygonCount;

    const normElem = mesh.getElement(VertexElementType.NORMAL) as VertexElementNormal | null;
    if (normElem) {
      console.log(`  Normals: ${normElem.data.length} entries, mapping=${normElem.mappingMode}`);
    }
  }
}
console.log(`Total polygons: ${totalPolygons}`);

// Re-export as ASCII STL
const saveOpts = new StlSaveOptions();
saveOpts.binaryMode = false; // ASCII output
scene.save('output_ascii.stl', saveOpts);

Beispiel 3: Szene programmgesteuert erstellen und als glTF speichern

Dieses Beispiel erstellt eine Szene mit einem PBR‑Material von Grund auf und speichert sie als JSON‑glTF‑Datei.

import { Scene, Mesh, PbrMaterial, Vector4 } from '@aspose/3d';
import { GltfSaveOptions, GltfFormat } from '@aspose/3d/formats/gltf';

const scene = new Scene();
const node = scene.rootNode.createChildNode('floor');

// Build a simple quad mesh (two triangles)
// controlPoints are Vector4 (x, y, z, w) where w=1 for positions
const mesh = new Mesh();
mesh.controlPoints.push(
  new Vector4(-1, 0, -1, 1),
  new Vector4( 1, 0, -1, 1),
  new Vector4( 1, 0,  1, 1),
  new Vector4(-1, 0,  1, 1),
);
mesh.createPolygon([0, 1, 2]);
mesh.createPolygon([0, 2, 3]);
node.entity = mesh;

// Apply a PBR material
const mat = new PbrMaterial();
mat.albedo = new Vector3(0.6, 0.6, 0.6);   // albedo starts null, must assign
mat.metallicFactor = 0.0;
mat.roughnessFactor = 0.8;
node.material = mat;

// Save as JSON glTF
const opts = new GltfSaveOptions();
opts.binaryMode = false;
scene.save('floor.gltf', GltfFormat.getInstance(), opts);
console.log('Scene written to floor.gltf');

Tipps und bewährte Verfahren

  • : Verwenden ObjLoadOptions.enableMaterials = true wann immer Sie Materialdaten aus .mtl‑Dateien benötigen. Ohne diese ist die Materialliste auf jedem Knoten leer.
  • Bevorzugen binaryMode = true für GLB bei der Erstellung von Assets für Web‑ oder Spiel‑Engines. Binäres GLB ist eine einzelne, eigenständige Datei und lädt in Browsern und Engines schneller als die Aufteilung JSON + .bin.
  • Verwenden openFromBuffer() in serverlosen Umgebungen um temporäre Datei‑I/O zu vermeiden. Holen Sie das Asset, übergeben Sie das Buffer direkt und schreiben Sie die Ausgabe in einen Stream oder einen anderen Puffer.
  • Prüfen node.entity vor dem Casten: Nicht alle Knoten tragen eine Entität. Immer mit einem prüfen instanceof prüfen Sie vor dem Zugriff Mesh-spezifische Eigenschaften wie controlPoints.
  • Setzen normalizeNormal = true in ObjLoadOptions wenn Ihre Quell‑OBJ‑Dateien aus nicht vertrauenswürdigen Quellen stammen. Dies verhindert, dass degenerierte Normalen in nachgelagerte Rendering‑ oder Validierungsschritte propagiert werden.
  • Beibehalten strict: true in tsconfig.json: Die Bibliothek wurde mit noImplicitAny und strictNullChecks. Deaktivieren strict verbirgt echte Typfehler und untergräbt den Wert der typisierten API.
  • Durchlaufen über childNodes, nicht eine Indexschleife: die childNodes Die Eigenschaft gibt ein Iterable zurück; vermeiden Sie die Abhängigkeit von numerischer Indizierung für zukünftige Kompatibilität.

Häufige Probleme

SymptomWahrscheinliche UrsacheLösung
Materialliste nach OBJ-Laden leerenableMaterials nicht gesetztSetzen options.enableMaterials = true
GLB-Datei enthält separate .bin-SidecarbinaryMode Standardmäßig auf falseSetzen opts.binaryMode = true
Vertex-Normalen fehlen in der STL-AusgabeSTL-ASCII-Modus lässt pro-Fläche-Normalen wegWechseln zu binaryMode = true oder Normalen vor dem Export berechnen
node.entity ist immer nullNur traversieren rootNode, nicht seine KinderRekursiv in node.childNodes
TypeScript-Fehler: Eigenschaft existiert nichtAlt @types CacheAusführen npm install @aspose/3d erneut; kein separates @types Paket wird benötigt
openFromBuffer wirft FormatfehlerFormat nicht automatisch aus Magic erkennbarGib die explizite Format-Option-Klasse als zweites Argument weiter

Häufig gestellte Fragen

Benötigt die Bibliothek native Add-ons oder Systempakete? Nein. Aspose.3D FOSS für TypeScript hat eine einzige Laufzeitabhängigkeit: xmldom, das reines JavaScript ist und automatisch von npm installiert wird. Es gibt keine .node native Add-ons und keine Systempakete zu installieren.

Welche Node.js-Versionen werden unterstützt? Node.js 18, 20 und 22 LTS. Die Bibliothek zielt auf CommonJS-Ausgabe ab und verwendet intern ES2020-Sprachfeatures.

Kann ich die Bibliothek in einem Browser-Bundle (webpack/esbuild) verwenden? Die Bibliothek zielt auf Node.js ab und verwendet das Node.js fs und Buffer APIs. Browser-Bundling wird nicht offiziell unterstützt. Für die Browser‑Nutzung laden Sie die Szene serverseitig und übertragen das Ergebnis (z. B. als GLB) an den Client.

Was ist der Unterschied zwischen GltfSaveOptions.binaryMode = true und false? binaryMode = false erzeugt ein .gltf JSON‑Datei plus eine separate .bin Binärpuffer‑Sidecar. binaryMode = true erstellt eine einzelne eigenständige .glb Datei. Verwenden Sie true für die Auslieferung von Produktions‑Assets.

Kann ich eine Datei aus einer HTTP‑Antwort laden, ohne sie auf die Festplatte zu speichern? Ja. Holen Sie die Antwort als Buffer (z. B. mit node-fetch oder das eingebaute fetch in Node 18+), dann rufen Sie scene.openFromBuffer(buffer, options).

Ist die FBX‑Unterstützung vollständig? Das Lesen und Schreiben von FBX wird für Szenenhierarchie, Mesh‑ und Geometriedaten, Animationsclips und Materialien unterstützt. Sehr komplexe FBX‑Dateien mit eingebetteten Medien können teilweise Ergebnisse liefern; testen Sie mit Ihrem spezifischen Asset‑Korpus.

Unterstützt die Bibliothek TypeScript 4.x? TypeScript 5.0+ wird empfohlen. TypeScript 4.7+ sollte in der Praxis funktionieren, aber die Bibliothek wird gegen 5.0+ getestet und entwickelt.

Zusammenfassung der API-Referenz

KlasseModulZweck
Scene@aspose/3dTop-Level‑Szenencontainer; open(), openFromBuffer(), save(), rootNode, animationClips
Node@aspose/3dSzenengraph‑Knoten; childNodes, entity, transform, materials, createChildNode()
Entity@aspose/3dBasisklasse für szenen‑anhängbare Objekte
SceneObject@aspose/3dBasisklasse, gemeinsam genutzt von Node und Entity
A3DObject@aspose/3dRoot‑Basis mit name und Property‑Bag
Transform@aspose/3dLokale Translation, Rotation und Skalierung
Mesh@aspose/3dPolygonnetz; controlPoints, polygonCount, createPolygon(), Vertex-Elemente
Geometry@aspose/3dBasisklasse für Geometrietypen
Camera@aspose/3dKamera-Entität mit Sichtfeld- und Projektions‑Einstellungen
Light@aspose/3dLicht-Entität (Punkt, Richtung, Spot)
LambertMaterial@aspose/3dDiffuses + Umgebungs‑Shading‑Modell
PhongMaterial@aspose/3dPhong-Shading mit Spiegelungen und Emission
PbrMaterial@aspose/3dPhysikalisch basiertes Rauheits-/Metallisch‑Modell für glTF
Vector3@aspose/3d3-component double-precision vector
Vector4@aspose/3d4-component vector for homogeneous math
Matrix4@aspose/3d4×4 transformation matrix
Quaternion@aspose/3dRotations‑Quaternion
BoundingBox@aspose/3dAchsenorientierte Begrenzungsbox
FVector3@aspose/3dSingle-precision-Variante von Vector3
VertexElementNormal@aspose/3dPro-Vertex- oder Pro-Polygon-Vertex-Normalen
VertexElementUV@aspose/3dTexturkoordinaten-Vertex-Element
VertexElementVertexColor@aspose/3dPro-Vertex-Farbe-Vertex-Element
MappingMode@aspose/3dEnum: CONTROL_POINT, POLYGON_VERTEX, POLYGON, ALL_SAME
ReferenceMode@aspose/3dEnum: Direct, IndexToDirect
AnimationClip@aspose/3dBenannte Animation; enthält AnimationNode Liste
AnimationNode@aspose/3dBindet Clip an Szenenknoten; enthält AnimationChannel Liste
AnimationChannel@aspose/3dZielt auf eine Eigenschaft; hält KeyframeSequence
KeyFrame@aspose/3dEinzelnes Zeit/Wert-Keyframe-Paar
KeyframeSequence@aspose/3dGeordnete Keyframe-Liste mit Interpolation und Extrapolation
Interpolation@aspose/3dEnum: Linear, Constant, Cubic
Extrapolation@aspose/3dEnum: Constant, Cycle, Mirror
ObjLoadOptions@aspose/3d/formats/objOBJ-Importoptionen: enableMaterials, flipCoordinateSystem, scale, normalizeNormal
GltfSaveOptions@aspose/3d/formats/gltfglTF/GLB-Exportoptionen: binaryMode
GltfFormat@aspose/3d/formats/gltfFormatinstanz für glTF/GLB; übergeben an scene.save()
StlLoadOptions@aspose/3d/formats/stlSTL-Importoptionen
StlSaveOptions@aspose/3d/formats/stlSTL-Exportoptionen: binaryMode
StlImporter@aspose/3d/formats/stlLow-Level STL-Reader
StlExporter@aspose/3d/formats/stlLow-level STL‑Schreiber
 Deutsch