You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 3 Next »

How to Stamp an Image Template with Context Specific Details

For certain applications its useful to have an image template that can be stamped with contextual data when displayed to the end user.

This example comes from an online travel survey is being conducted where there is a specific for which the trips will be collected.

So to better inform the respondent we generate an image containing the window of time we are interested in and contextualize it with the specific date details that apply.

The red circled date information is what is stamped into the image.

The final image is constructed in several steps:

  1. create new image.
  2. write transparent background with black text onto the image
  3. convert surveyedDate into text and render onto the image
  4. set the background to white

The generated image will be accessed through a hard-coded mount point.

Wicket Setup:

  1. mount the custom IRequestTargetUrlCodingStrategy in application.init();
    1. My custom strategy is hardcoded with the name of the image that it responds to: /surveyed-date.png
  2. When ever a request is sent to that image the strategy will either returned a cached copy or generate a new image by stamping the current date onto a template image.
    1. The page that places the image will have an image link with the src="/surveyed-date.png"

Create custom IRequestTargetUrlCodingStrategy and bind it to the /surveyed-date.png Image

First we create the IRequestTargetUrlCodingStrategy that will respond to requests to /surveyed-date.png

public class SessionScopedSurveyTimeImageRequestTarget implements
        IRequestTargetUrlCodingStrategy {

    private static final Logger    log    = Logger
                                            .getLogger(SessionScopedSurveyTimeImageRequestTarget.class);

// name of the image resource that we respond to
    private static final String    PATH    = "surveyed-date.png";
   
// service that generates the final image for the current state.
    private final TripTimeImageService    tripTimeImageService;

// spring session bean proxy that contains the current survey sample
    private final DataModelService    dmService;
   

    /**
     * @param tripTimeImageService
     *
     */
    public SessionScopedSurveyTimeImageRequestTarget(TripTimeImageService tripTimeImageService, DataModelService dmService) {
        this.tripTimeImageService = tripTimeImageService;
        this.dmService = dmService;

    }

  
    @Override
    public IRequestTarget decode(RequestParameters requestParameters) {

        // default to yesterday
        DateTime surveyedDate = new DateTime().minusDays(1);
       
        if (dmService.isCreated()) {
             // The surveyed date is set from the sample context.
            surveyedDate = new DateTime ( dmService.getDataModel().getSample().getSurveyedDate());
        }
        Resource r;
        try {
            // this spring service generates the Image Resource stamped with 'surveyedDate' detail
            r = tripTimeImageService.getImageResource(surveyedDate, true);
        }
        catch (IOException e) {
            log.error("decode(): exception", e);
            return null;
        }
       
        return new ResourceStreamRequestTarget (r.getResourceStream());
    }

   
    @Override
    public CharSequence encode(IRequestTarget requestTarget) {

        // intentionally does nothing
        return null;
    }

   
    @Override
    public String getMountPath() {

        return PATH;
    }

  
    @Override
    public boolean matches(IRequestTarget requestTarget) {

        return false;
    }

    @Override
    public boolean matches(String path, boolean caseSensitive) {

        // handle the match detection, i.e. path.equals ("surveyed-date.png")
        if (caseSensitive) {
       
            if (PATH.equals(path))
                return true;
            else
                return false;
        }
        else {

            if (PATH.toLowerCase().equals(path.toLowerCase()))
                return true;
            else
                return false;
        }
    }
}

Next we mount the strategy in Application.init(), as:

    mount (new SessionScopedSurveyTimeImageRequestTarget(tripTimeService, dmService));

The tripTimeService.getImageResource(surveyedDate, true) method is what does the work of converting the date into a particular format and then writing the text onto an image template.

How to create an image stamped with user specific context

public class TripTimeImageServiceImpl implements TripTimeImageService {

	private static final Logger										log				= Logger
																							.getLogger(TripTimeImageServiceImpl.class);


        // spring resource that points at the template image 
	private Resource												baseTripTimeImageFile;

	private DateTimeFormatter										dayOfWeekFormatter;

	private DateTimeFormatter										dateFormatter;

// Font to use to write the string version of the date onto the image template
	private static Font												font			= new Font(
																							Font.SANS_SERIF,
																							Font.BOLD,
																							14);
 
