An even simpler way: For each 5x5 grid point and each walkable area, only remember _whether_ that area has at least one pixel within x + 3, y + 3 around the grid point. This information is fairly easy to keep up-to-date, even when areas are changed at runtime. And it can be stored compactly.
When Character.PlaceOnWalkableArea() is called, find the point on the 5x5 grid that is nearest to the character and from there, do a breadth-first search for the first grid point that has an active area nearby, using the precompiled information. Then from that grid point, do a pixelwise breadth-first search to find the specific nearby pixel that belongs to that area. Move the character to that pixel.
When Character.PlaceOnWalkableArea() is called, find the point on the 5x5 grid that is nearest to the character and from there, do a breadth-first search for the first grid point that has an active area nearby, using the precompiled information. Then from that grid point, do a pixelwise breadth-first search to find the specific nearby pixel that belongs to that area. Move the character to that pixel.