Sign In

How to extract png positive prompt and save to txt file in the same directory (linux)

6

How to extract png positive prompt and save to txt file in the same directory (linux)

How to extract positive prompt from a png file made with forge or a1111 or any sd png that has the prompt in the parameters metadata. (in linux)

steps

create a c file for the script

nano extract_parameters.c

make sure libpng-dev is installed

sudo apt-get install libpng-dev

paste in the script:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <libpng16/png.h>
#include <sys/stat.h>

// Function to check if a file has a .png extension
int is_png(const char *filename) {
    const char *ext = strrchr(filename, '.');
    return ext && strcmp(ext, ".png") == 0;
}

// Function to extract "parameters" metadata
void extract_parameters(const char *png_file, const char *output_dir) {
    printf("Processing file: %s\n", png_file);

    FILE *fp = fopen(png_file, "rb");
    if (!fp) {
        perror("Failed to open PNG file");
        return;
    }

    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    png_infop info_ptr = png_create_info_struct(png_ptr);

    if (!png_ptr || !info_ptr) {
        fprintf(stderr, "Failed to initialize libpng\n");
        fclose(fp);
        return;
    }

    if (setjmp(png_jmpbuf(png_ptr))) {
        fprintf(stderr, "Error during PNG processing\n");
        fclose(fp);
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        return;
    }

    png_init_io(png_ptr, fp);
    png_read_info(png_ptr, info_ptr);

    png_textp text_ptr;
    int num_text;

    if (png_get_text(png_ptr, info_ptr, &text_ptr, &num_text) > 0) {
        printf("Found %d text entries in file: %s\n", num_text, png_file);
        for (int i = 0; i < num_text; i++) {
            printf("Key: %s\n", text_ptr[i].key);

            if (strcmp(text_ptr[i].key, "parameters") == 0) {
                char *parameters = text_ptr[i].text;

                // Find "Negative prompt:" and truncate
                char *negative_prompt = strstr(parameters, "Negative prompt:");
                if (negative_prompt) {
                    *negative_prompt = '\0';
                }

                // Print the truncated value
                printf("Extracted parameters metadata (truncated):\n%s\n", parameters);

                // Determine output file path
                char output_file[1024];
                const char *base_name = strrchr(png_file, '/'); // Get the base name
                base_name = base_name ? base_name + 1 : png_file; // Skip the slash if present

                if (output_dir) {
                    // Save to the specified output directory
                    snprintf(output_file, sizeof(output_file), "%s/%.*s.txt", 
                             output_dir, 
                             (int)(strrchr(base_name, '.') - base_name), 
                             base_name);
                } else {
                    // Save in the same directory as the input PNG
                    char input_dir[1024];
                    strncpy(input_dir, png_file, strrchr(png_file, '/') - png_file);
                    input_dir[strrchr(png_file, '/') - png_file] = '\0';
                    snprintf(output_file, sizeof(output_file), "%s/%.*s.txt", 
                             input_dir, 
                             (int)(strrchr(base_name, '.') - base_name), 
                             base_name);
                }

                // Write to file
                FILE *out_fp = fopen(output_file, "w");
                if (out_fp) {
                    fprintf(out_fp, "%s", parameters);
                    fclose(out_fp);
                    printf("Extracted metadata written to %s\n", output_file);
                } else {
                    perror("Failed to write metadata file");
                }
                break;
            }
        }
    } else {
        printf("No metadata found in file: %s\n", png_file);
    }

    fclose(fp);
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
}

// Function to process a directory
void process_directory(const char *dir_path, const char *output_dir) {
    DIR *dir = opendir(dir_path);
    if (!dir) {
        perror("Failed to open directory");
        return;
    }

    struct dirent *entry;
    while ((entry = readdir(dir)) != NULL) {
        if (entry->d_type == DT_REG && is_png(entry->d_name)) {
            char full_path[1024];
            snprintf(full_path, sizeof(full_path), "%s/%s", dir_path, entry->d_name);
            extract_parameters(full_path, output_dir);
        }
    }

    closedir(dir);
}

int main(int argc, char *argv[]) {
    if (argc < 2) {
        fprintf(stderr, "Usage: %s <directory> [output_directory]\n", argv[0]);
        return EXIT_FAILURE;
    }

    const char *input_dir = argv[1];
    const char *output_dir = NULL;

    if (argc >= 3) {
        output_dir = argv[2];

        // Check if output directory exists, create it if necessary
        struct stat st;
        if (stat(output_dir, &st) == -1) {
            if (mkdir(output_dir, 0700) == -1) {
                perror("Failed to create output directory");
                return EXIT_FAILURE;
            }
        } else if (!S_ISDIR(st.st_mode)) {
            fprintf(stderr, "Error: Output path is not a directory\n");
            return EXIT_FAILURE;
        }
    }

    process_directory(input_dir, output_dir);

    return EXIT_SUCCESS;
}

Compile the program:

gcc extract_parameters.c -o extract_parameters -lpng

Run program

./extract_parameters <input_directory> <output_directory>

you can run it with just input_directory and it will save the .txt file to the input_directory. this will run very fast.

6