Set your report layout to be based on the calendar events table rather than your contacts table. Use a "go to related records" script step to isolate all of the calendar events for that contact.
If you can avoid it, don't try to print portals. When creating a report, base the layout on the "lowest level" of data - in this case the calendar events.
There are a couple ways to do this IF you only want to print ONE calendar entry. As David said, you can print from the calendar events, but nornally you would choose that method if you wanted to print more than one calendar entry. In your case, I might do it differently, depending on how much contact info you are printing vs how much calendar data.
The old way (pre-FM12) would be to use a global field to create a temporary relationship to just the calendar entry you want to show.
The new way - use the ExecuteSQL function to pull the data you want. You could put it in a global field for printing, or you could even put it into a global variable (my preference, to avoid adding extra fields to the database). Definitely worth your while to learn this,
Pseudo-code Example: Set Variable $$calendarInfo [ExecuteSQL ( "SELECT calendarInfofields FROM calendarTable WHERE keyfieldfromcalendar = 123456 " )
place a merge variable <<$$calendarInfo>> on the layout and go.
Hope that helps.