# Tipps & Tricks

Allgemeine Themen in der Software Entwicklung

# Bild abdunkeln wenn es zu hell ist

Ja, das geht ganz einfach mit reinem .NET-Framework und C#. Du brauchst im Wesentlichen zwei Schritte:

1. **Mittlere Helligkeit messen**
2. **Bild um einen errechneten Faktor abdunkeln**

---

## 1. Mittlere Helligkeit messen

Wir laden das JPG in ein `Bitmap`, iterieren über alle Pixel (oder eine Unter-Stichprobe, um es schneller zu machen) und berechnen die durchschnittliche Luminanz mit der üblichen Formel

<span class="katex">Y=0,299 R+0,587 G+0,114 BY = 0{,}299\\,R + 0{,}587\\,G + 0{,}114\\,B</span>

```csharp
private static float GetAverageBrightness(Bitmap bmp)
{
    long sum = 0;
    int width = bmp.Width;
    int height = bmp.Height;
    int total = width * height;

    // Optional: für sehr große Bilder nur jedes N-te Pixel prüfen
    int step = (total > 1_000_000) ? 10 : 1;

    for (int y = 0; y < height; y += step)
    for (int x = 0; x < width;  x += step)
    {
        Color c = bmp.GetPixel(x, y);
        // Luminanz-Berechnung
        int lum = (int)(0.299 * c.R + 0.587 * c.G + 0.114 * c.B);
        sum += lum;
    }

    // Durch Schritt-Vergrößerung wieder korrigieren
    int count = (width / step) * (height / step);
    return sum / (float)count / 255f;  // Normiert auf [0,1]
}

```

Ruft ihr `GetAverageBrightness(yourBitmap)` auf, erhaltet ihr eine Zahl zwischen etwa 0 ( komplett schwarz) und 1 (komplett weiß). Werte über ~0.6–0.7 sind in der Regel zu hell für Passfotos.

---

## 2. Bild abdunkeln

Wenn der gemessene Wert <span class="katex">bb</span> zu hoch ist, könnt ihr das Bild um einen Faktor <span class="katex">(target/b)(\\mathrm{target} / b)</span> abdunkeln. Am einfachsten geht das mit einem **ColorMatrix** und `Graphics.DrawImage`:

```csharp
private static Bitmap AdjustBrightness(Bitmap original, float brightnessFactor)
{
    // ColorMatrix: Diagonale bleibt bei 1, und das Offset in der letzten Spalte skaliert RGB.
    var cm = new ColorMatrix(new float[][]
    {
        new float[] { brightnessFactor, 0,                 0,                 0, 0 },
        new float[] { 0,                 brightnessFactor, 0,                 0, 0 },
        new float[] { 0,                 0,                 brightnessFactor, 0, 0 },
        new float[] { 0,                 0,                 0,                 1, 0 },
        new float[] { 0,                 0,                 0,                 0, 1 }
    });

    var ret = new Bitmap(original.Width, original.Height);
    using (Graphics g = Graphics.FromImage(ret))
    using (var attrs = new ImageAttributes())
    {
        attrs.SetColorMatrix(cm);
        g.DrawImage(
            original,
            new Rectangle(0, 0, ret.Width, ret.Height),
            0, 0, original.Width, original.Height,
            GraphicsUnit.Pixel,
            attrs);
    }
    return ret;
}

```

---

## 3. Gesamt­routine

Kombinieren wir beides in einer Methode:

```csharp
public static Bitmap AutoDarken(Bitmap bmp, float targetBrightness = 0.5f)
{
    // 1. aktuelle Helligkeit
    float current = GetAverageBrightness(bmp);

    // 2. gewünschten Zielwert nicht überschreiten
    if (current <= targetBrightness)
        return bmp;  // ist dunkel genug

    // 3. Faktor berechnen und anwenden
    float factor = targetBrightness / current;
    return AdjustBrightness(bmp, factor);
}

```

### Beispiel-Aufruf

```csharp
var img = (Bitmap)Image.FromFile("passfoto.jpg");
var darkened = AutoDarken(img, 0.5f);
darkened.Save("passfoto_dunkler.jpg", ImageFormat.Jpeg);

```

- `targetBrightness` ist hier auf 0.5 gesetzt (also mittleres Grau). Je kleiner der Wert, desto dunkler das Ergebnis.
- Siehst du, dass manche Bilder immer noch zu hell sind, kannst du den Default-Wert weiter absenken (z. B. 0.45).

---

### Performance-Tipp

- Für große Bilder lohnt sich `Bitmap.LockBits` + Pointer-Zugriff statt `GetPixel`/`SetPixel`.
- Du könntest auch nur jeden 5. oder 10. Pixel zur Helligkeitsmessung heranziehen (wie im Beispiel), das reicht für eine grobe Schätzung meistens aus.

