This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.

 

  Color Manipulation
  Submitted by



Here comes my COTD, It consists on a collection of color manipulation primitives that work directly on 565 color space, their main contributions are that they donīt lose colour resolution and the colour saturation is performed without any conditional statement.

The example code comes in C++, but its easy to port it to Java or asm. Its also interesting that you can use the same kind of trick to code 555 and 888 bpp versions of te routines. The Operations Covered are:
  • One pair of colours saturated add/sub
  • Two pair of colours saturated add/sub
  • One pair of colours alfablend (32levels)
  • Two pair of colours alfablend (32levels)
  • Have a Nice Day :-)
    Unai Landa

    Download Associated File: colors.hpp (14,413 bytes)

    /*
      License:
        This is free software; you can redistribute it and/or
        modify it under the terms of the GNU Library General Public
        License as published by the Free Software Foundation; either
        version 2 of the License, or (at your option) any later version.
        
      Use:    
        Some usefull color code.
        
      Author:
        Unai Landa	(unai_landa#eresmas·com)

    Notes: My english is really bad, I allready now that so dont tell me. The original code was nice comented in spanish, but I translated this "on the fly" so I hope you can understand :-) */


    // -------------------------------------------------------------------------------------------------------------------- // Some 565 Color space defines. // -------------------------------------------------------------------------------------------------------------------- enum { COLORSPACE_565_RED_MASK = (0xF800), COLORSPACE_565_GREEN_MASK = (0x07E0), COLORSPACE_565_BLUE_MASK = (0x001F),

    COLORSPACE_565_SATURATE_RED_BIT = (0x10000), COLORSPACE_565_SATURATE_GREEN_BIT = (0x0800), COLORSPACE_565_SATURATE_BLUE_BIT = (0x0020), };

    //---------------------------------------------------------------------------- // Some more defines //---------------------------------------------------------------------------- enum { MAXIMO_NUM_BITS_COLOR = 6 , BITS_BAJOS = 5 ,

    MASCARA_A =(COLORSPACE_565_GREEN_MASK) , MASCARA_B =(COLORSPACE_565_RED_MASK|COLORSPACE_565_BLUE_MASK) ,

    MASCARA_SAT_A =(COLORSPACE_565_SATURATE_GREEN_BIT ) , MASCARA_SAT_B =(COLORSPACE_565_SATURATE_RED_BIT|COLORSPACE_565_SATURATE_BLUE_BIT) ,

    MASCARA_A_TWICE =( ((COLORSPACE_565_RED_MASK|COLORSPACE_565_BLUE_MASK)<<16)|(COLORSPACE_565_GREEN_MASK<<0 )) , MASCARA_B_TWICE =( ((COLORSPACE_565_RED_MASK|COLORSPACE_565_BLUE_MASK)<<0 )|(COLORSPACE_565_GREEN_MASK<<16)) ,

    MASCARA_SAT_A_TWICE =( ((COLORSPACE_565_SATURATE_RED_BIT|COLORSPACE_565_SATURATE_BLUE_BIT)<<(16-BITS_BAJOS))|(COLORSPACE_565_SATURATE_GREEN_BIT>>BITS_BAJOS) ) , MASCARA_SAT_B_TWICE =((((COLORSPACE_565_SATURATE_RED_BIT|COLORSPACE_565_SATURATE_BLUE_BIT) )|(COLORSPACE_565_SATURATE_GREEN_BIT<<16))<<(MAXIMO_NUM_BITS_COLOR-BITS_BAJOS) ) };

    //---------------------------------------------------------------------- // Use: Adds two 565 colours with saturation and no lose. // Returns: The added colour. // Parameters: Two colours. //---------------------------------------------------------------------- __inline unsigned GE_AddColors565( const unsigned c1, const unsigned c2) { // Separacion: // SetUp: unsigned t1_a = (c1 & MASCARA_A); // 0000__g1__ unsigned t2_a = (c2 & MASCARA_A); // 0000__g2__ unsigned t1_b = (c1 & MASCARA_B); // 0000r1__b1 unsigned t2_b = (c2 & MASCARA_B); // 0000r2__b2 // Suma_A: // Suma_B: t1_a = t2_a = t1_a + t2_a; // 00__gT__ * T means Total t1_b = t2_b = t1_b + t2_b; // 00rT__bT t2_a &= MASCARA_SAT_A; // 00_1____ *** 1 appears ONLY where saturation happened. t2_b &= MASCARA_SAT_B; // 01___1__ *** 1 appears ONLY where saturation happened. t2_a -= (t2_a>>MAXIMO_NUM_BITS_COLOR); // 00__11__ *** 1 appears ONLY where saturation happened. t2_b -= (t2_b>>BITS_BAJOS); // 0011__11 *** 1 appears ONLY where saturation happened. t1_a |= t2_a; // 00__gS__ * S means Saturated t1_b |= t2_b; // 00rS__bS // Comoposicion: return(t1_a | t1_b); }

    //---------------------------------------------------------------------- // Use: Adds two 565 colours TWICE with saturation and no lose. // Returns: The two added colours. // Parameters: Four 565 colours, The first parameter colurs are added to the second parameter colours.. //---------------------------------------------------------------------- __inline unsigned GE_AddColors565Twice( const unsigned c1, const unsigned c2) { // Separacion: // SetUp: unsigned t1_a = (c1 & MASCARA_A_TWICE) >> BITS_BAJOS; // __R1__B1__g1 unsigned t2_a = (c2 & MASCARA_A_TWICE) >> BITS_BAJOS; // __R2__B2__g2 unsigned t1_b = (c1 & MASCARA_B_TWICE) << (MAXIMO_NUM_BITS_COLOR-BITS_BAJOS); // __G1__r1__b1 unsigned t2_b = (c2 & MASCARA_B_TWICE) << (MAXIMO_NUM_BITS_COLOR-BITS_BAJOS); // __G2__r2__b2 // Suma_A: // Suma_B: t1_a = t2_a = t1_a + t2_a; // __RT__BT__gT * T means Total t1_b = t2_b = t1_b + t2_b; // __GT__rT__bT t2_a &= MASCARA_SAT_A_TWICE; // _1___1___1__ *** 1 appears ONLY where saturation happened. t2_b &= MASCARA_SAT_B_TWICE; // _1___1___1__ *** 1 appears ONLY where saturation happened. t2_a -= (t2_a>>MAXIMO_NUM_BITS_COLOR); // __11__11__11 *** 1 appears ONLY where saturation happened. t2_b -= (t2_b>>MAXIMO_NUM_BITS_COLOR); // __11__11__11 *** 1 appears ONLY where saturation happened. t1_a |= t2_a; // __RSxxBSxxgS * S means Saturated t1_b |= t2_b; // __GSxxrSxxbS * xx Garbage that appeared betwen the color components. t1_a = (t1_a<<BITS_BAJOS) & (MASCARA_A_TWICE); // 11xx11xx11xx * Moves all to its correct place. // 11__11__11__ * Cleans the space betwen components. t1_b = (t1_b>>MAXIMO_NUM_BITS_COLOR-BITS_BAJOS) & (MASCARA_B_TWICE); // 11xx11xx11xx * Moves all to its correct place. // __11__11__11 * Cleans the space betwen components. // Comoposicion: return(t1_a | t1_b); }

    //---------------------------------------------------------------------- // Use: Subs two 565 colours with saturation and no lose. // Returns: The Sub colour. // Parameters: Two colours. //---------------------------------------------------------------------- __inline unsigned GE_SubColors565( unsigned c1, const unsigned c2) { // Separacion: unsigned t1_a = (c1 & MASCARA_A) | MASCARA_SAT_A; // 0000_1g1__ // I set the bit so later I can check underflow. unsigned t2_a = (c2 & MASCARA_A); // 0000__g2__ unsigned t1_b = (c1 & MASCARA_B) | MASCARA_SAT_B; // 0001r1_1b1 // I set the bit so later I can check underflow. unsigned t2_b = (c2 & MASCARA_B); // 0000r2__b2 // Resta_A: // Resta_B: t1_a = t2_a = (t1_a - t2_a); // 00__gT__ * T means Total t1_b = t2_b = (t1_b - t2_b); // 00rT__bT t2_a &= (MASCARA_SAT_A); // 00_1____ I test sign change. t2_b &= (MASCARA_SAT_B); // 01___1__ 1 appears ONLY where no underflow happened. t2_a -= (t2_a>>MAXIMO_NUM_BITS_COLOR); // 00__11__ I create the 1filled mask on the colours the didn't underflow. t2_b -= (t2_b>>BITS_BAJOS); // 0011__11 t1_a &= t2_a; // 00__gU__ * U means UnderFlow t1_b &= t2_b; // 00rU__bU // Comoposicion: return(t1_a | t1_b); }

    //---------------------------------------------------------------------- // Use: Subs two 565 colours TWICE with saturation and no lose. // Returns: The two added colours. // Parameters: Four 565 colours, The second parameter colurs are sub from the first parameter colours.. //---------------------------------------------------------------------- __inline unsigned GE_SubColors565Twice( unsigned c1, const unsigned c2) { // Separacion: // SetUp: unsigned t1_a = ((c1 & MASCARA_A_TWICE) >> BITS_BAJOS) | MASCARA_SAT_A_TWICE; // _1R1_1B1_1g1 unsigned t2_a = ((c2 & MASCARA_A_TWICE) >> BITS_BAJOS); // __R2__B2__g2 unsigned t1_b = ((c1 & MASCARA_B_TWICE) << (MAXIMO_NUM_BITS_COLOR-BITS_BAJOS)) | MASCARA_SAT_B_TWICE; // _1G1_1r1_1b1 unsigned t2_b = ((c2 & MASCARA_B_TWICE) << (MAXIMO_NUM_BITS_COLOR-BITS_BAJOS)); // __G2__r2__b2 // Suma_A: // Suma_B: t1_a = t2_a = t1_a - t2_a; // __RT__BT__gT * T means Total t1_b = t2_b = t1_b - t2_b; // __GT__rT__bT t2_a &= MASCARA_SAT_A_TWICE; // _1___1___1__ *** 1 appears ONLY where no underflow happened. t2_b &= MASCARA_SAT_B_TWICE; // _1___1___1__ *** 1 appears ONLY where no underflow happened. t2_a -= (t2_a>>MAXIMO_NUM_BITS_COLOR); // __11__11__11 *** 1 appears ONLY where no underflow happened. t2_b -= (t2_b>>MAXIMO_NUM_BITS_COLOR); // __11__11__11 *** 1 appears ONLY where no underflow happened. t1_a &= t2_a; // __RUxxBUxxgU * U means Underflow t1_b &= t2_b; // __GUxxrSxxbU * xx Garbage that appeared betwen the color components. t1_a = (t1_a<<BITS_BAJOS) & (MASCARA_A_TWICE); // 11xx11xx11xx * Moves all to its correct place. // 11__11__11__ * Cleans the space betwen components. t1_b = (t1_b>>MAXIMO_NUM_BITS_COLOR-BITS_BAJOS) & (MASCARA_B_TWICE); // 11xx11xx11xx * Moves all to its correct place. // __11__11__11 * Cleans the space betwen components. // Comoposicion: return(t1_a | t1_b); }

    //---------------------------------------------------------------------- // Use: Make a 32 levels alfa blend betwen two 565 colours. // Returns: The blended colour. // Parameters: iAlfa=0 Only c1 is set, iAlfa=32 only c2 is set //---------------------------------------------------------------------- __inline unsigned GE_BlendColors565( const unsigned c1, const unsigned c2, int iAlfa) { unsigned ta = c1 & MASCARA_A; // 0000__g1__ unsigned tb = c2 & MASCARA_B; // 0000r2__b2 ta *= (32-iAlfa); tb *= ( iAlfa);

    ta += ( iAlfa) *(c2 & MASCARA_A); // 0000__g2__ tb += (32-iAlfa) *(c1 & MASCARA_B); // 0000r1__b1 ta = (ta>>BITS_BAJOS) & MASCARA_A; ta += (tb>>BITS_BAJOS) & MASCARA_B;

    return(ta); }

    //---------------------------------------------------------------------- // Use: Make a 32 levels alfa blend betwen two 565 colours TWICE // Returns: The two blended colours. // Parameters: iAlfa=0 Only c1 is set, iAlfa=32 only c2 is set // c1; two 565 Colours thar will blend with c2 that contains anothe two 565 colours. //---------------------------------------------------------------------- __inline unsigned GE_BlendColors565Twice( const unsigned c1, const unsigned c2, int iAlfa) { unsigned ta = (c1 & MASCARA_A_TWICE)>>BITS_BAJOS; // __R1__B1__g1 unsigned tb = (c1 & MASCARA_B_TWICE); // __G1__r1__b1 ta *= (32-iAlfa); tb *= (32-iAlfa); ta += iAlfa *((c2 & MASCARA_A_TWICE)>>(BITS_BAJOS)); // __R2__B2__g2 tb += iAlfa * (c2 & MASCARA_B_TWICE); // __G2__r2__b2 ta &= MASCARA_A_TWICE; // R2__B2__g2__ ta += (tb>>BITS_BAJOS) & MASCARA_B_TWICE; // __G2__r2__b2 return(ta); }

    The zip file viewer built into the Developer Toolbox made use of the zlib library, as well as the zlibdll source additions.

     

    Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
    Please read our Terms, Conditions, and Privacy information.