街中 テクスチャーギャラリー

## 1. 街中のテクスチャ収集をしています。
テクスチャーってわかりますか？
```テクスチャー (texture) とは、材料の表面の視覚的な色や明るさの均質さ、触覚的な比力の強弱を感じる凹凸といった部分的変化を、全体的にとらえた特徴、材質感覚、効果を指す。```
私はこんな感じの写真を意識的に撮ることをしています。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668122/5d74e390-1274-f5e8-2c84-630ace9dbd7d.jpeg" width="50%">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668122/0b3c8327-8572-ad05-3a54-17d8679a3cea.jpeg" width="50%">
元々は描いたイラストに合成して情報量を増やして見栄えを良くしたりするために集めていましたが、
どことなくアーティスティックな雰囲気を感じます。

**テクスチャー集めたHPギャラリーとかあったらお洒落くない？**
更にそのテクスチャーの画像から写真を撮影した場所が表示されたら、実際の元の風景も見に行くことが出来るかも。
ということで作ってみることに。

### 1-1. 作成したアプリはこちら

https://649afc34518162007fcb48df--earnest-sunburst-44764d.netlify.app/
画像をアップロードすると六角形に並べられていきます。
画像から位置情報を取得しているので六角形をクリックするとグーグルマップに飛びます。

### 1-2. 作成したコード


<details><summary> 作成したコード</summary>

```js
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>JavaScriptのFileAPIとcanvasで画像のプレビューと位置情報</title>
  <link rel="stylesheet" href="styles.css">
  <style>
    .image-container {
      display: flex;
      flex-wrap: wrap;
    }

    .hexagon {
      width: 200px;
      height: 200px;
      background-color: #a52a2a;
      margin: 10px;
      position: relative;
      overflow: hidden;
      clip-path: polygon(50% 0%, 95% 25%, 95% 75%, 50% 100%, 5% 75%, 5% 25%);
    }
  </style>
</head>
<body>
  <form>
    <input type="file" accept='image/*' onchange="previewImage(this);">
  </form>
  <p>
    Preview:<br>
    <canvas id="preview" style="max-width:200px;"></canvas>
  </p>
  <div id="image-gallery" class="image-container"></div>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/exif-js/2.3.0/exif.min.js"></script>
  <script src="script.js"></script>
  <script>
    function previewImage(obj) {
      const fileReader = new FileReader();
      fileReader.onload = function() {
        const canvas = document.getElementById('preview');
        const ctx = canvas.getContext('2d');
        const image = new Image();
        image.src = fileReader.result;
        image.onload = function() {
          canvas.width = image.width;
          canvas.height = image.height;
          ctx.drawImage(image, 0, 0);

          const gallery = document.getElementById('image-gallery');
          const hexagon = document.createElement('div');
          hexagon.className = 'hexagon';
          const hexagonImage = new Image();
          hexagonImage.src = fileReader.result;
          hexagonImage.style.width = '100%';
          hexagonImage.style.height = '100%';
          hexagon.appendChild(hexagonImage);

          EXIF.getData(image, function() {
            const lat = EXIF.getTag(this, 'GPSLatitude');
            const latRef = EXIF.getTag(this, 'GPSLatitudeRef');
            const lng = EXIF.getTag(this, 'GPSLongitude');
            const lngRef = EXIF.getTag(this, 'GPSLongitudeRef');

            if (lat && lng && latRef && lngRef) {
              const convertedLat = convertDMSToDD(lat, latRef);
              const convertedLng = convertDMSToDD(lng, lngRef);

              const locationInfo = document.createElement('p');
              locationInfo.innerHTML = 'Location: ' + convertedLat + ', ' + convertedLng;
              hexagon.appendChild(locationInfo);

              hexagon.addEventListener('click', function() {
                const googleMapsUrl = 'https://www.google.com/maps?q=' + convertedLat + ',' + convertedLng;
                window.open(googleMapsUrl);
              });
            }
          });

          gallery.appendChild(hexagon);
        };
      };
      fileReader.readAsDataURL(obj.files[0]);
    }

    function convertDMSToDD(coordinate, reference) {
      const degrees = coordinate[0];
      const minutes = coordinate[1];
      const seconds = coordinate[2];
      const direction = reference.toUpperCase();

      let dd = degrees + minutes / 60 + seconds / 3600;
      if (direction === 'S' || direction === 'W') {
        dd = -dd;
      }

      return dd.toFixed(6);
    }
  </script>
</body>
</html>


```
</details>

