Создать HTML-карту из изображения - PullRequest
12 голосов
/ 24 ноября 2008

Существует ли способ автоматической генерации совместимого с HTML-картой списка координат многоугольных объектов (например, стран на карте) с очень четкими границами?

Пример изображения:

Карта стран ЦВЕ 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>

Любые инструменты / скрипты, извлекающие координаты полигоноподобного выделения, были бы полезны.

Ответы [ 5 ]

10 голосов
/ 27 ноября 2008

Спасибо за вашу помощь!

Хотя Jonathans подсказка для использования фильтра Собела определенно будет работать, я выбрал Sparrs подход, состоящий в том, чтобы сначала преобразовать растровое изображение в векторное изображение (через 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();
}
8 голосов
/ 25 ноября 2008

Открыть карту в Inkscape. Если это растровое изображение, используйте Path -> Trace Bitmap, чтобы проследить края. Очистите векторные данные, чтобы они включали только те пути, которые вы хотите отобразить в вашей карте изображений. Сохраните документ, я предлагаю в файл POVRay. Теперь у вас есть список вершин (и множество разметки или метаданных, которые вас не интересуют) в текстовом формате. Преобразование из этого в требуемый синтаксис HTML все еще является проблемой, но не так сложно, как первый шаг.

Для чего бы то ни было, в Inkscape существует давний запрос на добавление опции экспорта карт изображений HTML.

1 голос
/ 24 ноября 2008

Я могу дать вам один шаг процесса: вам нужно будет использовать фильтр Собеля (часто называемый обнаружением краев в таких программах, как Photoshop).

После этого вам нужно будет найти библиотеку трассировки на вашем языке.

0 голосов
/ 22 сентября 2014

Кажется, функция "Герхард Динхоф" не правильная, и я тратил на это время. Здесь вы можете найти модифицированную версию, написанную на 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;
        }
    }
0 голосов
/ 22 октября 2011

Я внес некоторые изменения и реализацию в код Герхарда Динхофа.

Функция 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) );

?>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...