Home | History | Annotate | Download | only in etc1
      1 // Copyright 2009 Google Inc.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 // This is branched from frameworks/base/opengl/include/ETC1/etc1.cc
     16 //
     17 // It has been modified as follows:
     18 // 1. Unused or not related to encoding methods have been removed.
     19 // 2. Methods related to determining the size of the output texture have been
     20 //    added.
     21 // 3. EncodeImage has been modified to operate directly on a bitmap, work with
     22 //    4bpp input, and resize the output to a power-of-two size in order to work
     23 //    with the graphics driver.
     24 //
     25 
     26 #include "etc1.h"
     27 
     28 #include <string>
     29 #include <cmath>
     30 
     31 /* From http://www.khronos.org/registry/gles/extensions/OES/OES_compressed_ETC1_RGB8_texture.txt
     32 
     33  The number of bits that represent a 4x4 texel block is 64 bits if
     34  <internalformat> is given by ETC1_RGB8_OES.
     35 
     36  The data for a block is a number of bytes,
     37 
     38  {q0, q1, q2, q3, q4, q5, q6, q7}
     39 
     40  where byte q0 is located at the lowest memory address and q7 at
     41  the highest. The 64 bits specifying the block is then represented
     42  by the following 64 bit integer:
     43 
     44  int64bit = 256*(256*(256*(256*(256*(256*(256*q0+q1)+q2)+q3)+q4)+q5)+q6)+q7;
     45 
     46  ETC1_RGB8_OES:
     47 
     48  a) bit layout in bits 63 through 32 if diffbit = 0
     49 
     50  63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48
     51  -----------------------------------------------
     52  | base col1 | base col2 | base col1 | base col2 |
     53  | R1 (4bits)| R2 (4bits)| G1 (4bits)| G2 (4bits)|
     54  -----------------------------------------------
     55 
     56  47 46 45 44 43 42 41 40 39 38 37 36 35 34  33  32
     57  ---------------------------------------------------
     58  | base col1 | base col2 | table  | table  |diff|flip|
     59  | B1 (4bits)| B2 (4bits)| cw 1   | cw 2   |bit |bit |
     60  ---------------------------------------------------
     61 
     62 
     63  b) bit layout in bits 63 through 32 if diffbit = 1
     64 
     65  63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48
     66  -----------------------------------------------
     67  | base col1    | dcol 2 | base col1    | dcol 2 |
     68  | R1' (5 bits) | dR2    | G1' (5 bits) | dG2    |
     69  -----------------------------------------------
     70 
     71  47 46 45 44 43 42 41 40 39 38 37 36 35 34  33  32
     72  ---------------------------------------------------
     73  | base col 1   | dcol 2 | table  | table  |diff|flip|
     74  | B1' (5 bits) | dB2    | cw 1   | cw 2   |bit |bit |
     75  ---------------------------------------------------
     76 
     77 
     78  c) bit layout in bits 31 through 0 (in both cases)
     79 
     80  31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16
     81  -----------------------------------------------
     82  |       most significant pixel index bits       |
     83  | p| o| n| m| l| k| j| i| h| g| f| e| d| c| b| a|
     84  -----------------------------------------------
     85 
     86  15 14 13 12 11 10  9  8  7  6  5  4  3   2   1  0
     87  --------------------------------------------------
     88  |         least significant pixel index bits       |
     89  | p| o| n| m| l| k| j| i| h| g| f| e| d| c | b | a |
     90  --------------------------------------------------
     91 
     92 
     93  Add table 3.17.2: Intensity modifier sets for ETC1 compressed textures:
     94 
     95  table codeword                modifier table
     96  ------------------        ----------------------
     97  0                     -8  -2  2   8
     98  1                    -17  -5  5  17
     99  2                    -29  -9  9  29
    100  3                    -42 -13 13  42
    101  4                    -60 -18 18  60
    102  5                    -80 -24 24  80
    103  6                   -106 -33 33 106
    104  7                   -183 -47 47 183
    105 
    106 
    107  Add table 3.17.3 Mapping from pixel index values to modifier values for
    108  ETC1 compressed textures:
    109 
    110  pixel index value
    111  ---------------
    112  msb     lsb           resulting modifier value
    113  -----   -----          -------------------------
    114  1       1            -b (large negative value)
    115  1       0            -a (small negative value)
    116  0       0             a (small positive value)
    117  0       1             b (large positive value)
    118 
    119 
    120  */
    121 
    122 #define ETC1_ENCODED_BLOCK_SIZE 8
    123 #define ETC1_DECODED_BLOCK_SIZE 48
    124 
    125 namespace {
    126 
    127 typedef unsigned char etc1_byte;
    128 typedef int etc1_bool;
    129 typedef unsigned int etc1_uint32;
    130 
    131 static const int kModifierTable[] = {
    132 /* 0 */2, 8, -2, -8,
    133 /* 1 */5, 17, -5, -17,
    134 /* 2 */9, 29, -9, -29,
    135 /* 3 */13, 42, -13, -42,
    136 /* 4 */18, 60, -18, -60,
    137 /* 5 */24, 80, -24, -80,
    138 /* 6 */33, 106, -33, -106,
    139 /* 7 */47, 183, -47, -183 };
    140 
    141 static const int kLookup[8] = { 0, 1, 2, 3, -4, -3, -2, -1 };
    142 
    143 static inline etc1_byte clamp(int x) {
    144     return (etc1_byte) (x >= 0 ? (x < 255 ? x : 255) : 0);
    145 }
    146 
    147 static
    148 inline int convert4To8(int b) {
    149     int c = b & 0xf;
    150     return (c << 4) | c;
    151 }
    152 
    153 static
    154 inline int convert5To8(int b) {
    155     int c = b & 0x1f;
    156     return (c << 3) | (c >> 2);
    157 }
    158 
    159 static
    160 inline int convert6To8(int b) {
    161     int c = b & 0x3f;
    162     return (c << 2) | (c >> 4);
    163 }
    164 
    165 static
    166 inline int divideBy255(int d) {
    167     return (d + 128 + (d >> 8)) >> 8;
    168 }
    169 
    170 static
    171 inline int convert8To4(int b) {
    172     int c = b & 0xff;
    173     return divideBy255(c * 15);
    174 }
    175 
    176 static
    177 inline int convert8To5(int b) {
    178     int c = b & 0xff;
    179     return divideBy255(c * 31);
    180 }
    181 
    182 static
    183 inline int convertDiff(int base, int diff) {
    184     return convert5To8((0x1f & base) + kLookup[0x7 & diff]);
    185 }
    186 
    187 static
    188 void decode_subblock(etc1_byte* pOut, int r, int g, int b, const int* table,
    189         etc1_uint32 low, bool second, bool flipped) {
    190     int baseX = 0;
    191     int baseY = 0;
    192     if (second) {
    193         if (flipped) {
    194             baseY = 2;
    195         } else {
    196             baseX = 2;
    197         }
    198     }
    199     for (int i = 0; i < 8; i++) {
    200         int x, y;
    201         if (flipped) {
    202             x = baseX + (i >> 1);
    203             y = baseY + (i & 1);
    204         } else {
    205             x = baseX + (i >> 2);
    206             y = baseY + (i & 3);
    207         }
    208         int k = y + (x * 4);
    209         int offset = ((low >> k) & 1) | ((low >> (k + 15)) & 2);
    210         int delta = table[offset];
    211         etc1_byte* q = pOut + 3 * (x + 4 * y);
    212         *q++ = clamp(r + delta);
    213         *q++ = clamp(g + delta);
    214         *q++ = clamp(b + delta);
    215     }
    216 }
    217 
    218 // Input is an ETC1 compressed version of the data.
    219 // Output is a 4 x 4 square of 3-byte pixels in form R, G, B
    220 
    221 void etc1_decode_block(const etc1_byte* pIn, etc1_byte* pOut) {
    222     etc1_uint32 high = (pIn[0] << 24) | (pIn[1] << 16) | (pIn[2] << 8) | pIn[3];
    223     etc1_uint32 low = (pIn[4] << 24) | (pIn[5] << 16) | (pIn[6] << 8) | pIn[7];
    224     int r1, r2, g1, g2, b1, b2;
    225     if (high & 2) {
    226         // differential
    227         int rBase = high >> 27;
    228         int gBase = high >> 19;
    229         int bBase = high >> 11;
    230         r1 = convert5To8(rBase);
    231         r2 = convertDiff(rBase, high >> 24);
    232         g1 = convert5To8(gBase);
    233         g2 = convertDiff(gBase, high >> 16);
    234         b1 = convert5To8(bBase);
    235         b2 = convertDiff(bBase, high >> 8);
    236     } else {
    237         // not differential
    238         r1 = convert4To8(high >> 28);
    239         r2 = convert4To8(high >> 24);
    240         g1 = convert4To8(high >> 20);
    241         g2 = convert4To8(high >> 16);
    242         b1 = convert4To8(high >> 12);
    243         b2 = convert4To8(high >> 8);
    244     }
    245     int tableIndexA = 7 & (high >> 5);
    246     int tableIndexB = 7 & (high >> 2);
    247     const int* tableA = kModifierTable + tableIndexA * 4;
    248     const int* tableB = kModifierTable + tableIndexB * 4;
    249     bool flipped = (high & 1) != 0;
    250     decode_subblock(pOut, r1, g1, b1, tableA, low, false, flipped);
    251     decode_subblock(pOut, r2, g2, b2, tableB, low, true, flipped);
    252 }
    253 
    254 typedef struct {
    255     etc1_uint32 high;
    256     etc1_uint32 low;
    257     etc1_uint32 score; // Lower is more accurate
    258 } etc_compressed;
    259 
    260 static
    261 inline void take_best(etc_compressed* a, const etc_compressed* b) {
    262     if (a->score > b->score) {
    263         *a = *b;
    264     }
    265 }
    266 
    267 static
    268 void etc_average_colors_subblock(const etc1_byte* pIn, etc1_uint32 inMask,
    269         etc1_byte* pColors, bool flipped, bool second) {
    270     int r = 0;
    271     int g = 0;
    272     int b = 0;
    273 
    274     if (flipped) {
    275         int by = 0;
    276         if (second) {
    277             by = 2;
    278         }
    279         for (int y = 0; y < 2; y++) {
    280             int yy = by + y;
    281             for (int x = 0; x < 4; x++) {
    282                 int i = x + 4 * yy;
    283                 if (inMask & (1 << i)) {
    284                     const etc1_byte* p = pIn + i * 3;
    285                     r += *(p++);
    286                     g += *(p++);
    287                     b += *(p++);
    288                 }
    289             }
    290         }
    291     } else {
    292         int bx = 0;
    293         if (second) {
    294             bx = 2;
    295         }
    296         for (int y = 0; y < 4; y++) {
    297             for (int x = 0; x < 2; x++) {
    298                 int xx = bx + x;
    299                 int i = xx + 4 * y;
    300                 if (inMask & (1 << i)) {
    301                     const etc1_byte* p = pIn + i * 3;
    302                     r += *(p++);
    303                     g += *(p++);
    304                     b += *(p++);
    305                 }
    306             }
    307         }
    308     }
    309     pColors[0] = (etc1_byte)((r + 4) >> 3);
    310     pColors[1] = (etc1_byte)((g + 4) >> 3);
    311     pColors[2] = (etc1_byte)((b + 4) >> 3);
    312 }
    313 
    314 static
    315 inline int square(int x) {
    316     return x * x;
    317 }
    318 
    319 static etc1_uint32 chooseModifier(const etc1_byte* pBaseColors,
    320         const etc1_byte* pIn, etc1_uint32 *pLow, int bitIndex,
    321         const int* pModifierTable) {
    322     etc1_uint32 bestScore = ~0;
    323     int bestIndex = 0;
    324     int pixelR = pIn[0];
    325     int pixelG = pIn[1];
    326     int pixelB = pIn[2];
    327     int r = pBaseColors[0];
    328     int g = pBaseColors[1];
    329     int b = pBaseColors[2];
    330     for (int i = 0; i < 4; i++) {
    331         int modifier = pModifierTable[i];
    332         int decodedG = clamp(g + modifier);
    333         etc1_uint32 score = (etc1_uint32) (6 * square(decodedG - pixelG));
    334         if (score >= bestScore) {
    335             continue;
    336         }
    337         int decodedR = clamp(r + modifier);
    338         score += (etc1_uint32) (3 * square(decodedR - pixelR));
    339         if (score >= bestScore) {
    340             continue;
    341         }
    342         int decodedB = clamp(b + modifier);
    343         score += (etc1_uint32) square(decodedB - pixelB);
    344         if (score < bestScore) {
    345             bestScore = score;
    346             bestIndex = i;
    347         }
    348     }
    349     etc1_uint32 lowMask = (((bestIndex >> 1) << 16) | (bestIndex & 1))
    350             << bitIndex;
    351     *pLow |= lowMask;
    352     return bestScore;
    353 }
    354 
    355 static
    356 void etc_encode_subblock_helper(const etc1_byte* pIn, etc1_uint32 inMask,
    357         etc_compressed* pCompressed, bool flipped, bool second,
    358         const etc1_byte* pBaseColors, const int* pModifierTable) {
    359     int score = pCompressed->score;
    360     if (flipped) {
    361         int by = 0;
    362         if (second) {
    363             by = 2;
    364         }
    365         for (int y = 0; y < 2; y++) {
    366             int yy = by + y;
    367             for (int x = 0; x < 4; x++) {
    368                 int i = x + 4 * yy;
    369                 if (inMask & (1 << i)) {
    370                     score += chooseModifier(pBaseColors, pIn + i * 3,
    371                             &pCompressed->low, yy + x * 4, pModifierTable);
    372                 }
    373             }
    374         }
    375     } else {
    376         int bx = 0;
    377         if (second) {
    378             bx = 2;
    379         }
    380         for (int y = 0; y < 4; y++) {
    381             for (int x = 0; x < 2; x++) {
    382                 int xx = bx + x;
    383                 int i = xx + 4 * y;
    384                 if (inMask & (1 << i)) {
    385                     score += chooseModifier(pBaseColors, pIn + i * 3,
    386                             &pCompressed->low, y + xx * 4, pModifierTable);
    387                 }
    388             }
    389         }
    390     }
    391     pCompressed->score = score;
    392 }
    393 
    394 static bool inRange4bitSigned(int color) {
    395     return color >= -4 && color <= 3;
    396 }
    397 
    398 static void etc_encodeBaseColors(etc1_byte* pBaseColors,
    399         const etc1_byte* pColors, etc_compressed* pCompressed) {
    400     int r1, g1, b1, r2, g2, b2; // 8 bit base colors for sub-blocks
    401     bool differential;
    402     {
    403         int r51 = convert8To5(pColors[0]);
    404         int g51 = convert8To5(pColors[1]);
    405         int b51 = convert8To5(pColors[2]);
    406         int r52 = convert8To5(pColors[3]);
    407         int g52 = convert8To5(pColors[4]);
    408         int b52 = convert8To5(pColors[5]);
    409 
    410         r1 = convert5To8(r51);
    411         g1 = convert5To8(g51);
    412         b1 = convert5To8(b51);
    413 
    414         int dr = r52 - r51;
    415         int dg = g52 - g51;
    416         int db = b52 - b51;
    417 
    418         differential = inRange4bitSigned(dr) && inRange4bitSigned(dg)
    419                 && inRange4bitSigned(db);
    420         if (differential) {
    421             r2 = convert5To8(r51 + dr);
    422             g2 = convert5To8(g51 + dg);
    423             b2 = convert5To8(b51 + db);
    424             pCompressed->high |= (r51 << 27) | ((7 & dr) << 24) | (g51 << 19)
    425                     | ((7 & dg) << 16) | (b51 << 11) | ((7 & db) << 8) | 2;
    426         }
    427     }
    428 
    429     if (!differential) {
    430         int r41 = convert8To4(pColors[0]);
    431         int g41 = convert8To4(pColors[1]);
    432         int b41 = convert8To4(pColors[2]);
    433         int r42 = convert8To4(pColors[3]);
    434         int g42 = convert8To4(pColors[4]);
    435         int b42 = convert8To4(pColors[5]);
    436         r1 = convert4To8(r41);
    437         g1 = convert4To8(g41);
    438         b1 = convert4To8(b41);
    439         r2 = convert4To8(r42);
    440         g2 = convert4To8(g42);
    441         b2 = convert4To8(b42);
    442         pCompressed->high |= (r41 << 28) | (r42 << 24) | (g41 << 20) | (g42
    443                 << 16) | (b41 << 12) | (b42 << 8);
    444     }
    445     pBaseColors[0] = r1;
    446     pBaseColors[1] = g1;
    447     pBaseColors[2] = b1;
    448     pBaseColors[3] = r2;
    449     pBaseColors[4] = g2;
    450     pBaseColors[5] = b2;
    451 }
    452 
    453 static
    454 void etc_encode_block_helper(const etc1_byte* pIn, etc1_uint32 inMask,
    455         const etc1_byte* pColors, etc_compressed* pCompressed, bool flipped) {
    456     pCompressed->score = ~0;
    457     pCompressed->high = (flipped ? 1 : 0);
    458     pCompressed->low = 0;
    459 
    460     etc1_byte pBaseColors[6];
    461 
    462     etc_encodeBaseColors(pBaseColors, pColors, pCompressed);
    463 
    464     int originalHigh = pCompressed->high;
    465 
    466     const int* pModifierTable = kModifierTable;
    467     for (int i = 0; i < 8; i++, pModifierTable += 4) {
    468         etc_compressed temp;
    469         temp.score = 0;
    470         temp.high = originalHigh | (i << 5);
    471         temp.low = 0;
    472         etc_encode_subblock_helper(pIn, inMask, &temp, flipped, false,
    473                 pBaseColors, pModifierTable);
    474         take_best(pCompressed, &temp);
    475     }
    476     pModifierTable = kModifierTable;
    477     etc_compressed firstHalf = *pCompressed;
    478     for (int i = 0; i < 8; i++, pModifierTable += 4) {
    479         etc_compressed temp;
    480         temp.score = firstHalf.score;
    481         temp.high = firstHalf.high | (i << 2);
    482         temp.low = firstHalf.low;
    483         etc_encode_subblock_helper(pIn, inMask, &temp, flipped, true,
    484                 pBaseColors + 3, pModifierTable);
    485         if (i == 0) {
    486             *pCompressed = temp;
    487         } else {
    488             take_best(pCompressed, &temp);
    489         }
    490     }
    491 }
    492 
    493 static void writeBigEndian(etc1_byte* pOut, etc1_uint32 d) {
    494     pOut[0] = (etc1_byte)(d >> 24);
    495     pOut[1] = (etc1_byte)(d >> 16);
    496     pOut[2] = (etc1_byte)(d >> 8);
    497     pOut[3] = (etc1_byte) d;
    498 }
    499 
    500 // Input is a 4 x 4 square of 3-byte pixels in form R, G, B
    501 // inmask is a 16-bit mask where bit (1 << (x + y * 4)) tells whether the corresponding (x,y)
    502 // pixel is valid or not. Invalid pixel color values are ignored when compressing.
    503 // Output is an ETC1 compressed version of the data.
    504 
    505 static void etc1_encode_block(etc1_byte* pIn, int inMask, etc1_byte* pOut) {
    506     etc1_byte colors[6];
    507     etc1_byte flippedColors[6];
    508     etc_average_colors_subblock(pIn, inMask, colors, false, false);
    509     etc_average_colors_subblock(pIn, inMask, colors + 3, false, true);
    510     etc_average_colors_subblock(pIn, inMask, flippedColors, true, false);
    511     etc_average_colors_subblock(pIn, inMask, flippedColors + 3, true, true);
    512 
    513     etc_compressed a, b;
    514     etc_encode_block_helper(pIn, inMask, colors, &a, false);
    515     etc_encode_block_helper(pIn, inMask, flippedColors, &b, true);
    516     take_best(&a, &b);
    517     writeBigEndian(pOut, a.high);
    518     writeBigEndian(pOut + 4, a.low);
    519 }
    520 
    521 }  // anonymous namespace
    522 
    523 // Return the size of the encoded image data.
    524 
    525 etc1_uint32 etc1_get_encoded_data_size(etc1_uint32 width, etc1_uint32 height) {
    526   return (((width + 3) & ~3) * ((height + 3) & ~3)) >> 1;
    527 }
    528 
    529 // Encode an entire image.
    530 // pIn - pointer to the image data. Formatted such that the Red component of
    531 //       pixel (x,y) is at pIn + pixelSize * x + stride * y + redOffset;
    532 // pOut - pointer to encoded data. Must be large enough to store entire encoded image.
    533 // Returns false if there was an error.
    534 
    535 bool etc1_encode_image(const etc1_byte* pIn, etc1_uint32 width, etc1_uint32 height,
    536          etc1_uint32 pixelSize, etc1_uint32 stride, etc1_byte* pOut, etc1_uint32 outWidth,
    537          etc1_uint32 outHeight) {
    538     if (pixelSize < 2) {
    539           return false;
    540     }
    541     static const unsigned short kYMask[] = { 0x0, 0xf, 0xff, 0xfff, 0xffff };
    542     static const unsigned short kXMask[] = { 0x0, 0x1111, 0x3333, 0x7777,
    543             0xffff };
    544     etc1_byte block[ETC1_DECODED_BLOCK_SIZE];
    545     etc1_byte encoded[ETC1_ENCODED_BLOCK_SIZE];
    546 
    547     etc1_uint32 encodedWidth = (outWidth + 3) & ~3;
    548     etc1_uint32 encodedHeight = (outHeight + 3) & ~3;
    549 
    550     for (etc1_uint32 y = 0; y < encodedHeight; y += 4) {
    551         etc1_uint32 yEnd = outHeight - y;
    552         if (yEnd > 4) {
    553             yEnd = 4;
    554         }
    555         int ymask = kYMask[yEnd];
    556         for (etc1_uint32 x = 0; x < encodedWidth; x += 4) {
    557             etc1_uint32 xEnd = outWidth - x;
    558             if (xEnd > 4) {
    559                 xEnd = 4;
    560             }
    561             const int mask = ymask & kXMask[xEnd];
    562             // Shortcut to only encode blocks which overlap the input image.
    563             // The outside region will be undefined garbage.
    564             if (x < width && y < height) {
    565                 for (etc1_uint32 cy = 0; cy < yEnd; cy++) {
    566                     etc1_byte* q = block + (cy * 4) * 3;
    567                     const etc1_byte* p = pIn + pixelSize * x + stride * (y + cy);
    568                     if (y + cy < height) {
    569                         for (etc1_uint32 cx = 0; cx < xEnd; cx++) {
    570                             if (x + cx < width) {
    571                                 if (pixelSize == 4) {
    572                                     // RGBA_8888: Filter out the input's alpha channel.
    573                                     *q++ = p[0];
    574                                     *q++ = p[1];
    575                                     *q++ = p[2];
    576                                 } else {
    577                                     // RGB_565: Unpack input's 2 bytes to RGB.
    578                                     int pixel = (p[1] << 8) | p[0];
    579                                     *q++ = convert5To8(pixel >> 11);
    580                                     *q++ = convert6To8(pixel >> 5);
    581                                     *q++ = convert5To8(pixel);
    582                                 }
    583                                 p += pixelSize;
    584                             } else {
    585                                 // Out of bounds of the input image but within a
    586                                 // block that must be properly encoded, so pad
    587                                 // the original image with the last pixel.
    588                                 *(q + 0) = *(q - 3);
    589                                 *(q + 1) = *(q - 2);
    590                                 *(q + 2) = *(q - 1);
    591                                 q += 3;
    592                             }
    593                         }
    594                     } else {
    595                       // Out of bounds of the input image but within a
    596                       // block that must be properly encoded, so pad the
    597                       // original image with the last pixel.
    598                       *(q + 0) = *(q - 12);
    599                       *(q + 1) = *(q - 11);
    600                       *(q + 2) = *(q - 10);
    601                       q += 3;
    602                     }
    603                 }
    604                 etc1_encode_block(block, mask, encoded);
    605                 memcpy(pOut, encoded, sizeof(encoded));
    606             } else if (x == width && width > 0 && height > 0) {
    607                 // We need to extend the block right after to the last pixel of
    608                 // the source bitmap for the blending to work nicely.
    609                 for (etc1_uint32 cy = 0; cy < yEnd; cy++) {
    610                     etc1_byte* q = block + (cy * 4) * 3;
    611                     const etc1_byte* p = pIn + pixelSize * (width - 1) +
    612                             stride * std::min(y + cy, height - 1);
    613                     for (etc1_uint32 cx = 0; cx < xEnd; cx++) {
    614                         if (pixelSize == 4) {
    615                             // RGBA_8888: Filter out the input's alpha channel.
    616                             *q++ = p[0];
    617                             *q++ = p[1];
    618                             *q++ = p[2];
    619                         } else {
    620                             // RGB_565: Unpack input's 2 bytes to RGB.
    621                             int pixel = (p[1] << 8) | p[0];
    622                             *q++ = convert5To8(pixel >> 11);
    623                             *q++ = convert6To8(pixel >> 5);
    624                             *q++ = convert5To8(pixel);
    625                         }
    626                     }
    627                 }
    628                 etc1_encode_block(block, mask, encoded);
    629                 memcpy(pOut, encoded, sizeof(encoded));
    630             } else if (y == height && width > 0 && height > 0) {
    631                 // We need to extend the block right after to the last pixel of
    632                 // the source bitmap for the blending to work nicely.
    633                 for (etc1_uint32 cy = 0; cy < yEnd; cy++) {
    634                     etc1_byte* q = block + (cy * 4) * 3;
    635                     for (etc1_uint32 cx = 0; cx < xEnd; cx++) {
    636                         const etc1_byte* p = pIn +
    637                                 pixelSize * std::min(x + cx, width - 1) +
    638                                 stride * (height - 1);
    639                         if (pixelSize == 4) {
    640                             // RGBA_8888: Filter out the input's alpha channel.
    641                             *q++ = p[0];
    642                             *q++ = p[1];
    643                             *q++ = p[2];
    644                         } else {
    645                             // RGB_565: Unpack input's 2 bytes to RGB.
    646                             int pixel = (p[1] << 8) | p[0];
    647                             *q++ = convert5To8(pixel >> 11);
    648                             *q++ = convert6To8(pixel >> 5);
    649                             *q++ = convert5To8(pixel);
    650                         }
    651                     }
    652                 }
    653                 etc1_encode_block(block, mask, encoded);
    654                 memcpy(pOut, encoded, sizeof(encoded));
    655             } else {
    656                 memset(pOut, 0xFF, sizeof(encoded));
    657             }
    658             pOut += sizeof(encoded);
    659         }
    660     }
    661     return true;
    662 }
    663 
    664 // Decode an entire image.
    665 // pIn - pointer to encoded data.
    666 // pOut - pointer to the image data. Will be written such that the Red component of
    667 //       pixel (x,y) is at pIn + pixelSize * x + stride * y + redOffset. Must be
    668 //        large enough to store entire image.
    669 
    670 
    671 bool etc1_decode_image(const etc1_byte* pIn, etc1_byte* pOut,
    672         etc1_uint32 width, etc1_uint32 height,
    673         etc1_uint32 pixelSize, etc1_uint32 stride) {
    674     if (pixelSize < 2 || pixelSize > 4) {
    675         return false;
    676     }
    677     etc1_byte block[ETC1_DECODED_BLOCK_SIZE];
    678 
    679     etc1_uint32 encodedWidth = (width + 3) & ~3;
    680     etc1_uint32 encodedHeight = (height + 3) & ~3;
    681 
    682     for (etc1_uint32 y = 0; y < encodedHeight; y += 4) {
    683         etc1_uint32 yEnd = height - y;
    684         if (yEnd > 4) {
    685             yEnd = 4;
    686         }
    687         for (etc1_uint32 x = 0; x < encodedWidth; x += 4) {
    688             etc1_uint32 xEnd = width - x;
    689             if (xEnd > 4) {
    690                 xEnd = 4;
    691             }
    692             etc1_decode_block(pIn, block);
    693             pIn += ETC1_ENCODED_BLOCK_SIZE;
    694             for (etc1_uint32 cy = 0; cy < yEnd; cy++) {
    695                 const etc1_byte* q = block + (cy * 4) * 3;
    696                 etc1_byte* p = pOut + pixelSize * x + stride * (y + cy);
    697                 if (pixelSize == 3) {
    698                     memcpy(p, q, xEnd * 3);
    699                 } else if (pixelSize == 2) {
    700                     for (etc1_uint32 cx = 0; cx < xEnd; cx++) {
    701                         etc1_byte r = *q++;
    702                         etc1_byte g = *q++;
    703                         etc1_byte b = *q++;
    704                         etc1_uint32 pixel = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
    705                         *p++ = (etc1_byte) pixel;
    706                         *p++ = (etc1_byte) (pixel >> 8);
    707                     }
    708                 } else {
    709                   for (etc1_uint32 cx = 0; cx < xEnd; cx++) {
    710                       etc1_byte r = *q++;
    711                       etc1_byte g = *q++;
    712                       etc1_byte b = *q++;
    713                       *p++ = r;
    714                       *p++ = g;
    715                       *p++ = b;
    716                       *p++ = (etc1_byte) 0xFF;
    717                   }
    718                 }
    719             }
    720         }
    721     }
    722     return true;
    723 }
    724 
    725 static const char kMagic[] = { 'P', 'K', 'M', ' ', '1', '0' };
    726 
    727 static const etc1_uint32 ETC1_PKM_FORMAT_OFFSET = 6;
    728 static const etc1_uint32 ETC1_PKM_ENCODED_WIDTH_OFFSET = 8;
    729 static const etc1_uint32 ETC1_PKM_ENCODED_HEIGHT_OFFSET = 10;
    730 static const etc1_uint32 ETC1_PKM_WIDTH_OFFSET = 12;
    731 static const etc1_uint32 ETC1_PKM_HEIGHT_OFFSET = 14;
    732 
    733 static const etc1_uint32 ETC1_RGB_NO_MIPMAPS = 0;
    734 
    735 static void writeBEUint16(etc1_byte* pOut, etc1_uint32 data) {
    736     pOut[0] = (etc1_byte) (data >> 8);
    737     pOut[1] = (etc1_byte) data;
    738 }
    739 
    740 static etc1_uint32 readBEUint16(const etc1_byte* pIn) {
    741     return (pIn[0] << 8) | pIn[1];
    742 }
    743 
    744 // Format a PKM header
    745 
    746 void etc1_pkm_format_header(etc1_byte* pHeader, etc1_uint32 width, etc1_uint32 height) {
    747     memcpy(pHeader, kMagic, sizeof(kMagic));
    748     etc1_uint32 encodedWidth = (width + 3) & ~3;
    749     etc1_uint32 encodedHeight = (height + 3) & ~3;
    750     writeBEUint16(pHeader + ETC1_PKM_FORMAT_OFFSET, ETC1_RGB_NO_MIPMAPS);
    751     writeBEUint16(pHeader + ETC1_PKM_ENCODED_WIDTH_OFFSET, encodedWidth);
    752     writeBEUint16(pHeader + ETC1_PKM_ENCODED_HEIGHT_OFFSET, encodedHeight);
    753     writeBEUint16(pHeader + ETC1_PKM_WIDTH_OFFSET, width);
    754     writeBEUint16(pHeader + ETC1_PKM_HEIGHT_OFFSET, height);
    755 }
    756 
    757 // Check if a PKM header is correctly formatted.
    758 
    759 bool etc1_pkm_is_valid(const etc1_byte* pHeader) {
    760     if (memcmp(pHeader, kMagic, sizeof(kMagic))) {
    761         return false;
    762     }
    763     etc1_uint32 format = readBEUint16(pHeader + ETC1_PKM_FORMAT_OFFSET);
    764     etc1_uint32 encodedWidth = readBEUint16(pHeader + ETC1_PKM_ENCODED_WIDTH_OFFSET);
    765     etc1_uint32 encodedHeight = readBEUint16(pHeader + ETC1_PKM_ENCODED_HEIGHT_OFFSET);
    766     etc1_uint32 width = readBEUint16(pHeader + ETC1_PKM_WIDTH_OFFSET);
    767     etc1_uint32 height = readBEUint16(pHeader + ETC1_PKM_HEIGHT_OFFSET);
    768     return format == ETC1_RGB_NO_MIPMAPS &&
    769             encodedWidth >= width && encodedWidth - width < 4 &&
    770             encodedHeight >= height && encodedHeight - height < 4;
    771 }
    772 
    773 // Read the image width from a PKM header
    774 
    775 etc1_uint32 etc1_pkm_get_width(const etc1_byte* pHeader) {
    776     return readBEUint16(pHeader + ETC1_PKM_WIDTH_OFFSET);
    777 }
    778 
    779 // Read the image height from a PKM header
    780 
    781 etc1_uint32 etc1_pkm_get_height(const etc1_byte* pHeader){
    782     return readBEUint16(pHeader + ETC1_PKM_HEIGHT_OFFSET);
    783 }
    784