Add image file processor (resize image files)

Use this forum to request features. Maybe you'll get lucky!
Mister Anderson
Posts: 6
Joined: Tue Aug 02, 2022 12:52 pm

Add image file processor (resize image files)

Post by Mister Anderson »

Hi, so I've been using FFAStrans in a fairly basic capacity, to simply provide a network folder where users can dump video files in the "input" folder, then collect compressed versions (i.e. 720 pixels high, calculated width to maintain AR, lower bitrate) from the "output" folder when they appear. Works great and users can automatically compress videos taken from their phones etc.

However, I would love to have the same capability for plain image files. There are plenty of reasons to need image files compressed or at specific resolutions, and it seems that ffmpeg at least should be able to resize them. I would have to think it should be a fairly simple addition. There are already some processor nodes related to image files such as the Image Sequence node so I am guessing it's possible.

I know resizing image files is typically very simple but having an automated system with preset sizings would be amazing.
emcodem
Posts: 1811
Joined: Wed Sep 19, 2018 8:11 am

Re: Add image file processor (resize image files)

Post by emcodem »

Mr. Anderson, welcome back. We missed you.
- 'The Matrix Revolutions', 2003.

So image processing is a huge topic on it's own considering transparency, self contained sequences, continuously popping up new formats, propreitary formats etc... not to mention image colours, i cannot even imagine what images can do in this area ^^
But keeping it simple, you can already do lots of stuff with the existing processors, starting with image decoder.
The rest depends on your requirements, e.g. what format would you encode to (image or video), what kind of images would you expect as source and which features do they have (transparency)?

Also "sizing presets" can be done already but i'd like to ask what exactly you had in mind? Is it simple wxh->wxh mapping table?
emcodem, wrapping since 2009 you got the rhyme?
Mister Anderson
Posts: 6
Joined: Tue Aug 02, 2022 12:52 pm

Re: Add image file processor (resize image files)

Post by Mister Anderson »

Well, I'm imaging a very basic processor to simply compress and reduce the size of images, and output as JPG or PNG, either being fine. PNG handles transparency but JPG is more common for photo files.

I'm thinking of a simple watch folder that sees image files, takes the height and width, determines aspect ratio, resizes to a pre-defined width while keeping the aspect ratio correct for the height, converts the file to JPG, then outputs it in another folder and deletes it from the original folder.

I have pretty much this exact workflow going for video files, however I can't see an image processor node like there is for h.264 files to then do the actual conversion. I have all the conditional and calculation nodes working to set the sizing etc.

I have just realized I am only running v1.0.0 so I will update and have a look and see if there are any new nodes I haven't seen yet.
emcodem
Posts: 1811
Joined: Wed Sep 19, 2018 8:11 am

Re: Add image file processor (resize image files)

Post by emcodem »

OK for such simple stuff you can just use imagemagic in a cmd processor, we ship a copy of imagemagic with ffastrans.
"%s_ffastrans_dir%\Processors\ImageMagick\convert.exe" "%s_source%" -resize 1024x1024 c:\temp\deliverfolder\%s_original_name%_resized.png
Imagemagick has lots of logic built in to do the usual stuff people want when working with images, e.g. it will automatically keep the aspect ratio.
But yeah, a simple processor for this could be fun too :D @admin is that something for you?
emcodem, wrapping since 2009 you got the rhyme?
admin
Site Admin
Posts: 1687
Joined: Sat Feb 08, 2014 10:39 pm

Re: Add image file processor (resize image files)

Post by admin »

Well, we have the "Stills" encoder which allows you to create images from any video or image source. So I guess it's a matter of adding resizing and such options to it. Would that do?

-steinar
Mister Anderson
Posts: 6
Joined: Tue Aug 02, 2022 12:52 pm

Re: Add image file processor (resize image files)

Post by Mister Anderson »

Yeah I think that would probably do the job, from what I can see. Do the existing variables for frame height etc. work on image files?
emcodem
Posts: 1811
Joined: Wed Sep 19, 2018 8:11 am

Re: Add image file processor (resize image files)

Post by emcodem »

Sorry for the delay. Those variables should work, only condition for it is that exiftool supports the file type afaik
emcodem, wrapping since 2009 you got the rhyme?
Mister Anderson
Posts: 6
Joined: Tue Aug 02, 2022 12:52 pm

