2008-11-24 109 views
12

有沒有一種方法可以自動生成帶有非常鮮明邊框的多邊形對象(例如地圖上的國家)的HTML-Map兼容座標列表?從圖像生成HTML-Map

實施例圖像:

Map of CEE countries 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> 

任何工具/腳本中提取類似多邊形的選擇的座標將是有益的。

回答

8

在Inkscape中打開地圖。如果它是位圖,請使用路徑 - >跟蹤位圖來跟蹤邊緣。清理矢量數據以僅包含要在圖像映射中顯示的路徑。保存文件,我建議到一個POVRay文件。現在你有一個純文本格式的頂點列表(以及大量你不關心的標記或元數據)。將其轉換爲必要的HTML語法仍然是一個問題,但不像第一步那麼複雜。

對於它的價值,Inkscape有一個長期的功能要求,包括導出HTML圖像映射的選項。

1

我可以給你一個步驟的過程:你將需要使用索貝爾過濾器(通常稱爲Photoshop中的程序邊緣檢測)。

之後,您將需要找到您選擇的語言的跟蹤庫。

10

感謝您的幫助!

雖然Jonathans暗示使用Sobel濾波器肯定會工作,我選擇Sparrs的第一所述位圖轉換成矢量圖像(通過Inkscape中),然後處理該SVG文件的方法。 在學習了一些SVG規範的基礎知識之後,很容易從所有其他垃圾中提取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(); 
} 
+1

尷尬,我不能確定那是什麼語言只是看它。講述'var'表示JavaScript,但頭部看起來更像C++或Java。 T.T;是C#嗎?也許? – Ziggy 2012-11-29 19:28:55

0

我做了一些修改和實施格哈德Dinhof的代碼。

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

?> 
+1

這與inkscape的svg不兼容。就像一切。它充滿了難看的代碼。不要發佈,這個網站是爲了幫助人們。 – 2012-05-17 14:43:21

0

看起來「Gerhard Dinhof」功能不正確,我在這方面浪費了時間。 在這裏你可以找到一個用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; 
     } 
    }