|
132 | 132 | chmod("poti/src/{$time}{$ext}",PERMISSION_FOR_DEST); |
133 | 133 | } |
134 | 134 | $thumbnail=""; |
135 | | - if(thumb("src/",$imgfile,$time,$w,$h)){ |
| 135 | + if(thumbnail_gd::thumb("src/",$imgfile,$time,$w,$h)){ |
136 | 136 | $thumbnail='thumbnail'; |
137 | 137 | } |
138 | 138 | } |
@@ -295,174 +295,248 @@ function check_pch_ext ($filepath) { |
295 | 295 | return ''; |
296 | 296 | } |
297 | 297 |
|
298 | | -//GD版が使えるかチェック |
299 | | -function gd_check(){ |
300 | | - $check = array("ImageCreate","ImageCopyResized","ImageCreateFromJPEG","ImageJPEG"); |
| 298 | +// thumbnail_gd.inc.php for PetitNote (C)さとぴあ @satopian 2021 - 2025 |
| 299 | +// https://paintbbs.sakura.ne.jp/ |
| 300 | +// originalscript (C)SakaQ 2005 http://www.punyu.net/php/ |
301 | 301 |
|
302 | | - //最低限のGD関数が使えるかチェック |
303 | | - if(get_gd_ver() && (ImageTypes() & IMG_JPG)){ |
304 | | - foreach ( $check as $cmd ) { |
305 | | - if(!function_exists($cmd)){ |
306 | | - return false; |
| 302 | +$thumbnail_gd_ver=20250707; |
| 303 | +// defined('PERMISSION_FOR_DEST') or define('PERMISSION_FOR_DEST', 0606); //config.phpで未定義なら0606 |
| 304 | +class thumbnail_gd { |
| 305 | + |
| 306 | + public static function thumb($path,$fname,$time,$max_w,$max_h,$options=[]): ?string { |
| 307 | + // $path=basename($path).'/'; |
| 308 | + $fname=basename($fname); |
| 309 | + $time=basename($time); |
| 310 | + if(!ctype_digit($time)) { |
| 311 | + return null; |
| 312 | + } |
| 313 | + $fname=$path.$fname; |
| 314 | + if(!is_file($fname)){ |
| 315 | + return null; |
| 316 | + } |
| 317 | + if(!self::gd_check()||!function_exists("ImageCreate")||!function_exists("ImageCreateFromJPEG")){ |
| 318 | + return null; |
| 319 | + } |
| 320 | + if((isset($options['webp'])||isset($options['thumbnail_webp'])) && !function_exists("ImageWEBP")){ |
| 321 | + return null; |
| 322 | + } |
| 323 | + |
| 324 | + $fsize = filesize($fname); // ファイルサイズを取得 |
| 325 | + list($w,$h) = GetImageSize($fname); // 画像の幅と高さを取得 |
| 326 | + $w_h_size_over = $max_w && $max_h && ($w > $max_w || $h > $max_h); |
| 327 | + $f_size_over = !isset($options['toolarge']) ? ($fsize>1024*1024) : false; |
| 328 | + if(!$w_h_size_over && !$f_size_over && !isset($options['webp']) && !isset($options['png2webp']) && !isset($options['png2jpeg'])){ |
| 329 | + return null; |
| 330 | + } |
| 331 | + if(!$w_h_size_over || isset($options['png2jpeg']) || isset($options['png2webp']) || !$max_w || !$max_h){//リサイズしない |
| 332 | + $out_w = $w; |
| 333 | + $out_h = $h; |
| 334 | + }else{// リサイズ |
| 335 | + $w_ratio = $max_w / $w; |
| 336 | + $h_ratio = $max_h / $h; |
| 337 | + $ratio = min($w_ratio, $h_ratio); |
| 338 | + $out_w = ceil($w * $ratio);//端数の切り上げ |
| 339 | + $out_h = ceil($h * $ratio); |
| 340 | + } |
| 341 | + |
| 342 | + $mime_type = mime_content_type($fname); |
| 343 | + if(!$im_in = self::createImageResource($fname,$mime_type)){ |
| 344 | + return null; |
| 345 | + }; |
| 346 | + // 出力画像(サムネイル)のイメージを作成 |
| 347 | + if(function_exists("ImageCreateTrueColor")){ |
| 348 | + $im_out = ImageCreateTrueColor($out_w, $out_h); |
| 349 | + |
| 350 | + if(self::isTransparencyEnabled($options, $mime_type)){//透明度を扱う時 |
| 351 | + imagealphablending($im_out, false); |
| 352 | + imagesavealpha($im_out, true);//透明 |
| 353 | + }else{//透明度を扱わない時 |
| 354 | + if(function_exists("ImageColorAlLocate") && function_exists("imagefill")){ |
| 355 | + $background = ImageColorAlLocate($im_out, 0xFF, 0xFF, 0xFF);//背景色を白に |
| 356 | + imagefill($im_out, 0, 0, $background); |
| 357 | + } |
307 | 358 | } |
| 359 | + |
| 360 | + }else{ |
| 361 | + $im_out = ImageCreate($out_w, $out_h); |
308 | 362 | } |
309 | | - }else{ |
310 | | - return false; |
311 | | - } |
312 | 363 |
|
313 | | - return true; |
314 | | -} |
| 364 | + // コピー&再サンプリング&縮小 |
| 365 | + if(function_exists("ImageCopyResampled")){ |
| 366 | + ImageCopyResampled($im_out, $im_in, 0, 0, 0, 0, $out_w, $out_h, $w, $h); |
| 367 | + }else{ |
| 368 | + ImageCopyResized($im_out, $im_in, 0, 0, 0, 0, $out_w, $out_h, $w, $h);//"ImageCopyResampled"が無効の時 |
| 369 | + } |
315 | 370 |
|
316 | | -//gdのバージョンを調べる |
317 | | -function get_gd_ver(){ |
318 | | - if(function_exists("gd_info")){ |
319 | | - $gdver=gd_info(); |
320 | | - $phpinfo=$gdver["GD Version"]; |
321 | | - $end=strpos($phpinfo,"."); |
322 | | - $phpinfo=substr($phpinfo,0,$end); |
323 | | - $length = strlen($phpinfo)-1; |
324 | | - $phpinfo=substr($phpinfo,$length); |
325 | | - return $phpinfo; |
326 | | - } |
327 | | - return false; |
328 | | -} |
| 371 | + if(isset($options['toolarge'])){ |
| 372 | + $outfile = self::overwriteResizedImage($im_out, $fname, $mime_type); |
| 373 | + }else{ |
| 374 | + $outfile = self::createThumbnailImage($im_out, $time, $options); |
| 375 | + } |
| 376 | + // 作成したイメージを破棄 |
| 377 | + self::safeImageDestroy($im_in); |
| 378 | + self::safeImageDestroy($im_out); |
| 379 | + |
| 380 | + if(!$outfile){ |
| 381 | + return null; |
| 382 | + } |
| 383 | + |
| 384 | + if(!chmod($outfile,PERMISSION_FOR_DEST)){ |
| 385 | + return null; |
| 386 | + } |
| 387 | + |
| 388 | + if(is_file($outfile)){ |
| 389 | + return $outfile; |
| 390 | + } |
| 391 | + return null; |
329 | 392 |
|
330 | | -function thumb($path,$fname,$time,$max_w,$max_h,$options=[]){ |
331 | | - $path='src/'; |
332 | | - $fname=basename($fname); |
333 | | - $time=basename($time); |
334 | | - $fname=$path.$fname; |
335 | | - if(!is_file($fname)){ |
336 | | - return; |
337 | | - } |
338 | | - if(!gd_check()||!function_exists("ImageCreate")||!function_exists("ImageCreateFromJPEG")){ |
339 | | - return; |
340 | 393 | } |
341 | | - if((isset($options['webp'])||isset($options['thumbnail_webp'])) && (!function_exists("ImageWEBP")||version_compare(PHP_VERSION, '7.0.0', '<'))){ |
342 | | - return; |
| 394 | + //GD版が使えるかチェック |
| 395 | + private static function gd_check(): bool { |
| 396 | + // GDモジュールが有効化されているか |
| 397 | + if (!extension_loaded('gd')) { |
| 398 | + return false; |
| 399 | + } |
| 400 | + // GDモジュールが動作可能か |
| 401 | + if (!function_exists('gd_info')) { |
| 402 | + return false; |
| 403 | + } |
| 404 | + // JPEGのサポートを確認 |
| 405 | + if (!(ImageTypes() & IMG_JPG)) { |
| 406 | + return false; |
| 407 | + } |
| 408 | + // JPEG出力関数の存在を確認 |
| 409 | + if (!function_exists('ImageJPEG')) { |
| 410 | + return false; |
| 411 | + } |
| 412 | + return true; |
343 | 413 | } |
344 | 414 |
|
345 | | - $fsize = filesize($fname); // ファイルサイズを取得 |
346 | | - list($w,$h) = GetImageSize($fname); // 画像の幅と高さとタイプを取得 |
347 | | - $w_h_size_over=($w > $max_w || $h > $max_h); |
348 | | - $f_size_over=!isset($options['toolarge']) ? ($fsize>1024*1024) : false; |
349 | | - if(!$w_h_size_over && !$f_size_over && !isset($options['webp'])){ |
350 | | - return; |
| 415 | + //GDのイメージを破棄 |
| 416 | + private static function safeImageDestroy($gdImage): void { |
| 417 | + if(PHP_VERSION_ID < 80000) {//PHP8.0未満の時は |
| 418 | + imagedestroy($gdImage); |
| 419 | + } |
351 | 420 | } |
352 | | - // リサイズ |
353 | | - $w_ratio = $max_w / $w; |
354 | | - $h_ratio = $max_h / $h; |
355 | | - $ratio = min($w_ratio, $h_ratio); |
356 | | - $out_w = $w_h_size_over ? ceil($w * $ratio):$w;//端数の切り上げ |
357 | | - $out_h = $w_h_size_over ? ceil($h * $ratio):$h; |
358 | | - |
359 | | - switch ($mime_type = mime_content_type($fname)) { |
360 | | - case "image/gif": |
361 | | - if(!function_exists("ImageCreateFromGIF")){//gif |
362 | | - return; |
363 | | - } |
364 | | - $im_in = @ImageCreateFromGIF($fname); |
365 | | - if(!$im_in)return; |
366 | | - |
367 | | - break; |
368 | | - case "image/jpeg": |
369 | | - $im_in = @ImageCreateFromJPEG($fname);//jpg |
370 | | - if(!$im_in)return; |
371 | | - break; |
372 | | - case "image/png": |
373 | | - if(!function_exists("ImageCreateFromPNG")){//png |
374 | | - return; |
375 | | - } |
376 | | - $im_in = @ImageCreateFromPNG($fname); |
377 | | - if(!$im_in)return; |
378 | | - break; |
379 | | - case "image/webp": |
380 | | - if(!function_exists("ImageCreateFromWEBP")||version_compare(PHP_VERSION, '7.0.0', '<')){//webp |
381 | | - return; |
382 | | - } |
383 | | - $im_in = @ImageCreateFromWEBP($fname); |
384 | | - if(!$im_in)return; |
385 | | - break; |
386 | 421 |
|
387 | | - default : return; |
| 422 | + // 透明度の処理を行う必要があるかを判断 |
| 423 | + private static function isTransparencyEnabled($options, $mime_type): bool { |
| 424 | + // 透明度を扱うオプションが設定されているか確認 |
| 425 | + $transparencyOptionsSet = isset($options['toolarge']) || isset($options['webp']) || isset($options['thumbnail_webp']) || isset($options['png2webp']); |
| 426 | + |
| 427 | + // 対象の画像形式で透明度がサポートされているか確認 |
| 428 | + $transparencySupportedFormats = ["image/png", "image/gif", "image/webp"]; |
| 429 | + |
| 430 | + // 透明度を扱うための関数が存在するか確認 |
| 431 | + $transparencyFunctionsAvailable = function_exists("imagealphablending") && function_exists("imagesavealpha"); |
| 432 | + |
| 433 | + return $transparencyOptionsSet && in_array($mime_type, $transparencySupportedFormats) && $transparencyFunctionsAvailable; |
388 | 434 | } |
389 | | - // 出力画像(サムネイル)のイメージを作成 |
390 | | - $exists_ImageCopyResampled = false; |
391 | | - if(function_exists("ImageCreateTrueColor")&&get_gd_ver()=="2"){ |
392 | | - $im_out = ImageCreateTrueColor($out_w, $out_h); |
393 | | - if((isset($options['toolarge'])||isset($options['webp'])||isset($options['thumbnail_webp'])) && in_array($mime_type,["image/png","image/gif","image/webp"])){ |
394 | | - if(function_exists("imagealphablending") && function_exists("imagesavealpha")){ |
395 | | - imagealphablending($im_out, false); |
396 | | - imagesavealpha($im_out, true);//透明 |
397 | | - } |
398 | | - }else{ |
399 | | - if(function_exists("ImageColorAlLocate") && function_exists("imagefill")){ |
400 | | - $background = ImageColorAlLocate($im_out, 0xFF, 0xFF, 0xFF);//背景色を白に |
401 | | - imagefill($im_out, 0, 0, $background); |
| 435 | + //各画像フォーマットのリソースを作成 |
| 436 | + private static function createImageResource($fname,$mime_type) { |
| 437 | + switch ($mime_type) { |
| 438 | + case "image/gif": |
| 439 | + if(!function_exists("ImageCreateFromGIF")){//gif |
| 440 | + return null; |
402 | 441 | } |
403 | | - } |
404 | | - // コピー&再サンプリング&縮小 |
405 | | - if(function_exists("ImageCopyResampled")){ |
406 | | - ImageCopyResampled($im_out, $im_in, 0, 0, 0, 0, $out_w, $out_h, $w, $h); |
407 | | - $exists_ImageCopyResampled = true; |
| 442 | + $im_in = @ImageCreateFromGIF($fname); |
| 443 | + if(!$im_in)return null; |
| 444 | + break; |
| 445 | + case "image/jpeg": |
| 446 | + $im_in = @ImageCreateFromJPEG($fname);//jpg |
| 447 | + if(!$im_in)return null; |
| 448 | + break; |
| 449 | + case "image/png": |
| 450 | + if(!function_exists("ImageCreateFromPNG")){//png |
| 451 | + return null; |
| 452 | + } |
| 453 | + $im_in = @ImageCreateFromPNG($fname); |
| 454 | + if(!$im_in)return null; |
| 455 | + break; |
| 456 | + case "image/webp": |
| 457 | + if(!function_exists("ImageCreateFromWEBP")){//webp |
| 458 | + return null; |
| 459 | + } |
| 460 | + $im_in = @ImageCreateFromWEBP($fname); |
| 461 | + if(!$im_in)return null; |
| 462 | + break; |
| 463 | + |
| 464 | + default : return null; |
408 | 465 | } |
409 | | - }else{$im_out = ImageCreate($out_w, $out_h);} |
410 | | - // コピー&縮小 |
411 | | - if(!$exists_ImageCopyResampled) ImageCopyResized($im_out, $im_in, 0, 0, 0, 0, $out_w, $out_h, $w, $h); |
412 | | - if(isset($options['toolarge'])){ |
413 | | - $outfile=$fname; |
414 | | - //本体画像を縮小 |
| 466 | + return $im_in; |
| 467 | + } |
| 468 | + |
| 469 | + //縮小した画像で上書き |
| 470 | + private static function overwriteResizedImage($im_out, $fname, $mime_type): ?string { |
| 471 | + $outfile=(string)$fname; |
| 472 | + //本体画像を縮小 |
415 | 473 | switch ($mime_type) { |
416 | 474 | case "image/gif": |
417 | 475 | if(function_exists("ImagePNG")){ |
418 | 476 | ImagePNG($im_out, $outfile,3); |
419 | 477 | }else{ |
420 | 478 | ImageJPEG($im_out, $outfile,98); |
421 | 479 | } |
422 | | - break; |
| 480 | + return $outfile; |
423 | 481 | case "image/jpeg": |
424 | 482 | ImageJPEG($im_out, $outfile,98); |
425 | | - break; |
| 483 | + return $outfile; |
426 | 484 | case "image/png": |
427 | 485 | if(function_exists("ImagePNG")){ |
428 | 486 | ImagePNG($im_out, $outfile,3); |
429 | 487 | }else{ |
430 | 488 | ImageJPEG($im_out, $outfile,98); |
431 | 489 | } |
432 | | - break; |
| 490 | + return $outfile; |
433 | 491 | case "image/webp": |
434 | | - if(function_exists("ImageWEBP")&&version_compare(PHP_VERSION, '7.0.0', '>=')){ |
| 492 | + if(function_exists("ImageWEBP")){ |
435 | 493 | ImageWEBP($im_out, $outfile,98); |
436 | 494 | }else{ |
437 | 495 | ImageJPEG($im_out, $outfile,98); |
438 | 496 | } |
439 | | - break; |
| 497 | + return $outfile; |
440 | 498 |
|
441 | | - default : return; |
| 499 | + default : return null; |
442 | 500 |
|
443 | 501 | } |
444 | | - |
445 | | - }elseif(isset($options['webp'])){ |
446 | | - $outfile='poti/webp/'.$time.'t.webp'; |
447 | | - ImageWEBP($im_out, $outfile,90); |
448 | | - |
449 | | - }elseif(isset($options['thumbnail_webp'])){ |
450 | | - $outfile='poti/thumb/'.$time.'s.webp'; |
451 | | - ImageWEBP($im_out, $outfile,90); |
452 | | - }else{ |
453 | | - $outfile='poti/thumb/'.$time.'s.jpg'; |
454 | | - // サムネイル画像を保存 |
455 | | - ImageJPEG($im_out, $outfile,90); |
456 | | - } |
457 | | - // 作成したイメージを破棄 |
458 | | - if(PHP_VERSION_ID < 80000) {//PHP8.0未満の時は |
459 | | - ImageDestroy($im_in); |
460 | | - ImageDestroy($im_out); |
461 | | - } |
462 | | - if(!chmod($outfile,PERMISSION_FOR_DEST)){ |
463 | | - return; |
464 | 502 | } |
| 503 | + //サムネイル作成 |
| 504 | + private static function createThumbnailImage($im_out, $time, $options): ?string { |
| 505 | + |
| 506 | + if(isset($options['png2jpeg'])){ |
| 507 | + |
| 508 | + $outfile=TEMP_DIR.$time.'.jpg.tmp';//一時ファイル |
| 509 | + ImageJPEG($im_out, $outfile,98); |
| 510 | + |
| 511 | + } elseif(isset($options['png2webp'])){ |
| 512 | + |
| 513 | + if(function_exists("ImageWEBP")){ |
| 514 | + $outfile=TEMP_DIR.$time.'.webp.tmp';//一時ファイル |
| 515 | + ImageWEBP($im_out, $outfile,98); |
465 | 516 |
|
466 | | - return is_file($outfile); |
| 517 | + }else{ |
| 518 | + $outfile=TEMP_DIR.$time.'.jpg.tmp';//一時ファイル |
| 519 | + ImageJPEG($im_out, $outfile,98); |
| 520 | + |
| 521 | + } |
| 522 | + |
| 523 | + } elseif(isset($options['webp'])){ |
| 524 | + |
| 525 | + $outfile="poti/webp/{$time}t.webp"; |
| 526 | + ImageWEBP($im_out, $outfile,90); |
| 527 | + |
| 528 | + }elseif(isset($options['thumbnail_webp'])){ |
| 529 | + |
| 530 | + $outfile="poti/thumb/{$time}s.webp"; |
| 531 | + ImageWEBP($im_out, $outfile,90); |
| 532 | + |
| 533 | + }else{ |
467 | 534 |
|
| 535 | + $outfile="poti/thumb/{$time}s.jpg"; |
| 536 | + // サムネイル画像を保存 |
| 537 | + ImageJPEG($im_out, $outfile,90); |
| 538 | + |
| 539 | + } |
| 540 | + return $outfile; |
| 541 | + } |
468 | 542 | } |
0 commit comments