In the comments, Mark Setchell suggests calling .decode('ascii') on the result of your b64encode call. I agree that this will work, but I think base64encoding to begin with is introducing an unnecessary extra step that complicates your code.*
Instead, I suggest directly decoding the bytes returned by image.tostring. The only complication is that the bytes object can contain values larger than 128, so you can't decode it with ascii. Try using an encoding that can handle values up to 256, such as latin1.
from PIL import Image
import json
#create sample file. You don't have to do this in your real code.
img = Image.new("RGB", (10,10), "red")
#decode.
s = img.tobytes().decode("latin1")
#serialize.
with open("outputfile.json", "w") as file:
json.dump(s, file)
(*but, to my surprise, the resulting json file is still smaller than one made with a latin1 encoding, at least for my sample file. Use your own judgement to determine whether file size or program clarity is more important.)