Concepts / Colors and the Color Class in Java

Colors and the Color Class in Java

A transparent color is a Color object created with an alpha component, which controls its opacity; an ordinary three-argument RGB color is fully opaque.

  • Programming

A Color That Lets Shapes Show Through

Most colors you have used so far in Java are solid. When you draw with them, whatever you paint replaces what was underneath. Sometimes you want the opposite: a shape that lets the shapes beneath it show through. Java handles this with colors that carry an alpha component. This article starts from a small program that builds transparent colors and asks you to reason about what each color will look like, then explains the rules that make those predictions work.

Key point

Keep one question in mind as you read: when a program uses a transparent color, which line decides how opaque the color is? By the end of the article you should be able to answer that question, and the same habit will help you find the exact line where a result stops matching your expectation.

What the Alpha Component Controls

Colors with alpha components were introduced in Java along with Graphics2D, but they can also be used with ordinary Graphics objects. The alpha component is the part of a color that controls its opacity. Opacity describes how much of the drawing underneath a color shows through it. A higher alpha value makes the color more opaque, so less of what lies beneath is visible. A lower alpha value makes it more transparent, so more of the underlying drawing shows through.

Definition

A transparent color is a Color object created with an alpha component, which controls its opacity. An ordinary three-argument RGB color is fully opaque.

Blue backgroundopaqueBlue backgroundopaqueRed overlayfully opaqueRed overlaysemi-transparentVisible resultred onlyVisible resultred mixed with bluedrawn overdrawn over
What does the visible result look like when a red shape is drawn over a blue background shape, first fully opaque and then semi-transparent?

Read the top row of the figure first. A fully opaque red overlay covers the blue background in the region it occupies, so the blue is replaced and only red is visible there. Now read the bottom row. The same red shape is semi-transparent, so the blue beneath it still reaches your eye and the visible result is a mixture of the two. Nothing about the shape changed except its alpha value. That single number is what separates a solid replacement from a see-through overlay.

Tracing What setColor Does

Once a transparent color exists, you use it exactly the way you use any other color. The source describes this with a Color named c and a graphics context named g. Calling g.setColor(c) sets the color for subsequent drawing, and this is the same mechanism used for opaque colors. The color is a piece of state held by the graphics context. It stays in effect until another setColor call replaces it.

c transparent redcreated Colorg.setColor(c)active color becomes cfillRectuses cg.setColor(other)active color becomes otherfillRectuses otherpassed innext drawcolor replacednext draw
After g.setColor(c) runs, which later draw calls use c, and at what point does the active color change?

Follow the figure from top to bottom. The Color c is created once and then passed to setColor, which makes it the active color. The fillRect call that comes next draws with c, so the transparency of c applies to that shape. The active color does not switch back on its own. It changes only when another setColor call runs, which is why the second fillRect in the figure uses a different color. When you trace a program, track the active color as a value that moves forward line by line, not as something tied to the variable name c.

Two Alpha Scales Compared

The Color class offers two constructors that accept an alpha component. Both take four parameters: three color channels and one alpha value. The forms differ in the kind of number they expect. The first uses integers, and the second uses floating-point numbers. Read a constructor call from left to right. The first three arguments set the red, green, and blue channels, and the last argument sets the alpha component. The alpha argument is the last position in both forms, and its range matches the range of the other three arguments for that constructor.

0fully transparent0.0fully transparent200slightly transparent0.550 percent opaque255fully opaque1.0fully opaquesame opacitysame opacity
How do the same opacity levels map onto the 0 to 255 integer scale and the 0.0 to 1.0 float scale, so which value means fully transparent and which means fully opaque in each form?

The two columns in the figure describe the same range of opacity written in two different number styles. The integer form runs from 0 to 255, and the float form runs from 0.0 to 1.0. The endpoints match: the lowest value on each scale is the most transparent setting, and the highest value is fully opaque. The middle values also correspond. The integer alpha of 200 is the first color in the source, described as slightly transparent. The float alpha of 0.5 is the second color, described as 50 percent opaque. Those two numbers are written differently, but each one is read against its own scale.

The float form lets you think in percentages. A value of 0.5 is a half, which is exactly the 50 percent figure the source gives. That is the main reason to prefer the float form when your reasoning is already about proportions. The integer form fits better when you are working with values that are already in the 0 to 255 range.

Predicting the Default Alpha

The three-argument constructor creates a color with only red, green, and blue values, so no alpha value appears in the call. Before reading the answer, commit to a prediction about the opacity that Java gives such a color.

What do you think happens?

A color is created with Color(255, 0, 0) and no alpha argument. Is it transparent, semi-transparent, or fully opaque?

  • Fully transparent

  • Semi-transparent, around the middle of the scale

  • Fully opaque

Reveal answer
Answer:

Fully opaque

An ordinary three-argument RGB color is fully opaque. On the integer scale from 0 to 255 that corresponds to the top value, 255. The alpha is not written in the call, but the color is still solid, which is why the three-argument constructor produces the same kind of color you have used all along.

The reasoning is simple once you know the rule. A three-argument color has no transparency set by the program, so it is fully opaque. To make a color transparent, you must use one of the four-argument constructors and choose an alpha value that is less than fully opaque. The three-argument call is the signal that the color should be solid.