Mit dieser Methode kannst du automatisiert durch einen ganzen Ordner von Passfotos iterieren und alle zu hellen Bilder automatisch abdunkeln, bevor du sie auf die Plastikkarte druckst.

# LiteDB Kommandos für die Abfrage mit LiteDB Studio

Hier ein kompaktes, druckfertiges Cheatsheet zur LiteDB SQL-ähnlichen Abfragesprache. Einfach kopieren, als PDF/Print ausgeben – und schon hast du es offline zur Hand.

---

## Übersicht der SQL-Befehle

<table id="bkmrk-befehl-syntax-kurzbe"><thead><tr><th>Befehl</th><th>Syntax</th><th>Kurzbeschreibung</th></tr></thead><tbody><tr><td>**SELECT**</td><td>`SELECT [TOP n] <Felder> FROM <Collection> [WHERE <Filter>] [GROUP BY <Felder>]`</td><td> </td></tr><tr><td> `\[HAVING \] \[ORDER BY \[ASC</td><td>DESC\]\] \[LIMIT n\] \[OFFSET n\]`</td><td>Datenabfrage mit Projektion, Filter, Sortierung, Gruppierung und Pagination</td></tr><tr><td>**INSERT**</td><td>`INSERT INTO <Collection> (<Feld1>,…) VALUES (<Wert1>,…)``INSERT INTO <Collection> (<BsonDocument>)`</td><td>Neue Dokumente hinzufügen</td></tr><tr><td>**UPDATE**</td><td>`UPDATE <Collection> SET <Feld>=<Wert>[, …] [WHERE <Filter>]`</td><td>Felder bestehender Dokumente ändern</td></tr><tr><td>**DELETE**</td><td>`DELETE FROM <Collection> [WHERE <Filter>]`</td><td>Dokumente löschen (ohne `WHERE`: alle)</td></tr><tr><td>**RENAME**</td><td>`RENAME COLLECTION <alt> TO <neu>``RENAME INDEX <alt> TO <neu> ON <Collection>`</td><td>Umbenennen von Collections oder Indizes</td></tr><tr><td>**DROP**</td><td>`DROP INDEX <IndexName> ON <Collection>`</td><td>Index löschen</td></tr><tr><td>**EXPLAIN**</td><td>`EXPLAIN &lt;SELECT</td><td>INSERT</td></tr></tbody></table>

---

## Filter- und Ausdruckssyntax (BsonExpression)

- **Vergleichsoperatoren**  
    `=` `!=` `>` `<` `>=` `<=`
- **Logische Verkettung**  
    `AND`, `OR`, `NOT`
- **Pfadangaben**
    
    
    - Dot-Notation: `Address.City`
    - Array-Zugriff: `Tags[0]`, `[Scores].any(x=>x>50)`
- **Array-/Kollektions-Operatoren**
    
    
    - `any`, `all`, `contains`
- **Regex**
    
    
    - `/{pattern}/i` (z. B. `/^A.*/i`)

---

## Aggregationen &amp; Funktionen

<table id="bkmrk-funktion-beschreibun"><thead><tr><th>Funktion</th><th>Beschreibung</th><th>Beispiel</th></tr></thead><tbody><tr><td>`COUNT(&lt;Feld</td><td>\*&gt;)`</td><td>Anzahl Elemente/Gruppengröße</td></tr><tr><td>`SUM(<Feld>)`</td><td>Summe numerischer Werte</td><td>`SUM(Price)`</td></tr><tr><td>`MIN/MAX(<Feld>)`</td><td>Kleinster/Größter Wert</td><td>`MAX(Date)`</td></tr><tr><td>`AVG(<Feld>)`</td><td>Durchschnitt</td><td>`AVG(Rating)`</td></tr><tr><td>`TOLOWER/TOUPPER()`</td><td>Text in Klein-/Großbuchstaben</td><td>`TOUPPER(Name)`</td></tr><tr><td>`TRIM/LENGTH/SUBSTR`</td><td>Zeichenketten-Funktionen</td><td>`TRIM(Title)`, `LENGTH(Text)`</td></tr><tr><td>`DATETIME(x)`</td><td>Wandelt Timestamp/String → DateTime</td><td>`DATETIME(CreatedAt)`</td></tr></tbody></table>

> **Hinweis:** Zusätzlich unterstützen alle BsonExpression-Funktionen ([docs](https://www.litedb.org/docs/expressions/)) u. a. `IIF`, `ISNULL`, `ROUND`, `CEIL`, `FLOOR`.

---

## Beispiele

```sql
-- 1) Einfache Abfrage mit Filter und Sort
SELECT Name, Age
FROM users
WHERE Age >= 18 AND City = 'Berlin'
ORDER BY Name ASC
LIMIT 10 OFFSET 0;

