WordPressにメディアをアップするときに、ついでにAI画像のメタデータを読み込んで保存しておければ便利だなと思って作りました。
保存されたデータはwebui_prompt、webui_Negativeprompt、webui_metaというカスタムフィールドに登録されます。
webui_metaは配列となっていてwebui_meta[“step”]などで更に細かい情報を読み込めます。

こんな感じで表示されます。

//メタデータ追加処理
add_action('add_attachment', 'add_custom_metadata');
function add_custom_metadata($attachment_id)
{
    // metadataの加工処理    
    $metadata = get_webui_metadata($attachment_id);
    if(empty($metadata))return $post;
    update_post_meta($attachment_id, "webui_prompt", $metadata["prompt"]);
    update_post_meta($attachment_id, "webui_Negativeprompt", $metadata["Negativeprompt"]);
    update_post_meta($attachment_id, "webui_meta", $metadata["meta"]);
    foreach ($metadata["meta"] as $key => $value) {
        update_post_meta($attachment_id, "webui_" . $key, $value);
    }
    // metadataを保存
    return $post;
}
//メタデータ読み込み
function get_webui_metadata($attachment_id)
{
    $metadata = array();
    if(!$attachment_id)return $metadata;

    $webui_prompt = get_post_meta($attachment_id,"webui_prompt",true);

    if($webui_prompt){
        $metadata = get_Existing_metadata($attachment_id);
    }else{
        $extension = pathinfo(get_attached_file($attachment_id), PATHINFO_EXTENSION);
        //pngとjpgで処理変更
        if ($extension == 'jpg' || $extension == 'jpeg') {
            $metadata = get_jpg_metadata($attachment_id);
        }
        if ($extension == 'png') {
            $metadata = get_png_metadata($attachment_id);
        }
    }
    return $metadata;
}

// すでにメタデータがある場合
function get_Existing_metadata($attachment_id){
    $metadata = array(
        "prompt" => get_post_meta($attachment_id,"webui_prompt",true),
        "Negativeprompt" => get_post_meta($attachment_id,"webui_Negativeprompt",true),
        "meta" => get_post_meta($attachment_id,"webui_meta",true),
    );
    return $metadata;
}

//pngの処理
function get_png_metadata($attachment_id)
{
    //PNGシグネチャ
    define('PNG_SIGNATURE', "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a");
    $chunksize = 65536;
    $metadata = array();
    $path = get_attached_file($attachment_id);
    if(empty($path))return $metadata;
    
    $fp = fopen($path, 'rb');
    $total_read = 0;
    if (PNG_SIGNATURE === fread($fp, 8)) {
        $total_read = 8;
        error_log("read01:\n",3,get_stylesheet_directory(  ) . "/total.log");
        while ($chunkHeader = fread($fp, 8)) {
            //先頭8バイトから、チャンクデータの長さと種別を取得する
            $chunk = unpack('Nsize/a4type', $chunkHeader);
            //チャンクデータの種別
            $type = $chunk['type'];
            //チャンクデータの長さ
            $size = $chunk['size'];
            //チャンクデータ本体
            //Note: サイズ0の場合、fread関数がエラーを出すため空文字とする
            $data = (0 < $size) ? fread($fp, $size) : '';
            $crc = fread($fp, 4);
            //現在のチャンクデータを新しいファイルのデータに追加する
            if ($type === "tEXt") {
                error_log("read2:\n",3,get_stylesheet_directory(  ) . "/total.log");
                $separator = strpos($data, chr(0));
                $keyword = substr($data, 0, $separator++);
                $data = substr($data, $separator);
                if ($keyword == "parameters") {
                    error_log("read3:\n",3,get_stylesheet_directory(  ) . "/total.log");
                    $pos = strpos($data, "\nSteps:");
                    if ($pos !== false) {
                        error_log("read4:\n",3,get_stylesheet_directory(  ) . "/total.log");
                        $Negative_pos = strpos($data, "\nNegative prompt: ");
                        if ($Negative_pos !== false) {
                            $metadata["prompt"] = substr($data, 0, $Negative_pos);
                            error_log(print_r($metadata,true),3,get_stylesheet_directory(  ) . "/total.log");
                            $metadata["Negativeprompt"] = substr($data, $Negative_pos + strlen("\nNegative prompt: "), $pos - $Negative_pos - strlen("\nNegative prompt: "));
                            error_log(print_r($metadata,true),3,get_stylesheet_directory(  ) . "/total.log");
                        } else {
                            error_log("read4-2:\n",3,get_stylesheet_directory(  ) . "/total.log");
                            $metadata["prompt"] = substr($data, 0, $pos);
                            $metadata["Negativeprompt"] = "";
                        }
                        error_log(print_r($metadata,true),3,get_stylesheet_directory(  ) . "/total.log");
                    }
                    $metas = substr($data, $pos);
                    $meta_splits = explode(",", $metas ?? array());
                    foreach ($meta_splits as $meta_split) {
                        $keyvalue = explode(":", $meta_split ?? array());
                        $metadata['meta'][trim($keyvalue[0])] = $keyvalue[1];
                    }
                }
            }
            $total_read = $total_read + 12 + $size;
   
            if ($total_read > $chunksize) break;
        }
    }
    fclose($fp);
    return $metadata;
}

