I looked at mooncatparser and it just hardcodes all possible 2-bit art as a big string array constant at the top of the JS file. Definitely not "on the blockchain". The part that's stored on the blockchain is the index into the big string array.
Good job reading the code! It's as you should do when looking at a project.
Is there a way where the image can be replaced with another based on the scheme? I didn't see any, which achieves the same result as putting the image on-chain.
Avastars https://avastars.io/ is an NFT collection that's represented by an SVG. The SVGs are all written on-chain, back when it was cheaper to do so. https://nft.substack.com/p/the-art-of-avastars
The original NFT, Cryptopunks is also written on-chain now. (It wasn't originally). https://www.larvalabs.com/blog/2021-8-18-18-0/on-chain-crypt...
One of the oldest NFTs, MoonCatRescue https://mooncatrescue.com/ writes an encoded version of the image onchain, and uses a published function to regenerate the image. The MD5 hash of the algorithm is written onchain so you know you're using the right one. https://github.com/ponderware/mooncatparser/blob/master/moon...
For other NFT projects that can't use these techniques, they use decentralized storage like IPFS and ARWeave.
You can check what technique is used with this tool for any NFT project on ETH chain: https://checkmynft.com/