-- 2) Gruppierung und Having
SELECT City, COUNT(*) AS Einwohner
FROM users
GROUP BY City
HAVING Einwohner > 1000
ORDER BY Einwohner DESC;

-- 3) Einfügen
INSERT INTO products (Name, Price, Tags)
VALUES ('Kaffeemaschine', 79.99, ['küche', 'elektronik']);

-- 4) Update mit Filter
UPDATE products
SET Price = Price * 0.9
WHERE Tags.contains('elektronik');

-- 5) Löschen
DELETE FROM sessions
WHERE LastAccess < DATETIME('2025-01-01');

-- 6) Collection umbenennen
RENAME COLLECTION oldUsers TO customers;

```

---

## Schnellreferenz Schlüsselwörter

```
SELECT, INSERT, UPDATE, DELETE,
FROM, INTO, VALUES,
WHERE, GROUP BY, HAVING,
ORDER BY, LIMIT, OFFSET,
RENAME COLLECTION, RENAME INDEX,
DROP INDEX, EXPLAIN

```

---

> **Tipp:** Bei sehr vielen Feldern oder dynamisch konfigurierten Sets lieber die `WHEN … CONTAINS`-Variante in Switch-Statements nutzen, oder direkt `BsonExpression`-Filter anlegen. Damit bleibst du flexibel und wartbar.

---

**Viel Erfolg beim Ausdrucken und Entwickeln!**

# OpenApi Doc zu Proxy

Kurzantwort

- NSwag bekommst du als Windows‑GUI (NSwagStudio), als CLI und als NuGet/MSBuild-Integration. Download/Installationswege siehe unten.
- „Lists statt Arrays“ stellst du über die Generator‑Settings ein (arrayType/arrayInstanceType/responseArrayType/parameterArrayType). Beispiel‑nswag.json ist weiter unten.

Wo bekomme ich NSwag her?

- NSwagStudio (GUI + CLI inklusive): auf GitHub unter “Releases/Downloads” – MSI oder ZIP (xcopy). ([github.com](https://github.com/RicoSuter/NSwag?utm_source=openai))
- NSwag.MSBuild (für automatische Generierung beim Build): NuGet‑Paket NSwag.MSBuild in dein Projekt einbinden. ([nuget.org](https://www.nuget.org/packages/NSwag.MSBuild?utm_source=openai), [github.com](https://github.com/RicoSuter/NSwag/wiki/NSwag.MSBuild?utm_source=openai))
- Alternativ: CLI als .NET‑Tool/ZIP; allgemeine Befehle/Kommandos siehe Doku. ([github.com](https://github.com/RicoSuter/NSwag/wiki/CommandLine?utm_source=openai))
- Offizielle Einstiegshilfe von Microsoft (Codegen‑Optionen, NSwagStudio, NuGet, CLI): ([learn.microsoft.com](https://learn.microsoft.com/en-us/aspnet/core/tutorials/getting-started-with-nswag?view=aspnetcore-7.0&utm_source=openai))

Beispiel: C#‑Client mit List&lt;T&gt; statt T\[\] Variante A: nswag.json (empfohlen, reproduzierbar)

- Lege neben dein Projekt eine nswag.json und rufe sie via NSwagStudio („Generate Outputs“) oder per CLI/MSBuild auf.

Beispieldatei (wichtige Stellen markiert)

```json
{
  "documentGenerator": {
    "fromDocument": {
      "url": "https://example.local/swagger/v1/swagger.json",
      "output": null,
      "newLineBehavior": "Auto"
    }
  },
  "codeGenerators": {
    "openApiToCSharpClient": {
      "namespace": "MyCompany.MyApiClient",
      "className": "{controller}Client",
      "generateClientClasses": true,
      "generateClientInterfaces": true,
      "injectHttpClient": true,
      "disposeHttpClient": false,
      "useBaseUrl": false,

      // WICHTIG: Lists statt Arrays
      "arrayType": "System.Collections.Generic.List",
      "arrayInstanceType": "System.Collections.Generic.List",
      "responseArrayType": "System.Collections.Generic.List",
      "parameterArrayType": "System.Collections.Generic.IEnumerable",

      // weitere sinnvolle Defaults für .NET Framework 4.8
      "jsonLibrary": "NewtonsoftJson",
      "classStyle": "Poco",
      "generateDefaultValues": true,
      "generateDataAnnotations": true,

      "output": "Generated\\MyApiClient.g.cs",
      "newLineBehavior": "Auto"
    }
  }
}

