Wir haben eine Landkarte als PNG. Nun wollen wir je nach Einstellung eine Region auf dieser Karte markieren und klickbar machen. Dazu erhalten wir weitere PNGs, auf welchen eine Region eingefärbt und der Rest transparent ist. Dieses PNG ist exakt gleich größ wie die Landkarte und wird im Web über die Landkarte gelegt.
Aufgabe: Verlinke diese Region.
Problem: Region hat beliebige Form (kein Quadrat,etc.). Man benötigt eine HTML Map mit einem Polygon als Area. Dazu benötigt man Koordinaten. Wir wollen aber nicht für 100e Regionen Koordinaten händisch finden.
Eingeschränkte Lösung 1: Kleine C# Klasse, welche das PNG öffnet und von allen vier Rändern weg abtastet und die Koordinaten in der Richtigen Reihenfolge retourniert. Einen Offset für eventuellen Rand kann man auch einstellen. Funktioniert bei einfachen geometrischen Objekten sehr gut (Rechteck, Kreis), scheitert aber bei ausgefallenen Objekten (siehe ANhang).
Lösung 2:Suche alle Pixel, welche ein transparentes Pixel als Nachbar haben. Danach starte bei beliebigem Pixel und wandere den Rand entlang und sortiere die Pixel. Danach werden Geraden gesucht und unnötige Punkte entfernt. Funktioniert mit allen getesteten Grafiken. Siehe Anhang.
Einfach dem Konstruktor einen Dateipfad oder einen Filestream übergeben. Auf das Ergebnis kann mit Properties zugegriffen werden. Kann in beliebige .Net Anwendung eingebaut werden. Ein kleines Test-PNG im Anhang.
Have fun.
Lösung 1:
Code csharp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.IO;
namespace PNG_Get_HTML_area
{
class BitmapZuHtmlKoordinaten
{
private string _filename;
private string _html_area;
private string _coords;
private List<pos> _li;
private Stream _stream;
private int _offset = 1;
public string HtmlArea { get { return _html_area; } }
public string Coords { get { return _coords; } }
struct pos
{
internal int x;
internal int y;
};
//kann exception werfen
public BitmapZuHtmlKoordinaten(Stream stream)
{
_stream = stream;
_li = new List<pos>();
this.calculateObjectBorderCoords();
this.buildHtmlArea();
}
//kann exception werfen
public BitmapZuHtmlKoordinaten(string filename)
{
_filename = filename;
_li = new List<pos>();
this.calculateObjectBorderCoords();
this.buildHtmlArea();
}
private void buildHtmlArea()
{
string temp = "<area shape=\"poly\" coords=\"";
string end = "\" href=\"{0}\" alt=\"{1}\" title=\"{2}\">";
foreach (pos p in _li)
{
_coords += p.x + "," + p.y + ",";
}
_coords = _coords.TrimEnd(',');
temp += _coords;
temp += end;
_html_area = temp;
}
private void calculateObjectBorderCoords()
{
Bitmap bitmap = null;
if (!String.IsNullOrEmpty(_filename) && !String.IsNullOrWhiteSpace(_filename))
bitmap = new Bitmap(_filename);
else if (_stream != null)
bitmap = new Bitmap(_stream);
//x ist Breite
//y ist Höhe
//oben nach unten
for (int i = _offset; i < bitmap.Size.Width - _offset; i++)
{
for (int j = _offset; j < bitmap.Size.Height - _offset; j++)
{
if (bitmap.GetPixel(i, j).A > 10)
{
pos neuespixel;
neuespixel.x = i;
neuespixel.y = j;
if (!_li.Contains(neuespixel))
_li.Add(neuespixel);
break;
}
}
}
//rechts nach links
for (int i = _offset; i < bitmap.Size.Height - _offset; i++)
{
for (int j = bitmap.Size.Width - 1 - _offset; j >= _offset; j--)
{
if (bitmap.GetPixel(j, i).A > 10)
{
pos neuespixel;
neuespixel.x = j;
neuespixel.y = i;
if (!_li.Contains(neuespixel))
_li.Add(neuespixel);
break;
}
}
}
//unten nach oben
for (int i = bitmap.Size.Width - 1 - _offset; i >= _offset; i--)
{
for (int j = bitmap.Size.Height - 1 - _offset; j >= _offset; j--)
{
if (bitmap.GetPixel(i, j).A > 10)
{
pos neuespixel;
neuespixel.x = i;
neuespixel.y = j;
if (!_li.Contains(neuespixel))
_li.Add(neuespixel);
break;
}
}
}
//links nach rechts
for (int i = bitmap.Size.Height - 1 - _offset; i >= _offset; i--)
{
for (int j = _offset; j < bitmap.Size.Width - _offset; j++)
{
if (bitmap.GetPixel(j, i).A > 10)
{
pos neuespixel;
neuespixel.x = j;
neuespixel.y = i;
if (!_li.Contains(neuespixel))
_li.Add(neuespixel);
break;
}
}
}
}
static void Main(string[] args)
{
BitmapZuHtmlKoordinaten p1 = new BitmapZuHtmlKoordinaten(@"C:\Unbenannt.png");
}
}
} |
Lösung 2:
Code csharp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 | using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.IO;
namespace PNG_Get_HTML_area
{
class BitmapZuHtmlKoordinaten
{
private string _filename;
private string _html_area;
private string _coords;
private List<pos> _li;
private Stream _stream;
private int _offset = 1;
private int _toleranz = 10;
private Bitmap _bitmap = null;
public string HtmlArea { get { return _html_area; } }
public string Coords { get { return _coords; } }
struct pos
{
internal int x;
internal int y;
};
//kann exception werfen
public BitmapZuHtmlKoordinaten(Stream stream)
{
_stream = stream;
_li = new List<pos>();
this.calculateObjectBorderCoords();
this.buildHtmlArea();
}
//kann exception werfen
public BitmapZuHtmlKoordinaten(string filename)
{
_filename = filename;
_li = new List<pos>();
this.calculateObjectBorderCoords();
this.buildHtmlArea();
}
private void buildHtmlArea()
{
string temp = "<area shape=\"poly\" coords=\"";
string end = "\" href=\"{0}\" alt=\"{1}\" title=\"{2}\">";
foreach (pos p in _li)
{
_coords += p.x + "," + p.y + ",";
}
_coords = _coords.TrimEnd(',');
temp += _coords;
temp += end;
_html_area = temp;
}
private void calculateObjectBorderCoords()
{
if (!String.IsNullOrEmpty(_filename) && !String.IsNullOrWhiteSpace(_filename))
_bitmap = new Bitmap(_filename);
else if (_stream != null)
_bitmap = new Bitmap(_stream);
int nachbar = 0;
bool neustart;
do
{
neustart = false;
for (int i = _offset; i < _bitmap.Size.Width - _offset; i++)
{
for (int j = _offset; j < _bitmap.Size.Height - _offset; j++)
{
if (_bitmap.GetPixel(i, j).A > _toleranz)
{
//<7 transparente Nachbarn[def. rechts links oben unten und diagonale pixel]
nachbar = 0;
if (_bitmap.GetPixel(i - 1, j).A <= _toleranz)
nachbar++;
if (_bitmap.GetPixel(i + 1, j).A <= _toleranz)
nachbar++;
if (_bitmap.GetPixel(i, j - 1).A <= _toleranz)
nachbar++;
if (_bitmap.GetPixel(i, j + 1).A <= _toleranz)
nachbar++;
if (_bitmap.GetPixel(i + 1, j + 1).A <= _toleranz)
nachbar++;
if (_bitmap.GetPixel(i - 1, j + 1).A <= _toleranz)
nachbar++;
if (_bitmap.GetPixel(i + 1, j - 1).A <= _toleranz)
nachbar++;
if (_bitmap.GetPixel(i - 1, j - 1).A <= _toleranz)
nachbar++;
if (nachbar < 5 && nachbar > 0)
{
pos pixel;
pixel.x = i;
pixel.y = j;
_li.Add(pixel);
}
else if (nachbar >= 5)
{
//dieses "Sackgasse" pixel löschen von bild und berechnung neu starten (ineffizient gelöst)
_bitmap.SetPixel(i, j, Color.FromArgb(0, 0, 0, 0));
neustart = true;
//_li.Clear();
//break;
}
}
}
}
if (neustart)
_li.Clear();
} while (neustart);
if(_li.Count == 0)
return;
//alle Pixel durchgehen und immer direkt anliegendes nehmen
List<pos> li = new List<pos>();
pos start = _li[0];
_li.Remove(_li[0]);
pos temp = start;
bool gefunden;
do
{
gefunden = false;
foreach (pos px in _li)
{
if (px.x == temp.x - 1 && px.y == temp.y)
gefunden = true;
else if (px.x == temp.x + 1 && px.y == temp.y)
gefunden = true;
else if (px.x == temp.x && px.y == temp.y - 1)
gefunden = true;
else if (px.x == temp.x && px.y == temp.y + 1)
gefunden = true;
if (gefunden)
{
//System.Console.WriteLine("nn");
temp = px;
li.Add(temp);
_li.Remove(temp);
break;
}
}
if (!gefunden) //kann passieren, dass zu früh auf falsches pixel abgebogen wird, dann ist liste nicht leer.
break;
} while (_li.Count > 0);
_li = li;
//wenn Koordinaten Gerade bilden werden unnötige Punkte entfernt.
bool aufraumen;
do
{
aufraumen = false;
if (_li.Count < 3)
break;
for (int i = 2; i < _li.Count; i++)
{
pos first = _li[i - 2];
pos second = _li[i - 1];
pos third = _li[i];
double divisor1 = (second.x - first.x);
double divisor2 = (third.x - second.x);
if (divisor1 != 0 && divisor2 != 0)
{
double steigung1 = (second.y - first.y) / (second.x - first.x);
double steigung2 = (third.y - second.y) / (third.x - second.x);
double hoeher = steigung1 > steigung2 ? steigung1 : steigung2;
double tiefer = hoeher == steigung1 ? steigung2 : steigung1;
if (hoeher - tiefer < 0.1)
{
_li.Remove(second);
aufraumen = true;
break;
}
}
else
{
if (divisor1 == divisor2)
{
_li.Remove(second);
aufraumen = true;
break;
}
}
}
} while (aufraumen);
static void Main(string[] args)
{
BitmapZuHtmlKoordinaten p1 = new BitmapZuHtmlKoordinaten(@"C:\suedsteiermark ot.png");
}
}
} |
Schwachstelle: ineffizient, aber da jedes Bild nur einmal berechnet wird und Daten dann in DB gespeichert werden ist das egal.



Kommentar schreiben

Bereiche
Kategorien
Forum - Programming





Artikel bewerten