|
2 | 2 | /** |
3 | 3 | * Plugin Name: SB Punks Registry |
4 | 4 | * Description: BurnedPunks/MuseumPunks registry + front-page mosaic + numeric permalinks + single punk layout. |
5 | | - * Version: 0.3.1 |
| 5 | + * Version: 0.3.2 |
6 | 6 | * Author: SB |
7 | 7 | */ |
8 | 8 |
|
@@ -172,7 +172,7 @@ public static function filter_sb_punk_link($permalink, $post, $leavename = false |
172 | 172 | } |
173 | 173 |
|
174 | 174 | public static function enqueue_assets() : void { |
175 | | - $ver = '0.3.1'; |
| 175 | + $ver = '0.3.2'; |
176 | 176 | wp_enqueue_style('sbpr', plugins_url('assets/sbpr.css', __FILE__), [], $ver); |
177 | 177 | wp_enqueue_script('sbpr', plugins_url('assets/sbpr.js', __FILE__), [], $ver, true); |
178 | 178 | } |
@@ -669,9 +669,9 @@ public static function render_status_box($post) : void { |
669 | 669 | const PUNK_IMAGE_BASE = 'https://www.larvalabs.com/public/images/cryptopunks/punk'; |
670 | 670 |
|
671 | 671 | /** |
672 | | - * Fetch punk PNG from Larva Labs |
| 672 | + * Fetch punk PNG from Larva Labs and scale up with nearest-neighbor |
673 | 673 | */ |
674 | | - private static function fetch_punk_image(int $punk_id) : string { |
| 674 | + private static function fetch_punk_image(int $punk_id, int $target_size = 480) : string { |
675 | 675 | if ($punk_id < 0 || $punk_id > 9999) return ''; |
676 | 676 |
|
677 | 677 | // Format: punk0001.png, punk0123.png, punk9999.png |
@@ -699,9 +699,84 @@ private static function fetch_punk_image(int $punk_id) : string { |
699 | 699 | return ''; |
700 | 700 | } |
701 | 701 |
|
| 702 | + // Scale up the 24x24 image to target size using nearest-neighbor |
| 703 | + $scaled = self::scale_image_nearest_neighbor($body, $target_size); |
| 704 | + if (!empty($scaled)) { |
| 705 | + return $scaled; |
| 706 | + } |
| 707 | + |
| 708 | + // Fallback to original if scaling fails |
702 | 709 | return $body; |
703 | 710 | } |
704 | 711 |
|
| 712 | + /** |
| 713 | + * Scale PNG image data using nearest-neighbor interpolation |
| 714 | + */ |
| 715 | + private static function scale_image_nearest_neighbor(string $image_data, int $target_size) : string { |
| 716 | + // Try Imagick first (best quality control) |
| 717 | + if (class_exists('Imagick')) { |
| 718 | + try { |
| 719 | + $im = new Imagick(); |
| 720 | + $im->readImageBlob($image_data); |
| 721 | + $im->setImageInterpolateMethod(Imagick::INTERPOLATE_NEAREST_NEIGHBOR); |
| 722 | + $im->resizeImage($target_size, $target_size, Imagick::FILTER_POINT, 1); |
| 723 | + $im->setImageFormat('png'); |
| 724 | + $result = $im->getImageBlob(); |
| 725 | + $im->destroy(); |
| 726 | + return $result; |
| 727 | + } catch (Exception $e) { |
| 728 | + error_log('SBPR: Imagick scaling failed - ' . $e->getMessage()); |
| 729 | + } |
| 730 | + } |
| 731 | + |
| 732 | + // Fallback to GD |
| 733 | + if (function_exists('imagecreatefrompng')) { |
| 734 | + $src = @imagecreatefromstring($image_data); |
| 735 | + if ($src === false) { |
| 736 | + error_log('SBPR: GD could not read image'); |
| 737 | + return ''; |
| 738 | + } |
| 739 | + |
| 740 | + $src_w = imagesx($src); |
| 741 | + $src_h = imagesy($src); |
| 742 | + |
| 743 | + $dst = imagecreatetruecolor($target_size, $target_size); |
| 744 | + if ($dst === false) { |
| 745 | + imagedestroy($src); |
| 746 | + return ''; |
| 747 | + } |
| 748 | + |
| 749 | + // Preserve transparency |
| 750 | + imagealphablending($dst, false); |
| 751 | + imagesavealpha($dst, true); |
| 752 | + $transparent = imagecolorallocatealpha($dst, 0, 0, 0, 127); |
| 753 | + imagefill($dst, 0, 0, $transparent); |
| 754 | + |
| 755 | + // Scale using nearest-neighbor (pixel-by-pixel copy) |
| 756 | + $scale = $target_size / $src_w; |
| 757 | + for ($y = 0; $y < $target_size; $y++) { |
| 758 | + for ($x = 0; $x < $target_size; $x++) { |
| 759 | + $src_x = (int)floor($x / $scale); |
| 760 | + $src_y = (int)floor($y / $scale); |
| 761 | + $color = imagecolorat($src, $src_x, $src_y); |
| 762 | + imagesetpixel($dst, $x, $y, $color); |
| 763 | + } |
| 764 | + } |
| 765 | + |
| 766 | + ob_start(); |
| 767 | + imagepng($dst); |
| 768 | + $result = ob_get_clean(); |
| 769 | + |
| 770 | + imagedestroy($src); |
| 771 | + imagedestroy($dst); |
| 772 | + |
| 773 | + return $result; |
| 774 | + } |
| 775 | + |
| 776 | + error_log('SBPR: No image library available for scaling'); |
| 777 | + return ''; |
| 778 | + } |
| 779 | + |
705 | 780 | /** |
706 | 781 | * Generate punk image and set as featured image |
707 | 782 | */ |
|
0 commit comments