位置情報の取得はこちらのサイトを参考にさせていただきました。

https://blog.capilano-fw.com/?p=9502

複数画像の取得はこちらのサイト
プレビューが出るのがお気に入りです。

https://blog.ver001.com/javascript-image-preview-multiple/


お手本コードを探した後はいつも通り、ChatGPTに手伝ってもらっています。

### 1-3. 実際の画像
ファイルをアップロードすると画像の一部が六角形で表示されます。
六角形に切り取られていることも相まって、なんだかわからない感じがとても良いですね。
アートっぽい。
プレビューはアップロードした画像の全体が表示され、
切り取った一部の六角形と比較できるようにしているのがこだわりです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668122/9d563488-06eb-44c1-793a-be85db8e8db5.png)

今回は一番左側の六角形の画像をクリックするとGoogle Map 上に位置表示があらわれます。
どこだかわかりますか？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668122/5c809737-343a-f7f0-55d1-7fc43323120c.png)
盛大に位置情報がずれていますが、サンシャイン水族館の空飛ぶペンギン水槽の一部分の画像です。

## 2.実装内容
### 2-1. 画像からExifデータを取得
スマホやデジカメで写真を撮るとExifデータというものが自動で記録されています。
今回はExifデータの中から位置情報をJSで取得しています。

### 2-2.GoogleMap APIを利用して地図を表示
Google Embed Map の APIキーを取得して、位置情報からGoogle Mapに飛ぶように、画像にリンクを埋め込むコードにしています。

### 2-3. canvas APIで画像の加工
プレビュー画面の表示や画像の加工はcanvas要素を使用しています。
六角形は座標の指定で比較的簡単に作成できる図形だったので、今回はチョイスしました。
canvas要素を使えば、パスを利用して複雑な図形も描画できるようです。

### 2-4. CSSで装飾してみた
少しでもお洒落な感じを出したいのでこんな感じに
CodePenで作成しているのですが、CodePen 上で画像をクリックするとうまくGoogleMapに移行しませんが、
HTML、CSS、JS　を分けるとこんな感じです。

https://codepen.io/am003004/pen/qBQrZjy

こちらがお洒落にしたアプリのQR
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668122/7fb7024d-8588-6989-5a0f-41f7d2fbb93c.png)

https://649c294da1033000a753c5ec--deft-crostata-abf4d5.netlify.app/

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2668122/532728c3-78f8-6255-c2c6-d4d59d732e38.png)

## 3. iPhoneで撮った写真の位置情報が取得出来ない
### 3-1. HEIF形式の罠
お友達に触ってみてもらったんですが、写真をクリックしてもマップに飛ばないよとの指摘がありました。
自分でもiPhoneの写真アプリでは位置情報が表示できるのに、取得できない写真が多数ありました。
調べてみると、iPhoneで撮影したHEIF形式の写真はEXIF規格が異なるのでこのコードでは取得できないとのことです。

https://fa.hatenadiary.jp/entry/20200502/1588373190

位置情報が表示できてたのは古いiPhoneで撮影した、jpeg形式の写真だけでした！
困った。

### 3-2. 対処法jpegに変換する。
何のひねりもありませんが、他の画像ソフトでjpeg形式に変換したところ、無事に位置情報が取得できました。
ちなみにPNG形式の画像もうまく位置情報の取得が出来ないようです。
画像からEXIFを取得するのは思ってたよりも奥が深いです。

## 4. みんなで共有できるテクスチャーギャラリー
先ほどの写真はサンシャイン水族館だったので、ストリートビューで確認できませんでしたが、
他の写真に関してはストリートビューで実際どこの何か位置情報から探してもらえるようになったら良いと思っています。
今は自分の写真しかアップロードできないので、写真アプリでプレビューしているのとあまり変わりませんが、他の人の写真も見れたら、いつもとは違う景色の見方が出来て楽しいそうです。
ただし、自分の家とか特定されないように位置情報の取り扱いには要注意です。