Yes, you're right. Saving entire image in eth is very costly. I'll suggest you to check off chain data storages like IPFS or Swarm (the ethereum community usually recommends it).
There are alternative APIs are available. Mentioned are two popular services and most of dev's are using. Both are distributed off chain storages.
I'll suggest you to check below link once.
Coming to your question. This is an example of how to store a reference to an image, stored in IPFS, in an ethereum smart contract.
contract ImageInfo{
mapping(address=>Image[]) private images;
struct Image{
string imageHash;
string ipfsInfo;
}
function uploadImage(string hash, string ipfs) public{
images[msg.sender].push(Image(hash,ipfs)); //
}
}
Above code is for just illustration. Modify the data structure as per your requirements. I have not added any security checks.
The idea is to first upload the image to ipfs/swarm/any other off chain data store, get the value calculate hash of image to contract. Download data(image) from offchain and calculate hash and check hash saved in contract.
I feel like the above solution is one of the best way to handle images, because all data is distributed using serverless architecture.