png

Blurry Graphics in ADF Faces

Posted on Updated on

Ever since Apple introduced the Retina Display in 2010, modern devices have changed to display content at twice (@2x), three times (@3x), four times (@4x) [or even fractions in-between] the resolution that we have been used to in the past.

For app developers using bitmap graphics, this can be a bit of a nightmare to support. You have to generate graphics at multiple resolutions and change your application to reference different sizes of graphics. Unless you are using photographic content, you may find it easier to deal with SVG (vector graphic) images instead.

In ADF Faces applications, there are at least 3 categories of ways to display images:

  1. Image components
  2. Components that have an image somewhere inside of it (and that don’t offer a style attribute explicitly for that image)
  3. CSS background-image styles

blurry-images

SVG

For all 3 use cases, simply use the .svg file as you have been accustomed to using for .png files. Just make sure the graphic was well-designed to look good on an @1x display if legacy support is important to you.

PNG (or other bitmap graphic)

For use case 1, you specify your image in the “source” attribute then the dimensions in the “inlineStyle” attribute.

For use case 2, you specify your image in the appropriate image attribute, e.g. “icon” and specify a marker “styleClass” that you’ll need to make a style block definition for (e.g. via an af:resource tag). This block will use that marker then space then “IMG” for its selector and then in the body of the block, specify the width and height.

For use case 3, you are dealing with CSS styles (e.g. in an af:resource). Since browser support is not universal, you will need to specify 3 kinds of selectors: (a) the default fallback for legacy browsers–where you define your @1x graphic, (b) the WebKit @2x override, (c) the modern @2x override. You can make additional blocks for @3x, @4x, etc. (You may optionally use this technique to hide/show specific component instances for use cases 1 & 2 too if you really want your app to display resolution-specific graphics.)

Sample code

<?xml version='1.0' encoding='UTF-8'?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.1"
  xmlns:f="http://java.sun.com/jsf/core"
  xmlns:af="http://xmlns.oracle.com/adf/faces/rich"
  xmlns:trh="http://myfaces.apache.org/trinidad/html">
  <jsp:directive.page contentType="text/html;charset=UTF-8"/>
  <f:view>
    <af:document id="d1" title="Blurry Graphics" inlineStyle="padding:10px;">
      <f:facet name="metaContainer">
        <af:resource type="css">
          /* Dimensions for bitmap graphics on components that don't have
             style attributes for internal image elements. */
          .MyIconHolder IMG {
            width: 24px;
            height: 24px;
          }
          /* Example of background-image graphics */
          .MyBackgroundPNGImage {
            background-repeat: no-repeat;
            width: 24px;
            height: 24px;
            background-image: url(images/image@1x.png);
          }
          @media only screen and (-webkit-min-device-pixel-ratio: 2) {
            .MyBackgroundPNGImage {
              background-image: url('images/image@2x.png');
              -webkit-background-size: 24px 24px;
            }
          }
          @media only screen and (min-resolution: 2dppx) {
            .MyBackgroundPNGImage {
              background-image: url('images/image@2x.png');
              background-size: 24px 24px;
            }
          }
          .MyBackgroundSVGImage {
            background-repeat: no-repeat;
            width: 24px;
            height: 24px;
            background-image: url(images/image.svg);
          }
        </af:resource>
      </f:facet>
      <af:form id="f1">
        <trh:tableLayout id="tl1" borderWidth="1">
          <trh:rowLayout id="rl1">
            <trh:cellFormat id="cf1" header="true">
              <af:outputText id="ot1" value="Use Case"/>
            </trh:cellFormat>
            <trh:cellFormat id="cf2" header="true">
              <af:outputText id="ot2" value="@1x PNG"/>
            </trh:cellFormat>
            <trh:cellFormat id="cf3" header="true">
              <af:outputText id="ot3" value="@2x PNG"/>
            </trh:cellFormat>
            <trh:cellFormat id="cf4" header="true">
              <af:outputText id="ot4" value="SVG"/>
            </trh:cellFormat>
          </trh:rowLayout>
          <trh:rowLayout id="rl2">
            <trh:cellFormat id="cf5" halign="center">
              <af:outputText id="ot5" value="af:image"/>
            </trh:cellFormat>
            <trh:cellFormat id="cf6" halign="center">
              <af:image id="i1" source="/images/image@1x.png"/>
            </trh:cellFormat>
            <trh:cellFormat id="cf7" halign="center">
              <af:image id="i2" source="/images/image@2x.png"
                inlineStyle="width:24px;height:24px;"/>
            </trh:cellFormat>
            <trh:cellFormat id="cf8" halign="center">
              <af:image id="i3" source="/images/image.svg"/>
            </trh:cellFormat>
          </trh:rowLayout>
          <trh:rowLayout id="rl3">
            <trh:cellFormat id="cf9" halign="center">
              <af:panelGroupLayout id="pgl1" layout="vertical">
                <af:outputText id="ot6" value="af:commandToolbarButton"/>
                <af:outputText id="ot7" value="(no style attribute for dimensions)"/>
              </af:panelGroupLayout>
            </trh:cellFormat>
            <trh:cellFormat id="cf10" halign="center">
              <af:commandToolbarButton id="ctb1" icon="/images/image@1x.png"/>
            </trh:cellFormat>
            <trh:cellFormat id="cf11" halign="center">
              <af:commandToolbarButton id="ctb2" icon="/images/image@2x.png"
                styleClass="MyIconHolder"/>
            </trh:cellFormat>
            <trh:cellFormat id="cf12" halign="center">
              <af:commandToolbarButton id="ctb3" icon="/images/image.svg"/>
            </trh:cellFormat>
          </trh:rowLayout>
          <trh:rowLayout id="rl4">
            <trh:cellFormat id="cf13" halign="center">
              <af:panelGroupLayout id="pgl2" layout="vertical">
                <af:outputText id="ot8" value="af:panelGroupLayout"/>
                <af:outputText id="ot9" value="(background-image styling)"/>
              </af:panelGroupLayout>
            </trh:cellFormat>
            <trh:cellFormat id="cf14" halign="center" columnSpan="2">
              <af:panelGroupLayout id="pgl3" layout="vertical"
                styleClass="MyBackgroundPNGImage"/>
            </trh:cellFormat>
            <trh:cellFormat id="cf16" halign="center">
              <af:panelGroupLayout id="pgl4" layout="vertical"
                styleClass="MyBackgroundSVGImage"/>
            </trh:cellFormat>
          </trh:rowLayout>
        </trh:tableLayout>
      </af:form>
    </af:document>
  </f:view>
</jsp:root>