Revert "[4.0] Exposing Exif Image metadata"
[platform/core/uifw/dali-adaptor.git] / platform-abstractions / tizen / image-loaders / loader-ico.cpp
1 /*
2  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /*
18  * Derived from Enlightenment file evas_image_load_ico.c[1]  which is licensed
19  * under the BSD 2-clause license[2] reproduced below.
20  *
21  * [1][http://web.archive.org/web/20141201151111/http://git.enlightenment.org/core/efl.git/tree/src/modules/evas/loaders/ico/evas_image_load_ico.c]
22  * [2][http://web.archive.org/web/20140717012400/https://git.enlightenment.org/core/efl.git/about/]
23  *
24  * Copyright (C) 2002-2012 Carsten Haitzler, Dan Sinclair, Mike Blumenkrantz,
25  * Samsung Electronics and various contributors (see AUTHORS)
26  *
27  * All rights reserved.
28  *
29  * Redistribution and use in source and binary forms, with or without
30  * modification, are permitted provided that the following conditions are met:
31  *
32  *    1. Redistributions of source code must retain the above copyright
33  *       notice, this list of conditions and the following disclaimer.
34  *    2. Redistributions in binary form must reproduce the above copyright
35  *       notice, this list of conditions and the following disclaimer in the
36  *       documentation and/or other materials provided with the distribution.
37  *
38  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
39  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
40  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
41  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
42  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
44  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
45  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
46  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
47  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48  */
49
50 // HEADER
51 #include "loader-ico.h"
52
53 // EXTERNAL INCLUDES
54 #include <cstring>
55 #include <dali/public-api/common/dali-vector.h>
56
57 // INTERNAL INCLUDES
58 #include <dali/integration-api/debug.h>
59 #include <dali/integration-api/bitmap.h>
60
61 namespace Dali
62 {
63 using Integration::Bitmap;
64 using Dali::Integration::PixelBuffer;
65
66 namespace TizenPlatform
67 {
68
69 namespace
70 {
71 // Reserved 2 bytes + type 2 bytes + count 2 bytes + count * 16 bytes
72 const unsigned char ICO_FILE_HEADER = 22;
73 // Info header 40 bytes = size 4 bytes + width 4 bytes + height 4 bytes + planes 2 bytes + bitcount 2 bytes
74 // + compression 4 bytes + imagesize 4 bytes + xpixelsPerM 4 bytes + ypixelsPerM 4 bytes + colorsUsed 4 bytes + colorImportant 4 bytes
75 // besides, there are rgba color data = numberOfColors * 4 bytes
76 const unsigned char ICO_IMAGE_INFO_HEADER = 40;
77
78 typedef unsigned char  DATA8;
79 #define A_VAL(p) (reinterpret_cast< DATA8 * >( p )[3])
80
81 #define RGB_JOIN(r,g,b) \
82                 (((r) << 16) + ((g) << 8) + (b))
83
84 #define ARGB_JOIN(a,r,g,b) \
85                 (((a) << 24) + ((r) << 16) + ((g) << 8) + (b))
86
87 bool read_ushort(unsigned char *map, size_t length, size_t *position, unsigned short *ret)
88 {
89   unsigned char b[2];
90
91   if (*position + 2 > length)
92   {
93     return false;
94   }
95   b[0] = map[(*position)++];
96   b[1] = map[(*position)++];
97   *ret = (b[1] << 8) | b[0];
98   return true;
99 }
100
101 bool read_uint(unsigned char *map, size_t length, size_t *position, unsigned int *ret)
102 {
103   unsigned char b[4];
104   unsigned int i;
105
106   if (*position + 4 > length)
107   {
108     return false;
109   }
110   for (i = 0; i < 4; i++)
111   {
112     b[i] = map[(*position)++];
113   }
114   *ret = ARGB_JOIN(b[3], b[2], b[1], b[0]);
115   return true;
116 }
117
118 bool read_uchar(unsigned char *map, size_t length, size_t *position, unsigned char *ret)
119 {
120   if (*position + 1 > length)
121   {
122     return false;
123   }
124   *ret = map[(*position)++];
125   return true;
126 }
127
128 bool read_mem(unsigned char *map, size_t length, size_t *position, void *buffer, int size)
129 {
130   if (*position + size > length)
131   {
132     return false;
133   }
134   memcpy(buffer, map + *position, size);
135   *position += size;
136   return true;
137 }
138
139 enum
140 {
141   SMALLEST,
142   BIGGEST,
143   SMALLER,
144   BIGGER
145 };
146
147 enum
148 {
149   ICON = 1,
150   CURSOR = 2
151 };
152
153 struct IcoData
154 {
155   int pdelta;
156   int w, h;
157   int cols;
158   int bpp, planes;
159   int hot_x, hot_y;
160   unsigned int bmoffset, bmsize;
161 };
162
163 bool LoadIcoHeaderHelper( FILE* fp,
164                           IcoData& chosen,
165                           Dali::Vector<unsigned char>& map,
166                           unsigned int& fsize )
167 {
168   memset( &chosen, 0, sizeof(chosen) );
169
170   if(fp == NULL)
171   {
172     DALI_LOG_ERROR("Error loading bitmap\n");
173     return false;
174   }
175   size_t position = 0;
176   unsigned short word;
177   unsigned char byte;
178
179   if( fseek(fp,0,SEEK_END) )
180   {
181     DALI_LOG_ERROR("Error seeking ICO data\n");
182     return false;
183   }
184
185   long positionIndicator = ftell(fp);
186   fsize = 0u;
187
188   if( positionIndicator > -1L )
189   {
190     fsize = static_cast<unsigned int>(positionIndicator);
191   }
192
193   if( 0u == fsize )
194   {
195     return false;
196   }
197
198   if( fseek(fp, 0, SEEK_SET) )
199   {
200     DALI_LOG_ERROR("Error seeking ICO data\n");
201     return false;
202   }
203
204   if (fsize < (ICO_FILE_HEADER + ICO_IMAGE_INFO_HEADER)) //6 + 16 + 40
205   {
206     return false;
207   }
208   map.Resize(fsize);
209
210   if(fread(&map[0], 1, fsize, fp) != fsize)
211   {
212     DALI_LOG_WARNING("image file read opeation error!\n");
213     return false;
214   }
215
216   int search = BIGGEST;
217   unsigned short reserved, type, count;
218   if (!read_ushort(&map[0], fsize, &position, &reserved))
219   {
220     return false;
221   }
222   if (!read_ushort(&map[0], fsize, &position, &type))
223   {
224     return false;
225   }
226   if (!read_ushort(&map[0], fsize, &position, &count))
227   {
228     return false;
229   }
230   if (!((reserved == 0) &&
231        ((type == ICON) || (type == CURSOR)) && (count != 0)))
232   {
233     return false;
234   }
235   search = BIGGEST;
236   chosen.pdelta = 0;
237   bool have_choice = false;
238
239   for (unsigned short i = 0; i < count; i++)
240   {
241     unsigned char tw = 0, th = 0, tcols = 0;
242     if (!read_uchar(&map[0], fsize, &position, &tw))
243     {
244       return false;
245     }
246     int w = tw;
247     if (w <= 0)
248     {
249       w = 256;
250     }
251     if (!read_uchar(&map[0], fsize, &position, &th))
252     {
253       return false;
254
255     }
256     int h = th;
257     if (h <= 0)
258     {
259       h = 256;
260     }
261     if (!read_uchar(&map[0], fsize, &position, &tcols))
262     {
263       return false;
264     }
265     int cols = tcols;
266     if (!read_uchar(&map[0], fsize, &position, &byte))
267     {
268       return false;
269     }
270     if (!read_ushort(&map[0], fsize, &position, &word))
271     {
272       return false;
273     }
274     int planes=0;
275     if (type == 1)
276     {
277       planes = word;
278     }
279     //else hot_x = word;
280     if (!read_ushort(&map[0], fsize, &position, &word))
281     {
282       return false;
283     }
284     int bpp=0;
285     if (type == 1)
286     {
287       bpp = word;
288     }
289
290     // 0 colors means 256 for paletized modes.
291     // Note: We must not do this conversion for bpp greater than 8, as there is no palette.
292     if( bpp <= 8 && cols == 0 )
293     {
294       cols = 256;
295     }
296
297     //else hot_y = word;
298     unsigned int bmoffset, bmsize;
299     if (!read_uint(&map[0], fsize, &position, &bmsize))
300     {
301       return false;
302     }
303     if (!read_uint(&map[0], fsize, &position, &bmoffset))
304     {
305       return false;
306     }
307     if ((bmsize <= 0) || (bmoffset <= 0) || (bmoffset >= fsize))
308     {
309       return false;
310     }
311     if (search == BIGGEST)
312     {
313       int pdelta = w * h;
314       if ((!have_choice) ||
315        ((pdelta >= chosen.pdelta) &&
316            (((bpp >= 3) && (bpp >= chosen.bpp)) ||
317                ((bpp < 3) && (cols >= chosen.cols)))))
318       {
319         have_choice = true;
320         chosen.pdelta = pdelta;
321         chosen.w = w;
322         chosen.h = h;
323         chosen.cols = cols;
324         chosen.bpp = bpp;
325         chosen.planes = planes;
326         chosen.bmsize = bmsize;
327         chosen.bmoffset = bmoffset;
328       }
329     }
330   }
331
332   if (chosen.bmoffset == 0)
333   {
334     return false;
335   }
336
337   return true;
338 }
339
340 }//unnamed namespace
341
342 bool LoadIcoHeader( const ImageLoader::Input& input, unsigned int& width, unsigned int& height )
343 {
344   IcoData chosen;
345   Dali::Vector<unsigned char> map;
346   unsigned int fsize;
347   FILE* const fp = input.file;
348
349   if ( false == LoadIcoHeaderHelper(fp, chosen, map, fsize) )
350   {
351     return false;
352   }
353
354   width = chosen.w;
355   height = chosen.h;
356
357   return true;
358 }
359
360 bool LoadBitmapFromIco( const ImageLoader::Input& input, Integration::Bitmap& bitmap )
361 {
362   IcoData chosen;
363   Dali::Vector<unsigned char> map;
364   unsigned int fsize;
365   FILE* const fp = input.file;
366
367   if ( false == LoadIcoHeaderHelper(fp, chosen, map, fsize) )
368   {
369     return false;
370   }
371
372   Dali::Vector<unsigned int> pal;
373   Dali::Vector<unsigned int> surface;
374   Dali::Vector<unsigned char> maskbuf;
375   Dali::Vector<unsigned char> pixbuf;
376   pal.Resize(256 * 4);
377
378   unsigned int dword;
379   unsigned short word;
380
381   int diff_size = 0;
382   unsigned int* pix;
383   PixelBuffer* pixels = NULL;
384
385   size_t position = chosen.bmoffset;//22 == position
386
387   unsigned int w = chosen.w;
388   unsigned int h = chosen.h;
389   unsigned int cols = chosen.cols;
390
391   // read bmp header time... let's do some checking
392   if (!read_uint(&map[0], fsize, &position, &dword))
393   {
394     return false; // headersize - dont care
395   }
396   if (!read_uint(&map[0], fsize, &position, &dword))
397   {
398     return false; // width
399   }
400   if (dword > 0)
401   {
402     if (dword != w)
403     {
404       w = dword;
405       diff_size = 1;
406     }
407   }
408   if (!read_uint(&map[0], fsize, &position, &dword))
409   {
410     return false; // height
411   }
412   if (dword > 0)
413   {
414     if (dword != (h * 2))
415     {
416       h = dword / 2;
417       diff_size = 1;
418     }
419   }
420   if (diff_size)
421   {
422     DALI_LOG_WARNING("Broken ICO file!\n");
423   }
424
425   // Set up the surface as soon as we have the width and height, so we have a black image if there are any further errors.
426   surface.Resize( w * h * 4 );
427   memset( &surface[0], 0, w * h * 4 );
428
429   if (!read_ushort(&map[0], fsize, &position, &word))
430   {
431     return false; // planes
432   }
433   //planes2 = word;
434   if (!read_ushort(&map[0], fsize, &position, &word))
435   {
436     return false; // bitcount
437   }
438   unsigned int bitcount = word;
439   if (!read_uint(&map[0], fsize, &position, &dword))
440   {
441     return false; // compression
442   }
443   //compression = dword;
444   if (!read_uint(&map[0], fsize, &position, &dword))
445   {
446     return false; // imagesize
447   }
448   //imagesize = dword;
449   if (!read_uint(&map[0], fsize, &position, &dword))
450   {
451     return false; // z pixels per m
452   }
453   if (!read_uint(&map[0], fsize, &position, &dword))
454   {
455     return false; // y pizels per m
456   }
457   if (!read_uint(&map[0], fsize, &position, &dword))
458   {
459     return false; // colors used
460   }
461   //colorsused = dword;
462   if (!read_uint(&map[0], fsize, &position, &dword))
463   {
464     return false; // colors important
465   }
466
467   for( unsigned int i = 0; i < cols ; i ++ )
468   {
469     unsigned char a, r, g, b;
470
471     if (!read_uchar(&map[0], fsize, &position, &b))
472     {
473       return false;
474     }
475     if (!read_uchar(&map[0], fsize, &position, &g))
476     {
477       return false;
478     }
479     if (!read_uchar(&map[0], fsize, &position, &r))
480     {
481       return false;
482     }
483     if (!read_uchar(&map[0], fsize, &position, &a))
484     {
485       return false;
486     }
487     pal[i] = ARGB_JOIN( 0xff, b, g, r );
488   }
489
490   // This is the reference way of calculating the total number of bytes necessary to store one row of pixels.
491   unsigned int stride = ( ( ( bitcount * w ) + 31 ) / 32 ) * 4;
492   unsigned int bitStride = ( ( w + 31 ) / 32 ) * 4;
493
494   // Pixbuf only ever contains one scanline worth of data.
495   pixbuf.Resize( stride );
496   maskbuf.Resize( bitStride * h );
497
498   // Handle different bits-per-pixel.
499   // Note: Switch is in order of most common format first.
500   switch( bitcount )
501   {
502     case 32:
503     {
504       unsigned char* p = &map[position];
505       pix = &surface[0] + ( ( h - 1 ) * w );
506
507       for( unsigned int i = 0; i < h; i++ )
508       {
509         for( unsigned int j = 0; j < w; j++ )
510         {
511           *pix++ = ARGB_JOIN( p[3], p[0], p[1], p[2] );
512           p += 4;
513         }
514         // Move the output up 1 line (we subtract 2 lines because we moved forward one line while copying).
515         pix -= ( w * 2 );
516       }
517       break;
518     }
519
520     case 24:
521     {
522       for( unsigned int i = 0; i < h; i++ )
523       {
524         pix = &surface[0] + ( ( h - 1 - i ) * w );
525         if( !read_mem( &map[0], fsize, &position, &pixbuf[0], stride ) )
526         {
527           return false;
528         }
529         unsigned char* p = &pixbuf[0];
530         for( unsigned int j = 0; j < w; j++ )
531         {
532           *pix++ = ARGB_JOIN( 0xff, p[0], p[1], p[2] );
533           p += 3;
534         }
535       }
536       break;
537     }
538
539     case 8:
540     {
541       for( unsigned int i = 0; i < h; i++ )
542       {
543         pix = &surface[0] + ( ( h - 1 - i ) * w );
544         if( !read_mem( &map[0], fsize, &position, &pixbuf[0], stride ) )
545         {
546           return false;
547         }
548         unsigned char* p = &pixbuf[0];
549         for( unsigned int j = 0; j < w; j++ )
550         {
551           *pix++ = pal[*p++];
552         }
553       }
554       break;
555     }
556
557     case 4:
558     {
559       for( unsigned int i = 0; i < h; i++ )
560       {
561         pix = &surface[0] + ( ( h - 1 - i ) * w );
562         if( !read_mem( &map[0], fsize, &position, &pixbuf[0], stride ) )
563         {
564           return false;
565         }
566         unsigned char* p = &pixbuf[0];
567         for( unsigned int j = 0; j < w; j++ )
568         {
569           if( j & 0x1 )
570           {
571             *pix = pal[*p & 0x0f];
572             p++;
573           }
574           else
575           {
576             *pix = pal[*p >> 4];
577           }
578           pix++;
579         }
580       }
581       break;
582     }
583
584     case 1:
585     {
586       for( unsigned int i = 0; i < h; i++ )
587       {
588         pix = &surface[0] + ( ( h - 1 - i ) * w );
589         if( !read_mem( &map[0], fsize, &position, &pixbuf[0], stride ) )
590         {
591           return false;
592         }
593         unsigned char* p = &pixbuf[0];
594
595         for( unsigned int j = 0; j < w; j += 8 )
596         {
597           *pix++ = pal[ *p >> 7 ];
598           *pix++ = pal[ *p >> 6 & 0x01 ];
599           *pix++ = pal[ *p >> 5 & 0x01 ];
600           *pix++ = pal[ *p >> 4 & 0x01 ];
601           *pix++ = pal[ *p >> 3 & 0x01 ];
602           *pix++ = pal[ *p >> 2 & 0x01 ];
603           *pix++ = pal[ *p >> 1 & 0x01 ];
604           *pix++ = pal[ *p >> 0 & 0x01 ];
605
606           p++;
607         }
608       }
609       break;
610     }
611
612     default:
613     {
614       DALI_LOG_WARNING( "Image file contains unsupported bits-per-pixel %d\n", bitcount );
615       return false;
616     }
617   }
618
619   // From the spec: If bpp is less than 32, there will be a 1bpp mask bitmap also.
620   if( bitcount < 32 )
621   {
622     if( !read_mem( &map[0], fsize, &position, &maskbuf[0], bitStride * h ) )
623     {
624       return false;
625     }
626
627     // Apply mask.
628     // Precalc to save time in the loops.
629     unsigned int bytesPerWidth = w / 8;
630     unsigned int bytesRemainingPerWidth = w - ( bytesPerWidth << 3 );
631
632     // Loop for each line of the image.
633     for( unsigned int i = 0; i < h; ++i )
634     {
635       unsigned char *m = &maskbuf[0] + ( bitStride * i );
636       pix = &surface[0] + ( ( h - 1 - i ) * w );
637
638       // Do chunks of 8 pixels first so mask operations can be unrolled.
639       for( unsigned int j = 0; j < bytesPerWidth; ++j )
640       {
641         // Unrolled 8 bits of the mask to avoid many conditions and branches.
642         A_VAL( pix++ ) = ( *m & ( 1 << 7 ) ) ? 0x00 : 0xff;
643         A_VAL( pix++ ) = ( *m & ( 1 << 6 ) ) ? 0x00 : 0xff;
644         A_VAL( pix++ ) = ( *m & ( 1 << 5 ) ) ? 0x00 : 0xff;
645         A_VAL( pix++ ) = ( *m & ( 1 << 4 ) ) ? 0x00 : 0xff;
646         A_VAL( pix++ ) = ( *m & ( 1 << 3 ) ) ? 0x00 : 0xff;
647         A_VAL( pix++ ) = ( *m & ( 1 << 2 ) ) ? 0x00 : 0xff;
648         A_VAL( pix++ ) = ( *m & ( 1 << 1 ) ) ? 0x00 : 0xff;
649         A_VAL( pix++ ) = ( *m & ( 1 << 0 ) ) ? 0x00 : 0xff;
650         m++;
651       }
652
653       // Handle any remaining width ( < 8 ) or images that are < 8 wide.
654       if( bytesRemainingPerWidth > 0 )
655       {
656         for( unsigned int j = 0; j < bytesRemainingPerWidth; ++j )
657         {
658           // Note: Although we are doing less that a bytes worth of mask, we still always start on the first bit.
659           // If the image is smaller than 8 pixels wide, each mask will still start on a new byte.
660           A_VAL( pix++ ) = ( *m & ( 1 << ( 7 - j ) ) ) ? 0x00 : 0xff;
661         }
662         m++;
663       }
664     }
665   }
666
667   pixels = bitmap.GetPackedPixelsProfile()->ReserveBuffer( Pixel::RGBA8888, w, h );
668   memcpy( pixels, &surface[0], w * h * 4 );
669
670   return true;
671 }
672
673 }
674
675 }