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

Y=0,299 R+0,587 G+0,114 BY = 0{,}299\,R + 0{,}587\,G + 0{,}114\,B

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 bb zu hoch ist, könnt ihr das Bild um einen Faktor (target/b)(\mathrm{target} / b) abdunkeln. Am einfachsten geht das mit einem ColorMatrix und Graphics.DrawImage:

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:

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

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

Performance-Tipp

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

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

Filter- und Ausdruckssyntax (BsonExpression)


Aggregationen & Funktionen

Funktion Beschreibung Beispiel
`COUNT(<Feld *>)` Anzahl Elemente/Gruppengröße
SUM(<Feld>) Summe numerischer Werte SUM(Price)
MIN/MAX(<Feld>) Kleinster/Größter Wert MAX(Date)
AVG(<Feld>) Durchschnitt AVG(Rating)
TOLOWER/TOUPPER() Text in Klein-/Großbuchstaben TOUPPER(Name)
TRIM/LENGTH/SUBSTR Zeichenketten-Funktionen TRIM(Title), LENGTH(Text)
DATETIME(x) Wandelt Timestamp/String → DateTime DATETIME(CreatedAt)

Hinweis: Zusätzlich unterstützen alle BsonExpression-Funktionen (docs) u. a. IIF, ISNULL, ROUND, CEIL, FLOOR.


Beispiele

-- 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

Wo bekomme ich NSwag her?

Beispiel: C#‑Client mit List<T> statt T[] Variante A: nswag.json (empfohlen, reproduzierbar)

Beispieldatei (wichtige Stellen markiert)

{
  "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"
    }
  }
}

Aufruf

<!-- 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>

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

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"

Variante C: NSwagStudio (GUI)

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

Kompatibilität .NET Framework 4.8

Zusätzliche Hinweise

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.