```

- Die Settings arrayType/arrayInstanceType/responseArrayType/parameterArrayType sind offiziell Teil der NSwag/NJsonSchema‑Generator‑Konfiguration. In der „NSwag Configuration Document“-Doku findest du diese Felder (dort z. T. mit anderen Beispieltpyen); du setzt sie einfach auf List bzw. IEnumerable wie oben. ([github.com](https://github.com/RicoSuter/NSwag/wiki/NSwag-Configuration-Document?utm_source=openai), [stackoverflow.com](https://stackoverflow.com/questions/76207731/nswag-studio-is-unable-to-handle-a-json-body-with-an-array?utm_source=openai))
- Tipp: Für Methodenparameter ist IEnumerable&lt;T&gt; flexibel, Rückgaben/DTO‑Eigenschaften als List&lt;T&gt; erfüllen „List statt Array“.

Aufruf

- Per CLI (aus Projektordner): 
    - nswag run .\\nswag.json
- Per MSBuild automatisch (z. B. nach dem Build):

```xml
<!-- In der .csproj des .NET Framework 4.8-Projekts -->
<ItemGroup>
  <PackageReference Include="NSwag.MSBuild" Version="14.4.0">
    <PrivateAssets>all</PrivateAssets>
  </PackageReference>
</ItemGroup>

<Target Name="NSwag" AfterTargets="Build">
  <Exec Command="$(NSwagExe) run nswag.json" />
</Target>

```

- NSwag.MSBuild stellt die Variable $(NSwagExe) bereit, die das passende nswag‑Tool aufruft. ([github.com](https://github.com/RicoSuter/NSwag/wiki/NSwag.MSBuild?utm_source=openai))

Variante B: Direkt über die CLI ohne nswag.json

- Du kannst die wichtigsten Optionen auch als Schalter setzen, z. B.:

```
nswag openapi2csclient ^
  /input:https://example.local/swagger/v1/swagger.json ^
  /output:Generated\Client.g.cs ^
  /namespace:MyCompany.MyApiClient ^
  /ArrayType:"System.Collections.Generic.List" ^
  /ArrayInstanceType:"System.Collections.Generic.List" ^
  /ResponseArrayType:"System.Collections.Generic.List" ^
  /ParameterArrayType:"System.Collections.Generic.IEnumerable"

```

- Die verfügbaren Kommandos/Parameter sind in der CommandLine‑Doku beschrieben; die oben gezeigten Typ‑Optionen entsprechen den nswag.json‑Feldern aus der Config‑Doku. ([github.com](https://github.com/RicoSuter/NSwag/wiki/CommandLine?utm_source=openai))

Variante C: NSwagStudio (GUI)

- Swagger‑URL eintragen, Tab „CSharp Client“ öffnen und bei „Array Type“/„Array Instance Type“ List eintragen; generieren. NSwagStudio kann die Konfiguration als nswag.json speichern. ([github.com](https://github.com/RicoSuter/NSwag/wiki/NSwagStudio?utm_source=openai))

Server‑Stubs (falls du „API“ im Sinne von Controller‑Gerüst meintest)

- NSwag kann auch Controller aus einem OpenAPI‑Dokument erzeugen (ASP.NET Web API 2 für .NET Framework). In der Config nutzt du statt openApiToCSharpClient den Generator openApiToCSharpController, und kannst arrayType etc. identisch setzen; für klassisches Web API ist das aspNetNamespace typischerweise "System.Web.Http". ([github.com](https://github.com/RicoSuter/NSwag/wiki/NSwag-Configuration-Document?utm_source=openai))

Kompatibilität .NET Framework 4.8

- Die Kernpakete (NSwag.Core/NSwag.Generation/NSwag.AspNetCore) und NSwag.MSBuild unterstützen .NET Framework ≥4.6.2 – damit funktioniert 4.8 problemlos. ([www-1.nuget.org](https://www-1.nuget.org/packages/NSwag.Core/?utm_source=openai), [feed.nuget.org](https://feed.nuget.org/packages/NSwag.Generation/?utm_source=openai), [packages.nuget.org](https://packages.nuget.org/packages/NSwag.AspNetCore/?utm_source=openai))

Zusätzliche Hinweise

- Serializer: Für .NET Framework ist Newtonsoft.Json die pragmatische Wahl. Du kannst über jsonLibrary zwischen NewtonsoftJson und System.Text.Json wechseln (siehe Microsoft‑Blogbeitrag mit Beispiel). ([devblogs.microsoft.com](https://devblogs.microsoft.com/ise/2023/07/25/maintain-api-client-with-nswag-model-gen/?utm_source=openai))
- Best Practices: Auch wenn du List&lt;T&gt; erzwingst, sind für Parameter IEnumerable&lt;T&gt; und für öffentliche APIs häufig IReadOnlyList&lt;T&gt;/ICollection&lt;T&gt; sinnvoller. Wenn du aber explizit „List überall“ willst, setze responseArrayType ebenfalls auf List wie oben.

Wenn du mir deine Swagger/OpenAPI‑URL gibst, kann ich dir eine passende nswag.json mit genau den richtigen Settings für dein Projekt (.NET 4.8, Namespace, Dateinamen, usw.) vorbereiten.