質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

1回答

3539閲覧

javascriptでcanvasから生成した画像をLaravelのStorageで保存すると、開いた際に「ファイルが壊れています」と出る

takaoS

総合スコア9

Laravel

LaravelとはTaylor Otwellによって開発された、オープンソースなPHPフレームワークです。Laravelはシンプルで表現的なシンタックスを持ち合わせており、ウェブアプリケーション開発の手助けをしてくれます。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

0クリップ

投稿2020/06/05 02:45

編集2020/06/05 02:50

発生している問題・エラーメッセージ

JavascriptのgetUserMediaを用いてwebカメラを実装し、撮影した画像をcanvasに表示し、その画像をLaravelのStorageを使ってlocalに保存するようなプログラムを作成しています。

一応、localへの保存まで動くのですが、保存した画像をMacで開こうとすると

「ファイル"sample.png"を開ませんでした。ファイルが壊れているか、"プレビュー"が認識しないフォーマットを使用している可能性があります。」

というメッセージが出て、開くことができません。

原因がわからず、そもそも本当に画像が壊れているのかすら分かりません。

前提

OS: macOS Catalina 10.15.4
Laravel: 7.12.0
webサーバ: nginx

Laradockで構築しています。

javascriptのコードは root/resources/js/ に作成し、npm run watchコマンドで変換しています。

最終的には、このプログラムで撮影した画像をAWS S3に保存し、別のプログラムでローカルにダウンロードしたいと考えています。

該当のソースコード

// web.php <?php use Illuminate\Support\Facades\Route; Route::get('/', 'TestController@index'); Route::post('/', 'TestController@store');
// capture_image.blade.php <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <link rel="stylesheet" href="{{ asset('css/style.css') }}"> <title>カメラ サンプル</title> <meta name="description" content=""> <meta name="keywords" content=""> <meta name="csrf-token" content="{{ csrf_token() }}"> </head> <body> <h2>Video</h2> <video id="video_area" width="640" height="480" style="background-color: #000" autoplay></video> <button id="start">映像表示開始</button> <button id="capture">撮影</button> <form id="image_form" action="{{ url('/') }}" method="post"> @csrf <input id="image" type="hidden" name="image" value=""> <input id="submit_image" type="submit" name="submit" value="送信"> </form> <canvas id="captured_image"></canvas> <script src="{{ asset('js/script.js') }}"></script> </body> </html>
// script.js npm run watchで変換する前です 'use strict'; var video_area = document.getElementById('video_area'); var start = document.getElementById('start'); var capture = document.getElementById('capture'); // 「映像表示開始」を押下で、getUserMedia を使って映像をに表示 start.addEventListener('click', () => { navigator.mediaDevices.getUserMedia({ video: true, audio: false }) .then(stream => video_area.srcObject = stream) .catch(err => alert(`${err.name} ${err.message}`)); }, false); // 「撮影」を押下で、canvasに撮影した画像を表示し、formの<input type=hidden>にダウンロードURLを埋め込み capture.addEventListener('click', () => { var ci = document.getElementById('captured_image'); var ci_context = ci.getContext('2d'); var va = document.getElementById('video_area'); ci.width = va.videoWidth; ci.height = va.videoHeight; ci_context.drawImage(va, 0, 0); document.getElementById('image').value = ci.toDataURL('image/png'); }, false);
// TestController.php <?php namespace App\Http\Controllers; use Illuminate\Http\Request; use Illuminate\Support\Facades\Storage; class TestController extends Controller { public function index() { return view('capture_image'); } public function store(Request $request) { $canvas = $request->input('image'); if (isset($canvas)) { $canvas = preg_replace('<data:image/png;base64,>', '', $canvas); $canvas = base64_decode($canvas); $result_image = imagecreatefromstring($canvas); Storage::disk('public')->put('sample.png', imagepng($result_image)); } return redirect('/'); } }

再現手順

  1. 「映像表示開始」をクリック
  2. 「撮影」をクリック
  3. 「送信」をクリック。root/storage/app/public/sample.png が作成される。
  4. Macで該当ファイルを表示(プレビュー.appをデフォルトで使用)すると、上述したエラーで開くことができない。

試したこと

①該当ファイルをchromeで開いてみても、表示されない(以下の添付画像参照)。
chromeで表示した場合

②script.jsに以下のコードを追加し実行すると、画像をローカルにダウンロードできる。

capture.addEventListener('click', () => { var ci = document.getElementById('captured_image'); var ci_context = ci.getContext('2d'); var va = document.getElementById('video_area'); ci.width = va.videoWidth; ci.height = va.videoHeight; ci_context.drawImage(va, 0, 0); document.getElementById('image').value = ci.toDataURL('image/png'); var link = document.createElement('a'); //追加 link.href = ci.toDataURL('image/png'); //追加 link.download = 'sample.png'; //追加 link.click(); //追加 }, false);

③TestController.phpを以下のように修正すると、ブラウザ上に画像を表示できる。

public function store(Request $request) { $canvas = $request->input('image'); if (isset($canvas)) { $canvas = preg_replace('<data:image/png;base64,>', '', $canvas); $canvas = base64_decode($canvas); $result_image = imagecreatefromstring($canvas); // 以下の一文をコメントアウト //Storage::disk('public')->put('sample.png', imagepng($result_image)); header('Content-Type: image/png'); //追加 imagepng($result_image); //追加 imagedestroy($result_image); //追加 } return redirect('/'); }

ということは、つまり、Storageの一文がうまく機能していないということでしょうか?

ご教授のほど、よろしくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

imagepng関数の使い方が適切ではないと思われます。

この関数は、ファイルやHTTPへの出力を行って、返り値はbooleanです(PHPマニュアル)。

投稿2020/06/05 02:56

maisumakun

総合スコア145183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2020/06/05 02:58

image系の関数を介さず、base64_decodeした$canvasをそのままファイルに書き出せばいいのではないでしょうか。
takaoS

2020/06/05 04:04

ご教授いただいた方法で解決しました! なるほど、imagecreatefromstring()ですら、そもそも必要なかったのですね。 迅速な回答、ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問