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

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

ただいまの
回答率

88.10%

PHPで元画像の画質のまま縮小した画像を作成したい

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 2,484

score 10

前提・実現したいこと

PHPで元画像の画質を落とさずに画像を縮小し、サムネイルの画像を作成したいです。

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

色々なページを参考に(https://qiita.com/suin/items/b01eebc05209dba0eb3e 等)以下のコードを書きましたが、最後にアップロードされる画像が元の画像より多少ぼやけた画像となってしまう原因がわからず困っております。

該当のソースコード

以下、ソースコードになります。

$originalFile = TMP . $userId . DS . $imgName . '.' . $imageExt; // 元画像

list($originalWidth, $originalHeight, $type) = getimagesize($originalFile);
switch ($type) {
    case IMAGETYPE_JPEG:
        $originalImage = imagecreatefromjpeg($originalFile);
        break;
    case IMAGETYPE_GIF:
        $originalImage = imagecreatefromgif($originalFile);
        break;
    case IMAGETYPE_PNG:
        $originalImage = imagecreatefrompng($originalFile);
        break;
}

//small画像のサイズを指定
if (strpos($fileDir, 'comment_files/') === false) { // 縮小のみする場合
    if ($originalWidth > 300) {
        $thumbW = 300;
        $thumbH = $thumbW / $originalWidth * $originalHeight;
    } else {
        $thumbW = $originalWidth;
        $thumbH = $originalHeight;
    }

    $smallImage = imagecreatetruecolor($thumbW, $thumbH);
    imagesavealpha($smallImage, true);
    imagecopyresampled($smallImage, $originalImage, 0, 0, 0, 0, $thumbW, $thumbH, $originalWidth, $originalHeight);
} else { // 縮小してトリミングする場合
    $thumbW = 300;
    $thumbH = 300;

    if ($originalWidth > $originalHeight) {
        $diffW = $originalHeight;
        $diffH = $originalHeight;
    } elseif ($originalWidth < $originalHeight) {
        $diffW = $originalWidth;
        $diffH = $originalWidth;
    } elseif ($originalWidth === $originalHeight) {
        $diffW = $originalWidth;
        $diffH = $originalHeight;
    }

    $smallImage = imagecreatetruecolor($thumbW, $thumbH);
    imagesavealpha($smallImage, true);
    imagecopyresampled($smallImage, $originalImage, 0, 0, 0, 0, $thumbW, $thumbH, $diffW, $diffH);
}

switch ($type) {
    case IMAGETYPE_JPEG:
        imagejpeg($smallImage, '_small.' . $imageExt, 100);
        break;
    case IMAGETYPE_GIF:
        imagegif($smallImage, '_small.' . $imageExt);
        break;
    case IMAGETYPE_PNG:
        imagepng($smallImage, '_small.' . $imageExt, 0);
        break;
}

// ファイルをアップロード
if (!$this->formatUploadDataAndUpload(
    $imgName . '_small.' . $imageExt,
    $fileName . '_small',
    $fileDir
)) {
    return false;
}

仕様で縮小してトリミングするパターンと、ただ縮小するパターンとを分けて実装したのですが、どちらで生成した画像もぼやけた画像となってしまいます。

又、調べてimagejpeg、imagepngの第三引数に画像のクオリティを指定できるようだったので100にしてみたのですがぼやけたままでした。ここで指定する前にぼやけてしまう原因があるのかなと思いつつわからないままです。

些細なことでもアドバイスいただけると嬉しく思います。
どうぞよろしくお願いいたします。

追記

皆様ご回答ありがとうございます。
答えになっていなかったらすみません。
最終的にブラウザで横293.91ピクセルの画像表示枠にアップロードした画像を表示予定です。

tabuuさんからのcaseやifの分岐が想定していないコードを実行している可能性もある、とのことで
横300ピクセルの画像で登録してみたところ画質は変わらないようでした。
調べてみて新しくわかったのは、元画像(1098×22000ピクセル)の画像を横300ピクセルに縮小して生成した画像(サムネイル)と元画像を横300ピクセルで指定しブラウザでimageタグで囲い表示し、検証機能で確認した際、縦の長さがそれぞれ6010.93ピクセル(元画像)、6010ピクセル(サムネイル)となっていることに原因があるかもしれないとわかったのですが、round等駆使してみたのですがなぜか小数点が切り捨てられた画像が生成されてしまいます。
↑imagecopyresampled等を通ったときにfloatがintになってしまう過程で小数点が切り捨てられている?

また画像のぼやけ具合ですが
イメージ説明
実際に表示される画像を並べました。左側がぼけてしまうサムネイル、右側が縮小していない元画像になります。

追記の追記

ご回答、アドバイスいただきありがとうございます。
以下新しく確認したことになります。

・縦1000ピクセル程度の画像の同様な画像で横300ピクセルに縮小した場合
->上に添付しました画像と変わらないくらいにぼやけておりました。
・ブラウザではなくペイント等のアプリで表示した場合
->上記のソースを通して生成したサムネイル画像で確認いたしましたがぼやけておりました。
・サムネイル画像の縦と横の比率は元画像と同一か
->上記の1回目の追記とにかよりますが、厳密にいえば生成されたサムネイルの縦幅は6010.928961748634であってほしいのですが、小数点が切り捨てられてしまい縦幅6010となってしまっている為、多少の誤差がございます。

縮小しているのだからしょうがないというご意見が多数あるようで、しょうがないと片づけたい気持ちとなんだかすっきりしない気持ちとで悩ましいです。。

質問が拙くて申し訳ないのですが、何かわかることがあれば助言いただけると幸いです。
よろしくお願いいたします。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • k_n

    2019/01/08 17:09

    アドバイスありがとうございます!不慣れですみません。
    修正いたしましたm(__)m

    キャンセル

  • tabuu

    2019/01/09 08:24 編集

    以下ご確認いただけないでしょうか。
    ・1000ピクセル程度の同様な画像を300ピクセルに縮小した場合もぼやけるか?
    ・ブラウザではなくペイント等のアプリで表示した場合もぼやけるか?
    ・サムネイル画像の縦と横の比率は元画像と同一か?(追記)

    キャンセル

  • tabuu

    2019/01/10 08:48

    提示のプログラムのファイル名等を修正して手持ちの画像で実行してみましたが、それほどぼやけているという感じはしませんでした。
    実行はCentOSのPHP5.3.3、確認はWindows10のフォトです。
    オリジナル:2889x3840 (1.75MB)
    サムネイル縮小のみ:300x398 (34.6KB)
    サムネイルトリミング:300x300 (28.4KB)

    オリジナルの画像が大きいとか、アスペクト比が偏っているとか、縮小率が高いとか、
    利用しているライブラリでは無理がきているのかもしれませんね。
    他の方がおっしゃっているようにimageMagick等を利用してみてはいかがでしょうか。

    ※6000px等であれば利用しているモニタの解像度以上の画像サイズと思われます。
    他の方のおっしゃる通り二重三重の縮小の結果、ぼやけるのかもしれません。

    キャンセル

回答 4

+1

画像を縮小しているのですから、画質を下げないというのは不可能です。

imageconvolution関数を使用して画像をシャープにすればぼやけた感じを改善はできます。
http://php.net/manual/ja/function.imageconvolution.php

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

画像処理のライブラリは複数用意されています=こちら
GDの結果が気に入らないならimageMagickを利用するなど別の手段を検討ください

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

300ピクセルに縮小した画像を293.91ピクセルに表示するということは2度縮小していることになるのでそれが原因です。
縮小は1回に留めてください。縮小のたびにぼけます。
また、2回目の縮小の縮小率が小さい(というのか大きいというのか、つまり100%に近い)のも悪い条件です。せめて1回目の縮小を1000ピクセルくらいに大きくしてください。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

check解決した方法

0

皆様、ご回答アドバイスをたくさんいただき本当にありがとうございました。
imageconvolution関数を使用して画像をシャープにしてみたり、imageMagickを使ってみたり、諦めて横幅の指定をもう少し大きくしたりと少しでもよくできるように試行錯誤したいと思います。
ベストアンサー、決めかねるので自決とさせてください。
本当にありがとうございましたm(__)m

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 88.10%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る