Re: Add image file processor (resize image files)

Post by Mister Anderson »

Thanks everyone for your help so far. So I've got the following workflow set up (this is an adaptation of my previous workflow for compressing videos, so you can see how I've adjusted it).

It works and is taking .jpg files and outputting them as .png files, so that's all good.

The only thing I need now is help setting the output resolution for the Stills encoder. You can see where I am populating variables then handing to the H.264 encoder node for video, but with no options for it in the Stills node, I'm not sure how to pass it. Will this need a feature update or can I use another node to set resolution first?

Not sure how to attach a .json file from the exported workflow but here's the contents:

Code: Select all

{
  "workflow": {
    "wf_id": "20220811-1211-0094-12f5-19b8297ab25f",
    "wf_folder": "",
    "created": "2022-08-11T12:11:00.941+10:00",
    "description": "",
    "general": {
      "sleep": 30,
      "priority": "2 (normal)",
      "timeout_level": 3
    },
    "maintainance": {
      "keep_all_workdir": false,
      "keep_failed_workdir": false,
      "cleanup_time": "04:00",
      "records_age": 1,
      "work_age": 1,
      "run_on_days": 1234567
    },
    "farming": {
      "hosts": [],
      "include": false
    },
    "special": {
      "log_level": "1 (Basic)",
      "force_32bit": false,
      "read_timecode": false,
      "protected": false,
      "password": ""
    },
    "wf_name": "Compress image files_copy",
    "updated": "2022-08-11T12:12:29.357+10:00",
    "updated_by": "oc-gande104@computer",
    "variable": {
      "wf_size": 205.8
    },
    "nodes": [
      {
        "id": "20200420-1153-2253-00e8-4303ca9f4ca0",
        "type": "mon_folder",
        "custom_proc_guid": "",
        "bypass": false,
        "execute_on": "success",
        "outbounds": [
          {
            "type": "op_cond",
            "id": "20200827-0935-4719-9732-9993ae1f5bfd"
          }
        ],
        "name": "Folder",
        "description": "Monitor input folder",
        "properties": {
          "folder": "C:\\input",
          "accept_files": "",
          "deny": {
            "files": "",
            "folders": "",
            "attributes": {
              "read": false,
              "arch": false,
              "sys": false,
              "hidden": false
            }
          },
          "recurse": true,
          "localize": true,
          "create_folder": false,
          "growing_files": false,
          "forget_missing": true,
          "file_size_mod": "once",
          "file_limit": "None",
          "skip_verify": false
        },
        "preset": {
          "name": "(custom)",
          "id": null
        },
        "pos_x": 75,
        "pos_y": 247,
        "start_proc": true
      },
      {
        "id": "20200420-1156-2908-834d-5db19e7b36fd",
        "type": "enc_av_mp4",
        "custom_proc_guid": "",
        "bypass": false,
        "execute_on": "success",
        "outbounds": [
          {
            "type": "dest_folder",
            "id": "20200420-1157-3279-2300-3e17ecf46d0b"
          }
        ],
        "name": "H.264",
        "description": "Actual video conversion.",
        "preset": {
          "id": null,
          "name": "(custom)"
        },
        "properties": {
          "video": {
            "bitrate": 1500,
            "level": "auto",
            "profile": "auto",
            "tuning": "none",
            "qspeed": "veryfast",
            "interlacing": "Autodetect",
            "field_order": "Progressive",
            "width": "%i_new_width%",
            "height": "%i_new_height%",
            "restrict": false,
            "framerate": 30,
            "par": "1.0 Square",
            "dar": "Same as source",
            "resizing": "Stretch and lose aspect",
            "colorspace": "Auto"
          },
          "audio": {
            "bitrate": 128,
            "bitdepth": 16,
            "codec": "aac",
            "samplerate": 48000,
            "db_adjust": -23,
            "loudness_table": "",
            "loudness_enable": false,
            "layout": "default",
            "streams": [
              {
                "codec": "aac",
                "samplerate": 48000,
                "bitrate": 128,
                "bitdepth": 16,
                "mapping": [
                  1,
                  2
                ]
              }
            ]
          },
          "wrapper": "MP4",
          "start_tc": "%s_start_tc%",
          "custom_x264opts": "",
          "faststart": true
        },
        "pos_x": 1927,
        "pos_y": 247,
        "start_proc": false
      },
      {
        "id": "20200420-1157-3279-2300-3e17ecf46d0b",
        "type": "dest_folder",
        "custom_proc_guid": "",
        "bypass": false,
        "execute_on": "success",
        "outbounds": [
          {
            "type": "op_hold",
            "id": "20200421-1029-5669-1b94-f790016599fc"
          }
        ],
        "name": "Folder",
        "description": "Place converted file in output folder.",
        "preset": {
          "id": null,
          "name": "(custom)"
        },
        "properties": {
          "folder": "C:\\output",
          "suffix": "",
          "prefix": "",
          "overwrite": false,
          "unique": true,
          "case": "None",
          "drop_name": false,
          "drop_ext": false,
          "move": false,
          "padding": "None"
        },
        "pos_x": 2235,
        "pos_y": 247,
        "start_proc": false
      },
      {
        "id": "20200420-1330-1409-8618-2ee2675ab731",
        "type": "cmd_run",
        "custom_proc_guid": "",
        "bypass": false,
        "execute_on": "success",
        "properties": {
          "command": "%comspec% \/c \"del \/f \/q \"%s_original_full%\"\"",
          "out_source": "",
          "omit_exit_code": false,
          "console": false,
          "show_command": true,
          "stdout_var_name": "None",
          "set_timeout": 120,
          "error_timeout": 1
        },
        "name": "Command executor",
        "description": "Deletes original file from the input folder.",
        "preset": {
          "name": "(custom)",
          "id": null
        },
        "outbounds": [],
        "pos_x": 2853,
        "pos_y": 247,
        "start_proc": false
      },
      {
        "id": "20200420-1658-5914-5ae4-bab2d365b42c",
        "type": "op_populate",
        "custom_proc_guid": "",
        "bypass": false,
        "execute_on": "success",
        "properties": {
          "variables": [
            {
              "name": "i_new_height",
              "data": 720,
              "type": "integer"
            },
            {
              "name": "s_par_width",
              "data": "$regext('%s_pix_aspect%','(\\d+:)')",
              "type": "string"
            },
            {
              "name": "s_par_width",
              "data": "$trimr(\"%s_par_width%\",1)",
              "type": "string"
            },
            {
              "name": "s_par_height",
              "data": "$regext('%s_pix_aspect%','(:\\d+)')",
              "type": "string"
            },
            {
              "name": "s_par_height",
              "data": "$triml(\"%s_par_height%\",1)",
              "type": "string"
            },
            {
              "name": "f_par_decimal",
              "data": "%s_par_width%/%s_par_height%",
              "type": "float"
            },
            {
              "name": "i_new_width",
              "data": "(%i_width%*%f_par_decimal%/%i_height%)*%i_new_height%",
              "type": "integer"
            },
            {
              "name": "i_new_width",
              "data": "$round(%i_new_width%/2)*2",
              "type": "integer"
            }
          ]
        },
        "preset": {
          "name": "(custom)",
          "id": null
        },
        "outbounds": [
          {
            "type": "enc_stills",
            "id": "20220811-1206-2631-1a3d-f310e63fe573"
          }
        ],
        "name": "Populate variables",
        "description": "Set the correct resolutions for the conversion based on desired vertical resolution.\r\n\r\n(Change vertical resolution here to whatever is desired; match the previous Conditional node)",
        "pos_x": 692,
        "pos_y": 247,
        "start_proc": false
      },
      {
        "id": "20200421-1029-5669-1b94-f790016599fc",
        "type": "op_hold",
        "custom_proc_guid": "",
        "bypass": false,
        "execute_on": "success",
        "preset": {
          "name": "(custom)",
          "id": null
        },
        "properties": {
          "syncronize": true,
          "sync_time": 3600,
          "sleep": false,
          "sleep_time": 60,
          "file_wait": false,
          "files_list": ""
        },
        "name": "Hold",
        "description": "Waits for Folder job on left to finish (may not be necessary).",
        "outbounds": [
          {
            "type": "cmd_run",
            "id": "20200420-1330-1409-8618-2ee2675ab731"
          }
        ],
        "pos_x": 2544,
        "pos_y": 247,
        "start_proc": false
      },
      {
        "id": "20200827-0935-4719-9732-9993ae1f5bfd",
        "type": "op_cond",
        "custom_proc_guid": "",
        "bypass": false,
        "execute_on": "success",
        "properties": {
          "dispel": false,
          "conditionals": [
            {
              "expression_1": "%i_height%",
              "operator": "larger than or equal to (>=)",
              "expression_2": 720,
              "decide": "Then"
            }
          ]
        },
        "outbounds": [
          {
            "type": "op_populate",
            "id": "20200420-1658-5914-5ae4-bab2d365b42c"
          },
          {
            "type": "op_populate",
            "id": "20200827-0940-5853-3805-6735fb674e68"
          }
        ],
        "name": "Conditional",
        "description": "Check if resolution is already lower than desired.\r\n\r\n(Change vertical resolution here to whatever is desired; match the next (upper) Populate variables node)",
        "preset": {
          "name": "(custom)",
          "id": null
        },
        "pos_x": 383,
        "pos_y": 247,
        "start_proc": false
      },
      {
        "type": "op_populate",
        "custom_proc_guid": "",
        "bypass": false,
        "id": "20200827-0940-5853-3805-6735fb674e68",
        "execute_on": "error",
        "preset": {
          "id": null,
          "name": "(custom)"
        },
        "properties": {
          "variables": [
            {
              "name": "i_new_height",
              "data": "%i_height%",
              "type": "integer"
            },
            {
              "name": "s_par_width",
              "data": "$regext('%s_pix_aspect%','(\\d+:)')",
              "type": "string"
            },
            {
              "name": "s_par_width",
              "data": "$trimr(\"%s_par_width%\",1)",
              "type": "string"
            },
            {
              "name": "s_par_height",
              "data": "$regext('%s_pix_aspect%','(:\\d+)')",
              "type": "string"
            },
            {
              "name": "s_par_height",
              "data": "$triml(\"%s_par_height%\",1)",
              "type": "string"
            },
            {
              "name": "f_par_decimal",
              "data": "%s_par_width%/%s_par_height%",
              "type": "float"
            },
            {
              "name": "i_new_width",
              "data": "(%i_width%*%f_par_decimal%/%i_height%)*%i_new_height%",
              "type": "integer"
            },
            {
              "name": "i_new_width",
              "data": "$round(%i_new_width%/2)*2",
              "type": "integer"
            }
          ]
        },
        "outbounds": [
          {
            "type": "enc_stills",
            "id": "20220811-1206-2631-1a3d-f310e63fe573"
          }
        ],
        "name": "Populate variables",
        "description": "Set the correct resolutions for the conversion, matching original vertical resolution.\r\n\r\n(Runs if your desired vertical resolution is GREATER than the original resolution to avoid increasing in size for no reason).",
        "pos_x": 692,
        "pos_y": 418,
        "start_proc": false
      },
      {
        "id": "20201110-0839-0878-3669-6dccf1e1185e",
        "type": "op_cond",
        "custom_proc_guid": "",
        "bypass": false,
        "execute_on": "success",
        "preset": {
          "id": null,
          "name": "(custom)"
        },
        "properties": {
          "dispel": false,
          "conditionals": [
            {
              "expression_1": "%i_a_channels%",
              "operator": "not equal to (\u2260), string",
              "expression_2": 1,
              "decide": "Then"
            }
          ]
        },
        "outbounds": [
          {
            "type": "enc_av_mp4",
            "id": "20200420-1156-2908-834d-5db19e7b36fd"
          },
          {
            "type": "dec_avmedia",
            "id": "20201110-0839-5478-4789-4e83d2b5c4d1"
          }
        ],
        "name": "Conditional",
        "description": "Check for single-channel audio, duplicate that audio to both L&R channels.",
        "pos_x": 1001,
        "pos_y": 247,
        "start_proc": true
      },
      {
        "id": "20201110-0839-5478-4789-4e83d2b5c4d1",
        "type": "dec_avmedia",
        "custom_proc_guid": "",
        "bypass": false,
        "execute_on": "error",
        "outbounds": [
          {
            "type": "avs_a_acmapper",
            "id": "20201110-0840-1556-27ae-4ea0c6fa5a51"
          }
        ],
        "preset": {
          "id": null,
          "name": "(custom)"
        },
        "properties": {
          "audio": {
            "use": true,
            "channels": 2,
            "method": "Intelligent"
          },
          "video": {
            "use": true,
            "format": "YUV 4:2:2 8bit",
            "method": "Intelligent"
          },
          "x64avisynth": true,
          "force8bit": true
        },
        "name": "A/V Media",
        "description": "Required for ChannelMapper to work.",
        "pos_x": 1309,
        "pos_y": 418,
        "start_proc": false
      },
      {
        "id": "20201110-0840-1556-27ae-4ea0c6fa5a51",
        "type": "avs_a_acmapper",
        "custom_proc_guid": "",
        "bypass": false,
        "execute_on": "success",
        "properties": {
          "mapping": [
            "1",
            "1",
            "3",
            "4",
            "5",
            "6",
            "7",
            "8",
            "9",
            "10",
            "11",
            "12",
            "13",
            "14",
            "15",
            "16",
            "17",
            "18",
            "19",
            "20",
            "21",
            "22",
            "23",
            "24",
            "25",
            "26",
            "27",
            "28",
            "29",
            "30",
            "31",
            "32"
          ],
          "muxing": "2 (stereo)"
        },
        "preset": {
          "name": "(custom)",
          "id": null
        },
        "outbounds": [
          {
            "type": "enc_av_mp4",
            "id": "20200420-1156-2908-834d-5db19e7b36fd"
          }
        ],
        "name": "ChannelMapper",
        "description": "Duplicates the original mono audio track to both L&R channels to avoid a silent channel being added.",
        "pos_x": 1618,
        "pos_y": 418,
        "start_proc": false
      },
      {
        "id": "20220715-1445-4954-771e-747482214800",
        "type": "op_populate",
        "custom_proc_guid": "",
        "bypass": false,
        "execute_on": "success",
        "pos_x": 75,
        "pos_y": 247,
        "start_proc": true,
        "name": "Populate variables",
        "outbounds": []
      },
      {
        "id": "20220811-1206-2631-1a3d-f310e63fe573",
        "type": "enc_stills",
        "custom_proc_guid": "",
        "name": "Stills",
        "slots": 1,
        "hosts_group": 0,
        "bypass": false,
        "start_proc": false,
        "pos_x": 1927,
        "pos_y": 75,
        "execute_on": "success",
        "preset": {
          "name": "(custom)",
          "id": null
        },
        "properties": {
          "format": "PNG",
          "force_digits": false,
          "digits": 4,
          "sequence": false,
          "quality": 8,
          "q_switch": false,
          "extract_type": 0,
          "every_n": 25,
          "distribute": 20,
          "sc_threshold": 5,
          "deinterlace": true
        },
        "outbounds": [
          {
            "type": "dest_folder",
            "id": "20200420-1157-3279-2300-3e17ecf46d0b"
          }
        ]
      }
    ],
    "version": "1.3.0.38"
  },
  "user_variables": {
    "variables": [
      {
        "name": "i_new_width",
        "data": "",
        "type": "integer"
      },
      {
        "name": "i_new_height",
        "data": "",
        "type": "integer"
      },
      {
        "name": "s_par_width",
        "data": "",
        "type": "string"
      },
      {
        "name": "s_par_height",
        "data": "",
        "type": "string"
      },
      {
        "name": "f_par_decimal",
        "data": "",
        "type": "float"
      }
    ]
  }
}
emcodem
Posts: 1811
Joined: Wed Sep 19, 2018 8:11 am

Re: Add image file processor (resize image files)

Post by emcodem »

There is currently no way for you to go with the existing stills encoder processor.
Here is a modified version of your workflow that goes with imagemagick commandline processor as proposed above.
Compress image files_copy.json
(16.43 KiB) Downloaded 396 times
emcodem, wrapping since 2009 you got the rhyme?
admin
Site Admin
Posts: 1687
Joined: Sat Feb 08, 2014 10:39 pm

Re: Add image file processor (resize image files)

Post by admin »

Mister Anderson, why don't you use the stills decoder and add a resize node after? It should give you the options you need. Of course going with the command executor version from @emcodem will also do.

-steinar
Post Reply