Because, as you say, the input of file has to be filenames. The output of ls, however, is just text. That it happens to be a list of file names doesn't change the fact that it is simply text and not the location of files on the hard drive.
When you see output printed on the screen, what you see is text. Whether that text is a poem or a list of filenames makes no difference to the computer. All it knows is that it is text. This is why you can pass the output of ls to programs that take text as input (although you really, really shouldn't):
$ ls / | grep etc
etc
So, to use the output of a command that lists file names as text (such as ls or find) as input for a command that takes filenames, you need to use some tricks. The typical tool for this is xargs:
$ ls
file1 file2
$ ls | xargs wc
9 9 38 file1
5 5 20 file2
14 14 58 total
As I said before, though, you really don't want to be parsing the output of ls. Something like find is better (the print0 prints a \0 instead of a newilne after each file name and the -0 of xargs lets it deal with such input; this is a trick to make your commands work with filenames containing newlines):
$ find . -type f -print0 | xargs -0 wc
9 9 38 ./file1
5 5 20 ./file2
14 14 58 total
Which also has its own way of doing this, without needing xargs at all:
$ find . -type f -exec wc {} +
9 9 38 ./file1
5 5 20 ./file2
14 14 58 total
Finally, you can also use a shell loop. However, note that in most cases, xargs will be much faster and more efficient. For example:
$ for file in *; do wc "$file"; done
9 9 38 file1
5 5 20 file2