How to resize WordPress images on upload to specific height and width without cropping it

WordPress’s image resizing does not artwork your image onto a canvas, it just resizes mages to fit, cropping if you tell it to.

add_image_size('contained-image', 300, 400);

will get you the image size you want, but not letterboxed.

Images will be resized to fit tightly within a 300×400 rectangle. However they won’t be padded out to 300×400 with a border saved as part of the image.

You ought to be able to achieve that in your CSS with something like

img.size-contained-image {
    width: 300px;
    height: 400px;
    object-fit: contain;
}

Although IE & older browsers won’t support this, there are polyfills.

If you’re calling the images into your theme, then you could wrap them in a div and use CSS to get your result.

It’s also possible to hook into WP’s resizing and do your own thing. Watermarking plugins do this, for example.