        // cache containing the created image for each 
	private Map<String, BufferedDynamicImageResource>	dateToImageMap	= new LinkedHashMap<String, BufferedDynamicImageResource>();

	private BufferedDynamicImageResource generateImage(DateTime surveyedDate,
			SurveyTime st, boolean cacheable) throws IOException {

		BufferedDynamicImageResource generatedImage = new BufferedDynamicImageResource(
				"png");

		
		String dow = dayOfWeekFormatter.print(surveyedDate);

		String date = dateFormatter.print(surveyedDate);

		DateTime nextDay = surveyedDate.plusDays(1);

		String nextDow = dayOfWeekFormatter.print(nextDay);
		String nextDate = dateFormatter.print(nextDay);

		BufferedImage overlayImage = ImageIO.read(baseTripTimeImageFile.getFile());

		int width = overlayImage.getWidth();

		int height = overlayImage.getHeight();

		
		
		Graphics2D overlayG2d = overlayImage.createGraphics();

		overlayG2d.setFont(font);
		

		overlayG2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
				RenderingHints.VALUE_ANTIALIAS_ON);
		overlayG2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
				RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

	overlayG2d.setPaint(Color.BLACK);
		
		/*
		 * These offsets were calculated using a test case to repeatably place the details
		 * and with the Gimp to locate viable insertion points.
		 */
		// day of week
		overlayG2d.drawString(dow, 32, 90);

		// date
		overlayG2d.drawString(date, 32, 107);

		// next day of week
		overlayG2d.drawString(nextDow, 332, 90);

		// next date
		overlayG2d.drawString(nextDate, 332, 107);
		
		// next we write the progress bar onto its own image so thay we can layer them and have the bar at the back of the image stack.
		
		BufferedImage target = new BufferedImage (width, height, BufferedImage.TYPE_INT_ARGB);
		
		Graphics2D targetG2d = target.createGraphics();
		
		targetG2d.setFont(font);
		

		targetG2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
				RenderingHints.VALUE_ANTIALIAS_ON);
		targetG2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
				RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

		
		targetG2d.setPaint(Color.white);
		
		targetG2d.fillRect(0, 0, width, height);
		
		targetG2d.setPaint(Color.RED);
		
		// fill with the background color (white)
//		targetG2d.fillRect(0, 0, width, height);
				
// draw the overlay (the printed surveyedDate detail) onto the target.	
		targetG2d.drawImage(overlayImage, 0, 0, null);

	
// do the final setup on the BufferedDynamicImageResource that will contain this image
		// note that the generated image does not change the base image.
		generatedImage.setImage(target);

		generatedImage.setCacheable(cacheable);
		generatedImage.setFormat("png");
		
		log.info("generated image");
		

		return generatedImage;
		
	}

	
	public void setBaseTripTimeImageFile(Resource baseTripTimeImageFile) {

		this.baseTripTimeImageFile = baseTripTimeImageFile;
	}

	
	public TripTimeImageServiceImpl() {

		// e.g Wednesday
		dayOfWeekFormatter = DateTimeFormat.forPattern("EEEE");

		// e.g. February 18, 2009
		dateFormatter = DateTimeFormat.forPattern("MMMM dd, yyyy");
	}

	
	@Override
	public org.apache.wicket.Resource getImageResource(DateTime surveyedDate, boolean cacheable)
			throws IOException {

		return getImageResource(surveyedDate, null, cacheable);

	}

	
	@Override
	public org.apache.wicket.Resource getImageResource(DateTime surveyedDate,
			SurveyTime previousDepartureTime, boolean cacheable) throws IOException {

			BufferedDynamicImageResource cachedImage = null;

			
			String cachedImageKey = TimeUtils.getInstance().getString(
					surveyedDate);


			cachedImage = this.dateToImageMap.get(cachedImageKey);
			
			
			if (cachedImage == null) {
				
				cachedImage = generateImage(surveyedDate, previousDepartureTime, cacheable);

				this.dateToImageMap.put(cachedImageKey, cachedImage);

			}
			
				return cachedImage;
		

	}

}

Linking to the dynamic image from your pages

<img src="/surveyed-date.png" alt="Contextualized Image">

  • No labels