Worked Example: Two Constructors Side by Side

java
Notes on the code
  • Line 1: integer form, red 255, green 0, blue 0, alpha 200 on the 0 to 255 scale. This is the source's transparent red.
  • Line 2: float form, red 0.0, green 0.5, blue 0.5, alpha 0.5 on the 0.0 to 1.0 scale. This is the source's blue-green color at 50 percent opacity.
  • Lines 3 and 4: setColor makes t the active color, and the next fillRect draws with it.
  • Lines 5 and 6: setColor replaces the active color with u, and the following fillRect draws with it.
Worked example

Reading each constructor call against its own range

Two colors are created, one with integer arguments and one with float arguments. For each call, state the alpha value on the scale it uses and say how opaque the color is.

  1. 1
    Check the last argument first

    In the first call the alpha argument is 200. Because the arguments are integers, the alpha scale is 0 to 255.

  2. 2
    Confirm the other arguments fit the range

    The red value 255 is the top of the 0 to 255 range, and the green and blue values are 0, which also fall inside it. The call is valid.

  3. 3
    Interpret the integer alpha

    An alpha of 200 is near the top of the integer scale, so the red is slightly transparent.

  4. 4
    Check the float call the same way

    In the second call the alpha argument is 0.5, and the arguments are floats, so the alpha scale is 0.0 to 1.0. All four values fall inside that range.

  5. 5
    Interpret the float alpha

    An alpha of 0.5 is a half, so the blue-green color is 50 percent opaque.

Result

The integer call gives a slightly transparent red. The float call gives a blue-green color at 50 percent opacity. Each value was read against the scale of its own constructor form.

Locating the Failing Line

When a transparent-color program produces a result you did not expect, do not start by asking whether the whole program is wrong. Move line by line and stop at the first line where the stored value differs from your prediction. That line is the failure location. For each line, ask two questions: which value is being stored, and does that value fall inside the range the constructor requires? Most surprising results trace back to one of those two questions, and the cause is almost always in the arguments on that line or in the choice of constructor.

  • Common mistake

    Using the integer alpha scale when the float scale was intended

    What it looks like

    Color c = new Color(1.0f, 0.0f, 0.0f, 1); ... the alpha 1 is an integer, but the other arguments are floats, which does not match the float constructor's expected types.

    Why it fails

    The alpha argument must follow the same number type and range as the other three arguments for that constructor. Mixing styles breaks the rule that all four positions use one scale.

    Do this instead

    Use the float form with 1.0f for full opacity, or use the integer form with 255 for full opacity, and keep all four arguments in the same style.

  • Common mistake

    Reading an integer alpha of 1 as almost opaque

    What it looks like

    Color c = new Color(255, 0, 0, 1); the red is intended to be solid.

    Why it fails

    On the 0 to 255 scale, an alpha of 1 is at the very bottom of the range, so the color is nearly fully transparent. It is not nearly fully opaque.

    Do this instead

    For a solid color on the integer scale, the alpha should be 255. Check the scale before you read the number.

  • Common mistake

    Assuming a three-argument color is transparent

    Why it fails

    A three-argument RGB color is fully opaque, so the program draws a solid shape regardless of what was drawn underneath.

  • Common mistake

    Assuming setColor resets after one draw call

    Why it fails

    The active color stays in effect until another setColor call replaces it. A later shape can use a transparent color simply because no new color was set after it.

Practice Tracing Transparent Colors

MEDIUM

A program creates Color a = new Color(0, 0, 255, 128) and Color b = new Color(0.0f, 0.0f, 1.0f, 0.25f), then calls g.setColor(a), draws a rectangle, calls g.setColor(b), and draws a second rectangle. Which rectangle is more opaque, and what is the alpha of each color on its own scale?

Hints
  • Identify which constructor each color uses by checking whether the arguments are integers or floats.
  • Find the scale that matches the alpha argument in each call before deciding how opaque it is.
  • Remember that setColor changes the active color, so the second rectangle uses b, not a.
MEDIUM

Write a constructor call for a color with red 255, green 255, blue 0 that is 75 percent opaque, once using the integer form and once using the float form. Then state which alpha value you used on each scale.

Hints
  • On the float scale, 75 percent corresponds to 0.75.
  • On the integer scale from 0 to 255, multiply the fraction by 255 to find the matching alpha.

Key Takeaways

  • The alpha component of a Color controls its opacity: a higher alpha makes it more solid, and a lower alpha lets more of the underlying drawing show through.
  • The Color class has two four-argument constructors. The integer form uses 0 to 255 for alpha, and the float form uses 0.0 to 1.0, and the alpha argument follows the same range rule as the color channels.
  • A three-argument RGB color has no transparency and is fully opaque, so transparency only appears when a four-argument constructor sets a lower alpha.
  • Passing a color to g.setColor makes it the active color for later drawing calls until another setColor replaces it, so a transparent color is used exactly like any other color.
  • When a result is unexpected, trace the program line by line, check the stored value and its range on each line, and stop at the first line that disagrees with your prediction.