//jpgの処理
function get_jpg_metadata($attachment_id){
    $metadata = array();
    
    $path = get_attached_file($attachment_id);
    $exif = exif_read_data($path, 0, true);

    $data = $exif["COMPUTED"]["UserComment"]??"";
    $pos = strpos($data, "\nSteps:");
    if ($pos !== false) {
        $Negative_pos = strpos($data, "\nNegative prompt: ");
        if ($Negative_pos !== false) {
            $metadata["prompt"] = substr($data, 0, $Negative_pos);
            $metadata["Negativeprompt"] = substr($data, $Negative_pos + strlen("\nNegative prompt: "), $pos - $Negative_pos - strlen("\nNegative prompt: "));
        } else {
            $metadata["prompt"] = substr($data, 0, $pos);
            $metadata["Negativeprompt"] = "";
        }
    }
    $metas = substr($data, $pos);

    $meta_splits = explode(",", $metas ?? array());
    foreach ($meta_splits as $meta_split) {
        $keyvalue = explode(":", $meta_split ?? array());
        $metadata['meta'][trim($keyvalue[0])] = $keyvalue[1];
    }

    return $metadata;
}
//メディア詳細に表示
add_filter('attachment_fields_to_edit', 'add_custom_fields', 10, 2);
function add_custom_fields($form_fields, $post)
{
    $post_id = $post->ID;
    // 入力欄の追加
    $metadata = get_webui_metadata($post_id);
      
    if (get_post_meta($post_id, "webui_prompt", true)) {
        $prompt = get_post_meta($post_id, "webui_prompt", true);
    } else {
        $prompt = $metadata["prompt"];
    }
    $form_fields['webui_prompt'] = array(
    'label' => "Prompt",
    'input' => 'html',
    'html'  => '<textarea  name="attachments[webui][webui_prompt]"  class="widefat" />' . esc_attr($prompt)  . '</textarea>'
    );
    if (get_post_meta($post_id, "webui_Negativeprompt", true)) {
        $prompt = get_post_meta($post_id, "webui_Negativeprompt", true);
    } else {
        $prompt = $metadata["Negativeprompt"];
    }
    $form_fields['webui_Negativeprompt'] = array(
    'label' => "Negative Prompt",
    'input' => 'html',
    'html'  => '<textarea  name="attachments[webui][webui_Negativeprompt]"  class="widefat" />' . esc_attr($prompt)  . '</textarea>'
    );
    foreach ($metadata['meta'] as $key => $value) {
        $metakey = "webui_" . $key;
        if (get_post_meta($post_id, $metakey, true)) {
            $prompt = get_post_meta($post_id, $metakey, true);
        } else {
            $prompt = $value;
        }
        
        $form_fields[$metakey] = array(
        'label' => $key,
        'input' => 'html',
        'html'  => '<input  name="attachments[webui][' . $metakey . ']"  class="widefat" value="' . esc_attr($prompt) . '"/>'
        );
    }
    return $form_fields;
}
//メディアファイル保存時カスタムフィールド更新
add_filter('attachment_fields_to_save', 'save_custom_fields', 10, 2);
function save_custom_fields($post, $attachment)
{
    $post_id = $post["post_ID"];
    $metadata = $post["attachments"]["webui"];
    foreach ($metadata as $key => $value) {
        update_post_meta($post_id, $key, $value);
    }
    // metadataを保存
    return $post;
}

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です