sets your file handle to expect characters, and to encode into UTF-8 sequences then on the way out. But you are sending it pre-encoded byte sequences from the %map hash, which causes those bytes to be treated as character and encoded again by Perl IO

In contrast, your terminal is set to expect UTF-8-encoded data, but STDOUT isn't set to do any encoding at all (use open ':std' has no effect on its own, see below) so it passes your UTF-8-encoded bytes through unchanged which happens to be what the terminal expects

By the way, you have set a default open mode of :encoding(UTF-8) for input and output streams with

use open ':encoding(UTF-8)'

but have overridden it in your call to open. The :utf8 mode does a very basic translation from wide characters to byte sequences, but :encoding(UTF-8) is far more useful because it checks that each character being printed is a valid Unicode value. There is a good chance that it would have caught a mistake like this, and it would have been better to allow the default and write just

open my $final, '>', $result;

To keep things clean and tidy, your program should work in characters, and the file handles should be set to encode those characters to UTF-8 when those characters are printed

You can set UTF-8 as the default encoding for all newly-opened file handles as well as STDIN and STDOUT by adding

use open qw/ :std :encoding(utf-8) /;

to the top of your program (:encoding(utf-8) is preferable to :utf8) and remove all calls to encode. You had it almost right, but the :std and :encoding(utf-8) need to be in the same use statement

You should also add

use utf8;

at the very top so that you can use UTF-8 characters in the program itself

You also have a few incidental errors. For instance

In the statement

open my $in, '<', "$font" || die "can't open file: $!";

it is almost always wrong to quote a single scalar variable like $font unless it happens to be an object and you want to invoke the stringification method

You need or instead of ||, otherwise you're just testing the truth of $font

If I asked you what a variable called $in might contain I think you'd be hesitant; $in_fh is better and is a common idiom

It's always nice to put the name of the file into the die string as well as the reason from $!

Taking all of those into account makes your statement look like this

open my $in_fh, '<', $font or die qq{Unable to open "$font" for input: $!};

You should be consistent between upper and lower case scalar variables, and lower case is the correct choice. So

open my $OUTPUT, '>', $font || die "can't open file";

should be something like

open my $out_fh, '>', $font or die qq{Unable to open "$font" for output: $!};

The line

$/ = undef;

should be local $/ as you have used elsewhere, otherwise you are permanently modifying the input record separator for the rest of your program and modules. It also appears after the first read from the file handle, so your program will read and process one line, and then the whole of the rest of the file in the next iteration of the while loop

Email codedump link for Printing to a file vs printing to shell in Perl