Why use the authorization code flow?
The printer needs an access token, and only you can approve one, at the photo service. Your approval happens in your browser, on the photo service's own pages, so its result has to travel back to the printer through your browser. A browser is a poor place to carry a token. Anything placed in a URL can end up in browser history, server logs, and referrer information sent to other sites, and nothing in a URL ties the token to the application that asked for it.
The authorization code flow splits the delivery in two. Your browser carries back only an authorization code, a short-lived, single-use value that the photo API will not accept. The printer then sends that code to the authorization server's token endpoint in a direct request of its own, and the access token comes back in the response. The token never appears in a URL or passes through your browser.
That direct request is also where the authorization server can check who is asking. The printer's backend is a confidential client, so it authenticates itself, and a code copied from the browser is not enough without the printer's credentials. The printer also presents its PKCE verifier, showing that it is the client instance that started this attempt. A token sent straight back through the browser would allow neither check.
Browser and mobile applications that cannot authenticate themselves use the same flow. For them, PKCE is the check that links the code to the attempt that requested it.