Есть ли способ автоматически создать совместимый с HTML-Map список координат многоугольных объектов (например, стран на карте) с очень четкими границами?
Пример изображения:
Карта стран ЦВЕ http://www.bankaustria.at/landkarten/CEE_2007_w524.jpg
Конечный результат:
<map id = "ceemap" name = "ceemap">
<area shape = "poly" coords = "149,303,162,301,162,298,171,293,180,299,169,309,159,306,148,306,149,303" href = "austria.html" target = "_blank" alt = "Austria" />
<!-- ... -->
</map>
Были бы полезны любые инструменты / скрипты, извлекающие координаты выделенного многоугольника.






Я могу дать вам один шаг процесса: вам нужно будет использовать фильтр Собеля (часто называемый обнаружением краев в таких программах, как Photoshop).
После этого вам нужно будет найти библиотеку трассировки на выбранном вами языке.
Откройте карту в Inkscape. Если это растровое изображение, используйте Path -> Trace Bitmap, чтобы отследить края. Очистите векторные данные, чтобы включить только те пути, которые вы хотите отобразить в карте изображений. Сохраните документ, предлагаю в файл POVRay. Теперь у вас есть список вершин (и множество разметки или метаданных, которые вам не нужны) в текстовом формате. Преобразование этого синтаксиса в необходимый HTML все еще является проблемой, но не такой сложной, как первый шаг.
Как бы то ни было, у Inkscape есть давний запрос функции, чтобы включить возможность экспорта карт изображений HTML.
Спасибо за вашу помощь!
Хотя намек Джонатанс на использование фильтра Собела определенно сработает, я выбрал подход Спарры, когда сначала преобразовываю растровое изображение в векторное изображение (через Inkscape), а затем обрабатываю файл SVG. После изучения некоторых основ спецификации SVG было довольно легко извлечь необходимые - для карт изображений HTML - координаты X / Y из всего остального мусора и сгенерировать подходящий код.
Хотя это не ракетостроение, кому-то может пригодиться этот фрагмент кода:
// input format: M 166,362.27539 C 163.525,360.86029 161.3875,359.43192 161.25,359.10124 C ...
private static void Svg2map(string svg_input)
{
StringBuilder stringToFile = new StringBuilder();
// get rid of some spaces and characters
var workingString = svg_input.Replace("z", "").Replace(" M ", "M").Replace(" C ", "C");
// split into seperate polygons
var polygons = workingString.Split('M');
foreach (var polygon in polygons)
{
if (!polygon.Equals(String.Empty))
{
// each polygon is a clickable area
stringToFile.Append("<area shape=\"poly\" coords=\"");
// split into point information
var positionInformation = polygon.Split('C');
foreach (var position in positionInformation)
{
var noise = position.Trim().Split(' ');
// only the first x/y-coordinates after C are relevant
var point = noise[0].Split(',');
foreach (var value in point)
{
var valueParts = value.Split('.');
// remove part after comma - we don't need this accurancy in HTML
stringToFile.Append(valueParts[0]);
// comma for seperation - don't worry, we'll clean the last ones within an area out later
stringToFile.Append(",");
}
}
stringToFile.AppendLine("\" href=\"targetpage.html\" alt=\"Description\" />");
}
}
// clean obsolete commas - not pretty nor efficient
stringToFile = stringToFile.Replace(",\"", "\"");
var fs = new StreamWriter(new FileStream("output.txt", FileMode.Create));
fs.Write(stringToFile.ToString());
fs.Close();
}
Я внес некоторые изменения и реализацию в код Герхарда Динхофа.
Функция PHP генерирует карту изображения с предоставленными координатами svg. Вы можете указать коэффициент, который изменяет размер области, и числа пересчета x-y, чтобы выровнять карту по вашему изображению.
<?php
/**
* $str SVG coordinates string
* $factor number that multiply every coordinate (0-1)
* $x translation on the x-axis
* $y translation on the y-axis
*/
function svg2imap($str, $factor=1, $x=0, $y=0) {
$res = "";
$str = str_replace(array(" M ","M ", " C "," z "," z"),array("M","M","C","",""), $str);
$polygons = explode("M", $str);
for($i=0; $i<count($polygons); $i++) {
if ($polygons[$i]! = "") {
$res .= "<area shape=\"poly\" coords=\"";
$coordinates = explode("C", $polygons[$i]);
foreach( $coordinates as $position ) {
$noise = explode(" ", trim($position));
$point = explode(",", $noise[0]);
for($j=0; $j<2; $j++) {
$val = round( $point[$j]*$factor, 0);
if ($j==0)
$res .= ($val + $x).",";
else
$res .= ($val + $y).",";
}
}
$res .= "\" href=\"link.html\" alt=\"desc\" />";
}
}
return $res = str_replace(",\"","\"", $res);;
}
?>
<?php
$svg = "M 6247.5037,5935.0511 C 6246.0707,5940.7838 6247.5037,5947.9495 C 6243.2043,5959.4149 z";
highlight_string( svg2imap($svg, $factor=0.33, $x=0, $y=0) );
?>
Это не совсем работает с svg в inkscape. вроде у всех. и он полон уродливого кода. не публикуйте это, этот сайт предназначен для ПОМОЩИ людям.
Кажется, функция "Герхарда Динхофа" некорректна, и я зря тратил на это время. Здесь вы можете найти измененную версию, написанную на C#, для преобразования простого файла SVG в соответствующие коды карт HTML. Использование: MessageBox.Show (Svg2map ("c: \ test.svg"))
// Sample file contents:
// <?xml version = "1.0" encoding = "UTF-8" ?>
// <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
// <svg width = "739pt" height = "692pt" viewBox = "0 0 739 692" version = "1.1" xmlns = "http://www.w3.org/2000/svg">
// <path fill = "#fefefe" d = " M 0.00 0.00 L 190.18 0.00 C 188.15 2.70 186.03 5.53 185.30 8.90 L 0.00 0.00 Z" />
// </svg>
private string Svg2map(string svg_file_path)
{
string[] svgLines = File.ReadAllLines(svg_file_path);
string svg = string.Join("", svgLines).ToLower();
int temp;
int w = int.Parse(ExtractData(svg,0,out temp, "<svg", "width").Replace("pt", "").Replace("px", ""));
int h = int.Parse(ExtractData(svg, 0, out temp, "<svg", "height").Replace("pt", "").Replace("px", ""));
StringBuilder stringToFile = new StringBuilder();
stringToFile.AppendLine(string.Format("<img id=\"image1\" src=\"image1.jpg\" border=\"0\" width=\"{0}\" height=\"{1}\" orgwidth=\"{0}\" orgheight=\"{1}\" usemap=\"#map1\" alt=\"\" />", w, h));
stringToFile.AppendLine("<map name=\"map1\" id=\"map1\">");
byte dataKey1 = (byte)'a';
byte dataKey2 = (byte)'a';
int startIndex = 0;
int endIndex = 0;
while (true)
{
string color = ExtractData(svg, startIndex, out endIndex, "<path", "fill");
string svg_input = ExtractData(svg, startIndex, out endIndex, "<path", "d = ");
if (svg_input == null)
break;
startIndex = endIndex;
/// Start..
stringToFile.Append(string.Format("<area data-key=\"{0}{1}\" shape=\"poly\" href=\"targetpage.html\" alt=\"Description\" coords=\"", (char)dataKey1, (char)dataKey2));
dataKey1 += 1;
if (dataKey1 > (byte)'z')
{
dataKey2 += 1;
dataKey1 = (byte)'a';
}
bool bFinished = false;
while (!bFinished)
{
string[] points = new string[0];
string pattern = "";
svg_input = svg_input.ToUpper().Trim();
char code = svg_input[0];
switch (code)
{
case 'M':
case 'L':
pattern = svg_input.Substring(0, svg_input.IndexOf(" ", svg_input.IndexOf(" ", svg_input.IndexOf(" ") + 1) + 1));
svg_input = svg_input.Remove(0, pattern.Length);
points = pattern.Trim().Substring(1).Trim().Split(' ');
break;
case 'C':
pattern = svg_input.Substring(0, svg_input.IndexOf(" ", svg_input.IndexOf(" ", svg_input.IndexOf(" ", svg_input.IndexOf(" ", svg_input.IndexOf(" ", svg_input.IndexOf(" ", svg_input.IndexOf(" ") + 1) + 1) + 1) + 1) + 1) + 1));
svg_input = svg_input.Remove(0, pattern.Length);
points = pattern.Trim().Substring(1).Trim().Split(' ');
break;
case 'Z':
bFinished = true;
continue;
default:
throw new Exception("Invalid pattern");
}
int count = points.Length;
if (count > 4)
count = 4;
for (int i = 0; i < count; i++)
{
var valueParts = points[i].Split('.');
// remove part after comma - we don't need this accurancy in HTML
stringToFile.Append(valueParts[0]);
// comma for seperation - don't worry, we'll clean the last ones within an area out later
stringToFile.Append(",");
}
}
stringToFile.AppendLine("\" />");
}
// clean obsolete commas - not pretty nor efficient
stringToFile.AppendLine("</map>");
stringToFile = stringToFile.Replace(",\"", "\"");
return stringToFile.ToString();
}
private string ExtractData(string data, int startIndex, out int endIndex, string key, string param)
{
try
{
endIndex = 0;
int a = data.IndexOf(key, startIndex);
int a2 = data.IndexOf(key, a + key.Length);
if (a2 == -1)
a2 = data.IndexOf(">", a + key.Length);
int b = data.IndexOf(param, a + key.Length);
int start = data.IndexOf("\"", b + param.Length) + 1;
int end = data.IndexOf("\"", start + 1);
if (b > a2 || start > a2 || end > a2)
return null;
int len = end - start;
endIndex = end;
string t = data.Substring(start, len);
return t;
}
catch
{
endIndex = 0;
return null;
}
}
К сожалению, я не могу определить, что это за язык, просто взглянув на него. Контрольная "var" говорит о javascript, но заголовки больше похожи на C++ или Java. T.T; это C# ??? Может быть?